Merge "Adds tests for PreferenceDataStore funcionality."
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 6d3693f..97344e2 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -92,6 +92,7 @@
 
 notification-bot := $(call intermediates-dir-for,APPS,NotificationBot)/package.apk
 permission-app := $(call intermediates-dir-for,APPS,CtsPermissionApp)/package.apk
+usb-companion := $(call intermediates-dir-for,APPS,CtsVerifierUSBCompanion)/package.apk
 
 # Builds and launches CTS Verifier on a device.
 .PHONY: cts-verifier
@@ -130,20 +131,15 @@
 #	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py $@
 
 cts : $(verifier-zip)
-ifeq ($(HOST_OS),linux)
-$(verifier-zip) : $(HOST_OUT)/bin/cts-usb-accessory
-endif
 $(verifier-zip) : $(HOST_OUT)/CameraITS
 $(verifier-zip) : $(notification-bot)
 $(verifier-zip) : $(permission-app)
+$(verifier-zip) : $(usb-companion)
 $(verifier-zip) : $(call intermediates-dir-for,APPS,CtsVerifier)/package.apk | $(ACP)
 		$(hide) mkdir -p $(verifier-dir)
 		$(hide) $(ACP) -fp $< $(verifier-dir)/CtsVerifier.apk
 		$(ACP) -fp $(notification-bot) $(verifier-dir)/NotificationBot.apk
 		$(ACP) -fp $(permission-app) $(verifier-dir)/CtsPermissionApp.apk
-ifeq ($(HOST_OS),linux)
-		$(hide) $(ACP) -fp $(HOST_OUT)/bin/cts-usb-accessory $(verifier-dir)/cts-usb-accessory
-endif
 		$(hide) $(ACP) -fpr $(HOST_OUT)/CameraITS $(verifier-dir)
 		$(hide) cd $(cts-dir) && zip -rq $(verifier-dir-name) $(verifier-dir-name)
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index f3a37cf..15ce007 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1694,23 +1694,26 @@
 
         <activity android:name=".usb.accessory.UsbAccessoryTestActivity"
                 android:label="@string/usb_accessory_test"
-                android:configChanges="keyboardHidden|orientation|screenSize"
-                android:launchMode="singleTop">
+                android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
-            <intent-filter>
-                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
-            </intent-filter>
-            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
-                    android:resource="@xml/accessory_filter" />
             <meta-data android:name="test_category" android:value="@string/test_category_hardware" />
             <meta-data android:name="test_required_features" android:value="android.hardware.usb.accessory" />
             <meta-data android:name="test_excluded_features"
                     android:value="android.hardware.type.watch" />
         </activity>
 
+        <activity android:name=".usb.accessory.AccessoryAttachmentHandler">
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+            </intent-filter>
+
+            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                android:resource="@xml/accessory_filter" />
+        </activity>
+
         <activity android:name=".usb.device.UsbDeviceTestActivity"
                 android:label="@string/usb_device_test"
                 android:configChanges="keyboardHidden|orientation|screenSize">
@@ -2580,7 +2583,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
         </activity>
 
         <activity android:name=".tv.MockTvInputSetupActivity">
@@ -2787,6 +2790,28 @@
                 android:name="com.android.cts.verifier.sensors.sixdof.Activities.TestActivity"
                 android:label="@string/title_activity_cts">
         </activity>
+
+        <activity android:name=".voicemail.VoicemailBroadcastActivity"
+          android:label="@string/voicemail_broadcast_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <data android:scheme="tel" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_telephony"/>
+        </activity>
+
+        <receiver android:name=".voicemail.VoicemailBroadcastReceiver">
+            <intent-filter>
+                <action android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
+            </intent-filter>
+        </receiver>
     </application>
 
 </manifest>
diff --git a/apps/CtsVerifier/res/drawable/ic_usb_48.xml b/apps/CtsVerifier/res/drawable/ic_usb_48.xml
new file mode 100644
index 0000000..eebb4fb
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/ic_usb_48.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2016 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48.0"
+    android:viewportHeight="48.0">
+    <path
+        android:pathData="M30,14v8h2v4h-6V10h4l-6,-8 -6,8h4v16h-6v-4.14c1.41,-0.73 2.4,-2.16 2.4,-3.86 0,-2.43 -1.97,-4.4 -4.4,-4.4 -2.43,0 -4.4,1.97 -4.4,4.4 0,1.7 0.99,3.13 2.4,3.86V26c0,2.21 1.79,4 4,4h6v6.1c-1.42,0.73 -2.4,2.19 -2.4,3.9 0,2.43 1.97,4.4 4.4,4.4 2.43,0 4.4,-1.97 4.4,-4.4 0,-1.71 -0.98,-3.17 -2.4,-3.9V30h6c2.21,0 4,-1.79 4,-4v-4h2v-8h-8z"
+        android:fillColor="#757575"/>
+</vector>
diff --git a/apps/CtsVerifier/res/layout-land/usb_main.xml b/apps/CtsVerifier/res/layout-land/usb_main.xml
deleted file mode 100644
index 139b54b..0000000
--- a/apps/CtsVerifier/res/layout-land/usb_main.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        >
-    <LinearLayout android:orientation="horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            >
-        <LinearLayout android:orientation="vertical"
-                android:layout_width="1px"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                >
-            <TextView android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/usb_sent_messages"
-                    style="?android:attr/listSeparatorTextViewStyle"
-                    />
-            <FrameLayout android:orientation="vertical"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    >
-                <ListView android:id="@+id/usb_sent_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        />
-                <TextView android:id="@+id/usb_empty_sent_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:gravity="center"
-                        android:text="@string/usb_no_messages"
-                        android:visibility="gone"
-                        />
-            </FrameLayout>
-        </LinearLayout>
-        <include layout="@layout/vertical_divider" />
-        <LinearLayout android:orientation="vertical"
-                android:layout_width="1px"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                >
-            <TextView android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:text="@string/usb_received_messages"
-                    style="?android:attr/listSeparatorTextViewStyle"
-                    />
-            <FrameLayout android:orientation="vertical"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    >
-                <ListView android:id="@+id/usb_received_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        />
-                <TextView android:id="@+id/usb_empty_received_messages"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:gravity="center"
-                        android:text="@string/usb_no_messages"
-                        android:visibility="gone"
-                        />
-            </FrameLayout>
-        </LinearLayout>
-    </LinearLayout>
-
-    <include layout="@layout/pass_fail_buttons" />
-
-</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
index 2e43b5f..d02ef0b 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
@@ -1,18 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
+<!-- Copyright (C) 2015 The Android Open Source Project Licensed under the
+    Apache License, Version 2.0 (the "License"); you may not use this file except
+    in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+    Unless required by applicable law or agreed to in writing, software distributed
+    under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+    OR CONDITIONS OF ANY KIND, either express or implied. See the License for
+    the specific language governing permissions and limitations under the License. -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
@@ -23,54 +16,285 @@
     <ScrollView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:id="@+id/scrollView"
-    >
+        android:id="@+id/scrollView">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="vertical"
-        >
+            android:orientation="vertical">
 
-        <TextView
+            <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:scrollbars="vertical"
                 android:gravity="bottom"
-                android:id="@+id/audio_frequency_unprocessed_defined"/>
-
-                <ProgressBar
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    android:id="@+id/audio_frequency_unprocessed_progress_bar" />
+                android:id="@+id/audio_frequency_unprocessed_defined" />
 
             <LinearLayout
-                android:layout_width="wrap_content"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
-                android:id="@+id/audio_frequency_unprocessed_layout_test1"
+                android:id="@+id/unprocessed_layout_test_tone"
             >
 
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/audio_frequency_unprocessed_instructions2"
-                    android:id="@+id/audio_frequency_unprocessed_instructions2" />
-
-                <Button
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/audio_frequency_unprocessed_test1_btn"
-                    android:id="@+id/audio_frequency_unprocessed_test1_btn" />
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
 
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/audio_frequency_unprocessed_results_text"
-                    android:id="@+id/audio_frequency_unprocessed_results1_text" />
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_tone_instructions"
+                    android:id="@+id/unprocessed_test_tone_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_tone_btn"
+                            android:id="@+id/unprocessed_test_tone_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_tone_progress_bar" />
+
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_play"
+                            android:id="@+id/unprocessed_play_tone_btn" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_tone_result"
+                    android:id="@+id/unprocessed_test_tone_result" />
             </LinearLayout>
 
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/unprocessed_layout_test_noise">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_noise_instructions"
+                    android:id="@+id/unprocessed_test_noise_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_noise_btn"
+                            android:id="@+id/unprocessed_test_noise_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_noise_progress_bar" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_play"
+                            android:id="@+id/unprocessed_play_noise_btn" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_noise_result"
+                    android:id="@+id/unprocessed_test_noise_result" />
+            </LinearLayout>
+
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/unprocessed_layout_test_usb_background">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_usb_background_instructions"
+                    android:id="@+id/unprocessed_test_usb_background_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_usb_background_btn"
+                            android:id="@+id/unprocessed_test_usb_background_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_usb_background_progress_bar" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_usb_background_result"
+                    android:id="@+id/unprocessed_test_usb_background_result" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/unprocessed_layout_test_usb_noise">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_usb_noise_instructions"
+                    android:id="@+id/unprocessed_test_usb_noise_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_usb_noise_btn"
+                            android:id="@+id/unprocessed_test_usb_noise_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_usb_noise_progress_bar" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_play"
+                            android:id="@+id/unprocessed_play_usb_noise_btn" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_usb_noise_result"
+                    android:id="@+id/unprocessed_test_usb_noise_result" />
+            </LinearLayout>
+             <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="?android:colorAccent" />
+
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_global_result"
+                    android:id="@+id/unprocessed_test_global_result" />
 
             <include layout="@layout/pass_fail_buttons" />
         </LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/pwa_widgets.xml b/apps/CtsVerifier/res/layout/pwa_widgets.xml
index e5ebddb..cb611b9 100644
--- a/apps/CtsVerifier/res/layout/pwa_widgets.xml
+++ b/apps/CtsVerifier/res/layout/pwa_widgets.xml
@@ -12,19 +12,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <TextureView
-        android:id="@+id/texture_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
     <LinearLayout
+        android:id="@+id/test_controls"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:layout_gravity="top">
 
         <LinearLayout
             android:layout_width="match_parent"
@@ -55,4 +52,10 @@
         </LinearLayout>
     </LinearLayout>
 
-</LinearLayout>
+    <TextureView
+        android:id="@+id/texture_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@id/test_controls" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/usb_main.xml b/apps/CtsVerifier/res/layout/usb_main.xml
index 5c16612..d693ae5 100644
--- a/apps/CtsVerifier/res/layout/usb_main.xml
+++ b/apps/CtsVerifier/res/layout/usb_main.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,55 +14,40 @@
      limitations under the License.
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        >
-    <TextView android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/usb_sent_messages"
-            style="?android:attr/listSeparatorTextViewStyle"
-            />
-    <FrameLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            >
-        <ListView android:id="@+id/usb_sent_messages"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                />
-        <TextView android:id="@+id/usb_empty_sent_messages"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                android:text="@string/usb_no_messages"
-                android:visibility="gone"
-                />
-    </FrameLayout>
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
-    <TextView android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/usb_received_messages"
-            style="?android:attr/listSeparatorTextViewStyle"
-            />
-    <FrameLayout android:orientation="vertical"
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:padding="16dp">
+
+        <ImageView android:layout_width="32dp"
+            android:layout_height="32dp"
+            android:src="@drawable/ic_usb_48"
+            android:tint="@color/primary"
+            android:scaleType="fitCenter"
+            android:layout_marginBottom="16dp" />
+
+        <ProgressBar android:id="@+id/progress_bar"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            >
-        <ListView android:id="@+id/usb_received_messages"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            android:visibility="gone" />
+
+        <ScrollView android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1">
+
+            <TextView android:id="@+id/status"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                />
-        <TextView android:id="@+id/usb_empty_received_messages"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:gravity="center"
-                android:text="@string/usb_no_messages"
-                android:visibility="gone"
-                />
-    </FrameLayout>
+                android:layout_height="wrap_content" />
+
+        </ScrollView>
+
+    </LinearLayout>
 
     <include layout="@layout/pass_fail_buttons" />
 
diff --git a/apps/CtsVerifier/res/layout/usb_message_row.xml b/apps/CtsVerifier/res/layout/usb_message_row.xml
deleted file mode 100644
index 3bb228a..0000000
--- a/apps/CtsVerifier/res/layout/usb_message_row.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="@style/MessageRow"
-        />
diff --git a/apps/CtsVerifier/res/layout/voicemail_broadcast.xml b/apps/CtsVerifier/res/layout/voicemail_broadcast.xml
new file mode 100644
index 0000000..5ce102a
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/voicemail_broadcast.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:orientation="vertical"
+  android:layout_width="match_parent"
+  android:layout_height="match_parent">
+  <TextView
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:text="@string/voicemail_broadcast_instructions"/>
+  <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/set_default_dialer_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/voicemail_set_default_dialer_description"
+      android:textSize="16dp"/>
+  </LinearLayout>
+
+  <Button
+    android:id="@+id/set_default_dialer"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/voicemail_set_default_dialer_button"/>
+
+  <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/leave_voicemail_image"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:src="@drawable/fs_indeterminate"
+      android:layout_marginRight="@dimen/js_padding"/>
+    <TextView
+      android:id="@+id/leave_voicemail_text"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/voicemail_leave_voicemail"
+      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/restore_default_dialer_image"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:src="@drawable/fs_indeterminate"
+      android:layout_marginRight="@dimen/js_padding"/>
+    <TextView
+      android:id="@+id/restore_default_dialer_text"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:text="@string/voicemail_restore_default_dialer_description"
+      android:textSize="16dp"/>
+  </LinearLayout>
+
+  <Button
+    android:id="@+id/restore_default_dialer"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/voicemail_restore_default_dialer_button"/>
+
+  <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/raw/onekhztone.mp3 b/apps/CtsVerifier/res/raw/onekhztone.mp3
new file mode 100644
index 0000000..c0e6660
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/onekhztone.mp3
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index f51da52..54f6558 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -38,6 +38,7 @@
     <string name="test_category_features">Features</string>
     <string name="test_category_deskclock">Clock</string>
     <string name="test_category_jobscheduler">Job Scheduler</string>
+    <string name="test_category_telephony">Telephony</string>
     <string name="test_category_tv">TV</string>
     <string name="test_category_other">Other</string>
     <string name="clear">Clear</string>
@@ -1069,35 +1070,29 @@
 
     <!-- Strings for USB accessory test activity -->
     <string name="usb_accessory_test">USB Accessory Test</string>
-    <string name="sensor_power_test">Sensor Power Test</string>
     <string name="usb_accessory_test_info">
-        1. Connect your Android device to a computer and ensure that the connection is set
-        to charging only from the Android device.
-        \n\n2.Run the \'cts-usb-accessory\' program included with the CTS Verifier bundle.
-        \n\n3. If you have not started the CTS Verifier, press \'OK\' when asked to open the CTS
-        Verifier when the accessory is connected. \n\nIf you are already in this test,
-        then you can press \'Cancel\' but press \'OK\' in the next dialog asking whether to allow
-        CTS Verifier to access the accessory.
-        \n\n4. You should see the accessory and the CTS Verifier display a series of messages
-        which indicates that the accessory support is working properly, and then you will
-        be presented with more instructions.
+        1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n\n2. Start the accessory test companion in the Cts Verifier USB Companion.
+        \n\n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to the helper device. If using an Type-C cable make sure that the helper device is set as "supply power to the attached device".
+        \n\n4. Confirm access to the USB device on the helper device.
+        \n\n5. Confirm access to the USB accessory on this device
+        \n\n6. Confirm access to the USB device on the helper again.
+        \n\n7. Test will run and complete automatically in a less than 30 seconds.
+        \n\n8. Cancel all further dialogs on this device
     </string>
-    <string name="usb_not_available_title">USB accessory feature is not available?</string>
-    <string name="usb_not_available_message">If your device is supposed to support USB accessories, your API implementation is not behaving correctly!</string>
-    <string name="usb_received_messages">Received Messages</string>
-    <string name="usb_reconnect_title">Disconnect and Reconnect</string>
-    <string name="usb_disconnect_message">Please disconnect the Android device and the computer.</string>
-    <string name="usb_connect_message">Please connect the Android device and the computer. Do not interact with the device until prompted.</string>
-    <string name="usb_reconnect_timeout">Test failed because reconnect timed out. You can interact with the device again.</string>
-    <string name="usb_reconnect_abort">Abort Test</string>
-    <string name="usb_wait_for_done">Could not find USB accessory. Try waiting longer.</string>
-    <string name="usb_sent_messages">Sent Messages</string>
-    <string name="usb_no_messages">No messages</string>
-    <string name="usb_message_thread_started">Starting message processing...</string>
-    <string name="usb_message_thread_exception">Exception occurred while processing a message...</string>
-    <string name="usb_message_thread_ended">Stopping message processing...</string>
-    <string name="usb_test_passed">Test passed, pass button enabled! You can interact with the device again.</string>
-    <string name="usb_file_descriptor_error">Could not open file descriptor for USB accessory... try reconnecting and restarting the accessory?</string>
+    <string name="usb_accessory_test_step1">
+        In this specific order:
+        \n1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n2. Start the accessory test companion in the Cts Verifier USB Companion.
+        \n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to the helper device. If using an Type-C cable make sure that the helper device is set as "supply power to the attached device".
+        \n4. Confirm access to the USB device on the helper device. Only confirm once.
+        \n5. Confirm access to the USB accessory on this device.
+        \n6. Confirm access to the USB device on the helper device again.
+        \n\nResult: A progress indicator should appear or test will finish.
+    </string>
+    <string name="usb_accessory_test_step2">
+        Test is running and will complete automatically in less than 30 seconds.
+    </string>
 
     <!-- String for the USB device test activity -->
     <string name="usb_device_test">USB Device Test</string>
@@ -1106,10 +1101,29 @@
         \n\n2. Start the device test companion in the Cts Verifier USB Companion.
         \n\n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to this device. If using an Type-C cable make sure that this device is set as "supply power to the attached device".
         \n\n4. Confirm access to the USB device on this device.
-        \n\n5. Confirm access to the USB accessory on the helper device
+        \n\n5. Confirm access to the USB accessory on the helper device.
         \n\n6. Confirm access to the USB device on this device again.
-        \n\n7. Test will run and complete automatically in a few seconds
-        \n\n8. Cancel all further dialogs on the helper device
+        \n\n7. Test will run and complete automatically in a less than 30 seconds.
+        \n\n8. Cancel all further dialogs on the helper device.
+    </string>
+    <string name="usb_device_test_step1">
+        In this specific order:
+        \n1. Install the Cts Verifier USB Companion app on a separate helper device.
+        \n2. Start the device test companion in the Cts Verifier USB Companion.
+        \n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to this device. If using an Type-C cable make sure that this device is set as "supply power to the attached device".
+        \n\nResult: A dialog should show up on this device asking for access to a USB device.
+    </string>
+    <string name="usb_device_test_step2">
+        Confirm access to the USB device on this device.
+        \n\nResult: Dialogs should show up on this device and on the helper device asking for access to a USB device/accessory.
+    </string>
+    <string name="usb_device_test_step3">
+        1. Confirm access to the USB accessory on the helper device.
+        \n2. Confirm access to the USB device on this device again.
+        \n\nResult: A progress indicator should appear or test will finish.
+    </string>
+    <string name="usb_device_test_step4">
+        Test is running and will complete automatically in a less than 30 seconds.
     </string>
     <string name="usb_device_unexpected">Usb companion device is not as expected %1$s. Please retry test.</string>
 
@@ -1439,6 +1453,12 @@
     <string name="nls_clear_all">Check that service can clear all notifications.</string>
     <string name="nls_service_stopped">Service should stop once disabled.</string>
     <string name="nls_note_missed">Check that notification was not received.</string>
+    <string name="nls_snooze">Check the service can be snoozed.</string>
+    <string name="nls_unsnooze">Check the service can be unsnoozed.</string>
+    <string name="nls_hints">Check that the listener can set hints.</string>
+    <string name="nls_snooze_one">Check that service can snooze a notification.</string>
+    <string name="nls_snooze_one_time">Check that service can snooze a notification for a given time.</string>
+    <string name="nls_unsnooze_one">Check that service can unsnooze a notification.</string>
     <string name="nas_note_missed_enqueued">Check that notification was not enqueued.</string>
     <string name="cp_test">Condition Provider test</string>
     <string name="cp_service_name">Condition Provider for CTS Verifier</string>
@@ -2449,10 +2469,6 @@
         This was expected.\n
         Mark this test as passed.\n
     </string>
-    <string name="device_owner_vpn_connection_canceled">
-        Cannot establish a VPN connection.\n
-        Connection canceled by user.\n
-    </string>
     <string name="device_owner_vpn_test">Check VPN</string>
     <string name="device_owner_vpn_info_default">Vpn test message</string>
 
@@ -2466,7 +2482,8 @@
         - You cannot edit, add or remove any existing VPNs.\n
         - Trying to perform any of the above actions will trigger a support message.\n\n
         2. Press Check VPN to check programmatic Vpn test.\n
-        - Check Vpn setup\n\n
+        - Check Vpn setup is not allowed\n
+        - If prompted to allow a VPN connection, press OK.\n\n
         Use the Back button to return to this page.
     </string>
     <string name="device_owner_user_vpn_restriction_set">Set VPN restriction</string>
@@ -2666,7 +2683,7 @@
     <string name="password_quality_complex">Complex</string>
     <string name="set_permitted_accessibility_services">Set permitted accessibility services</string>
     <string name="permitted_accessibility_services_set_step">
-        Disallow \'Dummy Accessibility service\' from permitted accessibility services by turning on
+        Check that \'Dummy Accessibility service\' is not enabled in Settings and disallow \'Dummy Accessibility service\' from permitted accessibility services by turning on
         the switch below.
     </string>
     <string name="set_permitted_accessibility_services_action">
@@ -2677,7 +2694,7 @@
     </string>
     <string name="set_permitted_input_methods">Set permitted input methods</string>
     <string name="permitted_input_methods_set_step">
-        Disallow \'Dummy Input method\' from permitted input methods by turning on the switch below.
+        Check that \'Dummy Input method\' is not enabled in Settings and disallow \'Dummy Input method\' from permitted input methods by turning on the switch below.
     </string>
     <string name="set_permitted_input_methods_action">
         Enabling \'Dummy Input Method\' in the list of accessibility services
@@ -2938,7 +2955,7 @@
     <string name="audio_general_headset_yes">Yes</string>
     <string name="audio_general_deficiency_found">WARNING: Some results show potential deficiencies on the system.
     Please consider addressing them for a future release.</string>
-    <string name="audio_general_test_passed">Test Successful</string>
+    <string name="audio_general_test_passed">Test Result: Successful</string>
     <string name="audio_general_test_failed">Test Result: Not Optimal</string>
     <string name="audio_general_default_false_string">false</string>
     <string name="audio_general_default_true_string">true</string>
@@ -3032,18 +3049,40 @@
      <!-- Audio Frequency Unprocessed Test -->
     <string name="audio_frequency_unprocessed_test">Audio Frequency Unprocessed Test</string>
     <string name="audio_frequency_unprocessed_info">
-   This test requires an external broadband noise source (or click/impulse).
-   Please be prepared to activate the noise source when asked to.
-   The system will measure frequency response of the built in microphone using the UNPROCESSED
-   audio source.
+    This test requires an external USB reference microphone, external speakers and a Sound Pressure Level meter.
+    You can play the test signals from the device under test or from a secondary device.
+    Follow the instructions on the screen to measure the frequency response for the built in microphone
+    using UNPROCESSED audio source.
+    If the Audio Frequency Unprocessed feature is defined in this system, success in all tests is mandatory to pass.
+    If the feature is not defined, measurements are still needed, but success in all of them is not mandatory to pass.
        </string>
-    <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Test is mandatory</string>
-    <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Test is optional</string>
-     <string name="audio_frequency_unprocessed_instructions2">
-          Once you press the [TEST] button, you have 5 seconds to play a broadband sound (click or white noise).
-    </string>
-    <string name="audio_frequency_unprocessed_test1_btn">Test 1</string>
-    <string name="audio_frequency_unprocessed_results_text">Results...</string>
+    <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Success in all tests is mandatory to pass</string>
+    <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Success in all test is NOT mandatory to pass</string>
+
+    <string name="unprocessed_play">Play</string>
+    <string name="unprocessed_stop">Stop</string>
+
+    <string name="unprocessed_test_tone_instructions">TEST TONE: Press [PLAY] to play tone at 1 Khz. Measure sound SPL to be 94 dB
+    right next to microphone under test. Press [TEST]</string>
+    <string name="unprocessed_test_tone_btn">Test</string>
+    <string name="unprocessed_test_tone_result">Results...</string>
+
+    <string name="unprocessed_test_noise_instructions">TEST NOISE: Position speakers 40 cms from device under test.
+    Press [PLAY] to play broadband white noise. Press [TEST]</string>
+    <string name="unprocessed_test_noise_btn">Test</string>
+    <string name="unprocessed_test_noise_result">Results...</string>
+
+    <string name="unprocessed_test_usb_background_instructions">TEST USB BACKGROUND: Connect USB microphone and position it right next to microphone under test.
+    No source of noise should be active during this test. Press [TEST]</string>
+    <string name="unprocessed_test_usb_background_btn">Test</string>
+    <string name="unprocessed_test_usb_background_result">Results...</string>
+
+    <string name="unprocessed_test_usb_noise_instructions">TEST USB NOISE: Connect USB microphone and position it right next to microphone under test. 
+    Position speakers 40 cms from device under test. Press [PLAY] to play broadband white noise. Press [TEST]</string>
+    <string name="unprocessed_test_usb_noise_btn">Test</string>
+    <string name="unprocessed_test_usb_noise_result">Results...</string>
+
+    <string name="unprocessed_test_global_result">Global Results...</string>
 
     <!-- Strings for 6DoF test -->
     <string name="six_dof_test">6DoF Test</string>
@@ -3179,4 +3218,17 @@
         <item>@string/phase3_description</item>
     </string-array>
 
+    <!-- Strings for voicemail broadcast test -->
+    <string name="voicemail_broadcast_test">Voicemail Broadcast Test</string>
+    <string name="voicemail_broadcast_instructions">This test verifies that the default dialer can intercept the voicemail notification. The test must be conducted on a SIM with visual voicemail disabled</string>
+    <string name="voicemail_set_default_dialer_description">Before the test, the CTS verifier should be set to the default dialer</string>
+    <string name="voicemail_set_default_dialer_button">Set CTS verifier as default dialer"</string>
+    <string name="voicemail_leave_voicemail">Send a voicemail to the device, CTS verifier should receive a voicemail notification broadcast</string>
+    <string name="voicemail_broadcast_received">Voicemail broadcast Received</string>
+    <string name="voicemail_restore_default_dialer_description">(Optional) restore the default dialer setting</string>
+    <string name="voicemail_restore_default_dialer_no_default_description">(Optional) restore the default dialer by going to settings-> apps -> cogwheel -> Phone app</string>
+    <string name="voicemail_restore_default_dialer_button">Restore the default dialer"</string>
+    <string name="voicemail_default_dialer_already_set">Default dialer already set</string>
+    <string name="voicemail_default_dialer_already_restored">Default dialer already restored</string>
+
 </resources>
diff --git a/apps/CtsVerifier/res/xml/accessory_filter.xml b/apps/CtsVerifier/res/xml/accessory_filter.xml
index 21caaa4..4a1d779 100644
--- a/apps/CtsVerifier/res/xml/accessory_filter.xml
+++ b/apps/CtsVerifier/res/xml/accessory_filter.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <resources>
-    <usb-accessory manufacturer="Android CTS" model="CTS USB Accessory" version="1.0" />
+    <usb-accessory />
 </resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
index 56275c5..009dd58 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
@@ -22,11 +22,11 @@
 import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+
 import android.content.Context;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
-
 import android.media.AudioDeviceCallback;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
@@ -34,17 +34,13 @@
 import android.media.AudioTrack;
 import android.media.AudioRecord;
 import android.media.MediaRecorder;
-
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
-
 import android.util.Log;
-
 import android.view.View;
 import android.view.View.OnClickListener;
-
 import android.widget.Button;
 import android.widget.TextView;
 import android.widget.SeekBar;
@@ -59,25 +55,63 @@
     private static final String TAG = "AudioFrequencyUnprocessedActivity";
 
     private static final int TEST_STARTED = 900;
-    private static final int TEST_ENDED = 901;
-    private static final int TEST_MESSAGE = 902;
-    private static final int TEST1_MESSAGE = 903;
-    private static final int TEST1_ENDED = 904;
-    private static final double MIN_ENERGY_BAND_1 = -50.0;          //dB Full Scale
-    private static final double MAX_ENERGY_BAND_1_BASE = -60.0;     //dB Full Scale
-    private static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+    private static final int TEST_MESSAGE = 903;
+    private static final int TEST_ENDED = 904;
+    private static final int TEST_ENDED_ERROR = 905;
+    private static final double MIN_FRACTION_POINTS_IN_BAND = 0.5;
+
+    private static final double TONE_RMS_EXPECTED = -36.0;
+    private static final double TONE_RMS_MAX_ERROR = 3.0;
+
     private static final double MAX_VAL = Math.pow(2, 15);
     private static final double CLIP_LEVEL = (MAX_VAL-10) / MAX_VAL;
 
+    private static final int SOURCE_TONE = 0;
+    private static final int SOURCE_NOISE = 1;
+
+    private static final int TEST_NONE = -1;
+    private static final int TEST_TONE = 0;
+    private static final int TEST_NOISE = 1;
+    private static final int TEST_USB_BACKGROUND = 2;
+    private static final int TEST_USB_NOISE = 3;
+    private static final int TEST_COUNT = 4;
+    private int mCurrentTest = TEST_NONE;
+    private boolean mTestsDone[] = new boolean[TEST_COUNT];
+
+    private static final int TEST_DURATION_DEFAULT = 2000;
+    private static final int TEST_DURATION_TONE = TEST_DURATION_DEFAULT;
+    private static final int TEST_DURATION_NOISE = TEST_DURATION_DEFAULT;
+    private static final int TEST_DURATION_USB_BACKGROUND = TEST_DURATION_DEFAULT;
+    private static final int TEST_DURATION_USB_NOISE = TEST_DURATION_DEFAULT;
+
     final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
     Context mContext;
 
-    Button mTest1Button;                //execute test 1
-    Button mTest2Button;                 //user to start test
-    String mUsbDevicesInfo;             //usb device info for report
-    LinearLayout mLayoutTest1;
-    TextView mTest1Result;
-    ProgressBar mProgressBar;
+    LinearLayout mLayoutTestTone;
+    Button mButtonTestTone;
+    ProgressBar mProgressTone;
+    TextView mResultTestTone;
+    Button mButtonPlayTone;
+
+    LinearLayout mLayoutTestNoise;
+    Button mButtonTestNoise;
+    ProgressBar mProgressNoise;
+    TextView mResultTestNoise;
+    Button mButtonPlayNoise;
+
+    LinearLayout mLayoutTestUsbBackground;
+    Button mButtonTestUsbBackground;
+    ProgressBar mProgressUsbBackground;
+    TextView mResultTestUsbBackground;
+
+    LinearLayout mLayoutTestUsbNoise;
+    Button mButtonTestUsbNoise;
+    ProgressBar mProgressUsbNoise;
+    TextView mResultTestUsbNoise;
+    Button mButtonPlayUsbNoise;
+
+    TextView mGlobalResultText;
+    TextView mTextViewUnprocessedStatus;
 
     private boolean mIsRecording = false;
     private final Object mRecordingLock = new Object();
@@ -95,6 +129,8 @@
 
     PipeShort mPipe = new PipeShort(65536);
 
+    SoundPlayerObject mSPlayer;
+
     private boolean mSupportsUnprocessed = false;
 
     private DspBufferComplex mC;
@@ -102,25 +138,27 @@
 
     private DspWindow mWindow;
     private DspFftServer mFftServer;
-    private VectorAverage mFreqAverageMain = new VectorAverage();
-    private VectorAverage mFreqAverageBuiltIn = new VectorAverage();
+    private VectorAverage mFreqAverageTone = new VectorAverage();
+    private VectorAverage mFreqAverageNoise = new VectorAverage();
+    private VectorAverage mFreqAverageUsbBackground = new VectorAverage();
+    private VectorAverage mFreqAverageUsbNoise = new VectorAverage();
 
-    int mBands = 4;
-    AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
-    private TextView mTextViewUnprocessedStatus;
+    //RMS for tone:
+    private double mRMS;
+    private double mRMSMax;
 
-    private class OnBtnClickListener implements OnClickListener {
-        @Override
-        public void onClick(View v) {
-            switch (v.getId()) {
-            case R.id.audio_frequency_unprocessed_test1_btn:
-                setMaxLevel();
-                testMaxLevel();
-                startTest1();
-                break;
-            }
-        }
-    }
+    private double mRMSTone;
+    private double mRMSMaxTone;
+
+    int mBands = 3;
+    int mBandsTone = 3;
+    int mBandsBack = 3;
+    AudioBandSpecs[] mBandSpecsMic = new AudioBandSpecs[mBands];
+    AudioBandSpecs[] mBandSpecsTone = new AudioBandSpecs[mBandsTone];
+    AudioBandSpecs[] mBandSpecsBack = new AudioBandSpecs[mBandsBack];
+    private Results mResultsMic;
+    private Results mResultsTone;
+    private Results mResultsBack;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -139,13 +177,51 @@
                     getResources().getText(R.string.audio_frequency_unprocessed_not_defined));
         }
 
-        mTest1Button = (Button)findViewById(R.id.audio_frequency_unprocessed_test1_btn);
-        mTest1Button.setOnClickListener(mBtnClickListener);
-        mTest1Result = (TextView)findViewById(R.id.audio_frequency_unprocessed_results1_text);
-        mLayoutTest1 = (LinearLayout) findViewById(R.id.audio_frequency_unprocessed_layout_test1);
-        mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_unprocessed_progress_bar);
-        showWait(false);
-        enableLayout(mLayoutTest1, true);
+        mSPlayer = new SoundPlayerObject();
+        playerSetSource(SOURCE_TONE);
+
+        // Test tone
+        mLayoutTestTone = (LinearLayout) findViewById(R.id.unprocessed_layout_test_tone);
+        mButtonTestTone = (Button) findViewById(R.id.unprocessed_test_tone_btn);
+        mButtonTestTone.setOnClickListener(mBtnClickListener);
+        mProgressTone = (ProgressBar) findViewById(R.id.unprocessed_test_tone_progress_bar);
+        mResultTestTone = (TextView) findViewById(R.id.unprocessed_test_tone_result);
+        mButtonPlayTone = (Button) findViewById(R.id.unprocessed_play_tone_btn);
+        mButtonPlayTone.setOnClickListener(mBtnClickListener);
+        showWait(mProgressTone, false);
+
+        //Test Noise
+        mLayoutTestNoise = (LinearLayout) findViewById(R.id.unprocessed_layout_test_noise);
+        mButtonTestNoise = (Button) findViewById(R.id.unprocessed_test_noise_btn);
+        mButtonTestNoise.setOnClickListener(mBtnClickListener);
+        mProgressNoise = (ProgressBar) findViewById(R.id.unprocessed_test_noise_progress_bar);
+        mResultTestNoise = (TextView) findViewById(R.id.unprocessed_test_noise_result);
+        mButtonPlayNoise = (Button) findViewById(R.id.unprocessed_play_noise_btn);
+        mButtonPlayNoise.setOnClickListener(mBtnClickListener);
+        showWait(mProgressNoise, false);
+
+        //USB Background
+        mLayoutTestUsbBackground = (LinearLayout)
+                findViewById(R.id.unprocessed_layout_test_usb_background);
+        mButtonTestUsbBackground = (Button) findViewById(R.id.unprocessed_test_usb_background_btn);
+        mButtonTestUsbBackground.setOnClickListener(mBtnClickListener);
+        mProgressUsbBackground = (ProgressBar)
+                findViewById(R.id.unprocessed_test_usb_background_progress_bar);
+        mResultTestUsbBackground = (TextView)
+                findViewById(R.id.unprocessed_test_usb_background_result);
+        showWait(mProgressUsbBackground, false);
+
+        mLayoutTestUsbNoise = (LinearLayout) findViewById(R.id.unprocessed_layout_test_usb_noise);
+        mButtonTestUsbNoise = (Button) findViewById(R.id.unprocessed_test_usb_noise_btn);
+        mButtonTestUsbNoise.setOnClickListener(mBtnClickListener);
+        mProgressUsbNoise = (ProgressBar)findViewById(R.id.unprocessed_test_usb_noise_progress_bar);
+        mResultTestUsbNoise = (TextView) findViewById(R.id.unprocessed_test_usb_noise_result);
+        mButtonPlayUsbNoise = (Button) findViewById(R.id.unprocessed_play_usb_noise_btn);
+        mButtonPlayUsbNoise.setOnClickListener(mBtnClickListener);
+        showWait(mProgressUsbNoise, false);
+
+        setButtonPlayStatus(-1);
+        mGlobalResultText = (TextView) findViewById(R.id.unprocessed_test_global_result);
 
         //Init FFT stuff
         mAudioShortArray2 = new short[mBlockSizeSamples*2];
@@ -162,29 +238,141 @@
         setInfoResources(R.string.audio_frequency_unprocessed_test,
                 R.string.audio_frequency_unprocessed_info, -1);
 
-        //Init bands for BuiltIn/Reference test
-        bandSpecsArray[0] = new AudioBandSpecs(
-                2, 500,         /* frequency start,stop */
-                30.0, -50,     /* start top,bottom value */
-                30.0, -4.0       /* stop top,bottom value */);
+        //Init bands for Mic test
+        mBandSpecsMic[0] = new AudioBandSpecs(
+                5, 100,          /* frequency start,stop */
+                20.0, -20.0,     /* start top,bottom value */
+                20.0, -20.0      /* stop top,bottom value */);
 
-        bandSpecsArray[1] = new AudioBandSpecs(
-                500,4000,       /* frequency start,stop */
-                4.0, -4.0,      /* start top,bottom value */
-                4.0, -4.0        /* stop top,bottom value */);
+        mBandSpecsMic[1] = new AudioBandSpecs(
+                100, 7000,       /* frequency start,stop */
+                10.0, -10.0,     /* start top,bottom value */
+                10.0, -10.0      /* stop top,bottom value */);
 
-        bandSpecsArray[2] = new AudioBandSpecs(
-                4000, 12000,    /* frequency start,stop */
-                4.0, -4.0,      /* start top,bottom value */
-                5.0, -5.0       /* stop top,bottom value */);
+        mBandSpecsMic[2] = new AudioBandSpecs(
+                7000, 20000,     /* frequency start,stop */
+                30.0, -30.0,     /* start top,bottom value */
+                30.0, -30.0      /* stop top,bottom value */);
 
-        bandSpecsArray[3] = new AudioBandSpecs(
-                12000, 20000,   /* frequency start,stop */
-                5.0, -5.0,      /* start top,bottom value */
-                5.0, -30.0      /* stop top,bottom value */);
+        //Init bands for Tone test
+        mBandSpecsTone[0] = new AudioBandSpecs(
+                5, 900,          /* frequency start,stop */
+                -10.0, -100.0,     /* start top,bottom value */
+                -10.0, -100.0      /* stop top,bottom value */);
+
+        mBandSpecsTone[1] = new AudioBandSpecs(
+                900, 1100,       /* frequency start,stop */
+                10.0, -50.0,     /* start top,bottom value */
+                10.0, -10.0      /* stop top,bottom value */);
+
+        mBandSpecsTone[2] = new AudioBandSpecs(
+                1100, 20000,     /* frequency start,stop */
+                -30.0, -120.0,     /* start top,bottom value */
+                -30.0, -120.0      /* stop top,bottom value */);
+
+      //Init bands for Background test
+        mBandSpecsBack[0] = new AudioBandSpecs(
+                5, 100,          /* frequency start,stop */
+                10.0, -120.0,     /* start top,bottom value */
+                -10.0, -120.0      /* stop top,bottom value */);
+
+        mBandSpecsBack[1] = new AudioBandSpecs(
+                100, 7000,       /* frequency start,stop */
+                -10.0, -120.0,     /* start top,bottom value */
+                -50.0, -120.0      /* stop top,bottom value */);
+
+        mBandSpecsBack[2] = new AudioBandSpecs(
+                7000, 20000,     /* frequency start,stop */
+                -50.0, -120.0,     /* start top,bottom value */
+                -50.0, -120.0      /* stop top,bottom value */);
 
         mSupportsUnprocessed = supportsUnprocessed();
         Log.v(TAG, "Supports unprocessed: " + mSupportsUnprocessed);
+
+        mResultsMic =  new Results("mic_response", mBands);
+        mResultsTone = new Results("tone_response", mBandsTone);
+        mResultsBack = new Results("background_response", mBandsBack);
+    }
+
+    private void playerToggleButton(int buttonId, int sourceId) {
+        if (playerIsPlaying()) {
+            playerStopAll();
+        } else {
+            playerSetSource(sourceId);
+            playerTransport(true);
+            setButtonPlayStatus(buttonId);
+        }
+    }
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            int id = v.getId();
+            switch (id) {
+            case R.id.unprocessed_test_tone_btn:
+                startTest(TEST_TONE);
+                break;
+            case R.id.unprocessed_play_tone_btn:
+                playerToggleButton(id, SOURCE_TONE);
+                break;
+            case R.id.unprocessed_test_noise_btn:
+                startTest(TEST_NOISE);
+                break;
+            case R.id.unprocessed_play_noise_btn:
+                playerToggleButton(id, SOURCE_NOISE);
+                break;
+            case R.id.unprocessed_test_usb_background_btn:
+                startTest(TEST_USB_BACKGROUND);
+                break;
+            case R.id.unprocessed_test_usb_noise_btn:
+                startTest(TEST_USB_NOISE);
+                break;
+            case R.id.unprocessed_play_usb_noise_btn:
+                playerToggleButton(id, SOURCE_NOISE);
+                break;
+            }
+        }
+    }
+
+    private void setButtonPlayStatus(int playResId) {
+        String play = getResources().getText(R.string.unprocessed_play).toString();
+        String stop = getResources().getText(R.string.unprocessed_stop).toString();
+
+        mButtonPlayTone.setText(playResId == R.id.unprocessed_play_tone_btn ? stop : play);
+        mButtonPlayNoise.setText(playResId == R.id.unprocessed_play_noise_btn ? stop : play);
+        mButtonPlayUsbNoise.setText(playResId ==
+                R.id.unprocessed_play_usb_noise_btn ? stop : play);
+    }
+
+    private void playerSetSource(int sourceIndex) {
+        switch (sourceIndex) {
+            case SOURCE_TONE:
+                mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.onekhztone);
+                break;
+            default:
+            case SOURCE_NOISE:
+                mSPlayer.setSoundWithResId(getApplicationContext(),
+                        R.raw.stereo_mono_white_noise_48);
+                break;
+        }
+    }
+
+    private void playerTransport(boolean play) {
+        if (!mSPlayer.isAlive()) {
+            mSPlayer.start();
+        }
+        mSPlayer.play(play);
+    }
+
+    private boolean playerIsPlaying() {
+       return mSPlayer.isPlaying();
+    }
+
+    private void playerStopAll() {
+        if (mSPlayer.isAlive() && mSPlayer.isPlaying()) {
+            mSPlayer.play(false);
+            setButtonPlayStatus(-1);
+        }
     }
 
     /**
@@ -197,14 +385,66 @@
         }
     }
 
-    /**
-     * show active progress bar
-     */
-    private void showWait(boolean show) {
+    private void showWait(ProgressBar pb, boolean show) {
         if (show) {
-            mProgressBar.setVisibility(View.VISIBLE);
+            pb.setVisibility(View.VISIBLE);
         } else {
-            mProgressBar.setVisibility(View.INVISIBLE);
+            pb.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    private String getTestString(int testId) {
+        String name = "undefined";
+        switch(testId) {
+            case TEST_TONE:
+                name = "BuiltIn_tone";
+                break;
+            case TEST_NOISE:
+                name = "BuiltIn_noise";
+                break;
+            case TEST_USB_BACKGROUND:
+                name = "USB_background";
+                break;
+            case TEST_USB_NOISE:
+                name = "USB_noise";
+                break;
+        }
+        return name;
+    }
+
+    private void showWait(int testId, boolean show) {
+        switch(testId) {
+            case TEST_TONE:
+                showWait(mProgressTone, show);
+                break;
+            case TEST_NOISE:
+                showWait(mProgressNoise, show);
+                break;
+            case TEST_USB_BACKGROUND:
+                showWait(mProgressUsbBackground, show);
+                break;
+            case TEST_USB_NOISE:
+                showWait(mProgressUsbNoise, show);
+                break;
+        }
+    }
+
+    private void showMessage(int testId, String msg) {
+        if (msg != null && msg.length() > 0) {
+            switch(testId) {
+                case TEST_TONE:
+                    mResultTestTone.setText(msg);
+                    break;
+                case TEST_NOISE:
+                    mResultTestNoise.setText(msg);
+                    break;
+                case TEST_USB_BACKGROUND:
+                    mResultTestUsbBackground.setText(msg);
+                    break;
+                case TEST_USB_NOISE:
+                    mResultTestUsbNoise.setText(msg);
+                    break;
+            }
         }
     }
 
@@ -224,47 +464,320 @@
         return unprocessedSupport;
     }
 
-    /**
-     *  Start the loopback audio test
-     */
-    private void startTest1() {
+    private void computeAllResults() {
+        StringBuilder sb = new StringBuilder();
+
+        boolean allDone = true;
+
+        for (int i=0; i<TEST_COUNT; i++) {
+            allDone = allDone & mTestsDone[i];
+            sb.append(String.format("%s : %s\n", getTestString(i),
+                    mTestsDone[i] ? "DONE" :" NOT DONE"));
+        }
+
+        if (allDone) {
+            sb.append(computeResults());
+        } else {
+            sb.append("Please execute all tests for results\n");
+        }
+        mGlobalResultText.setText(sb.toString());
+    }
+
+    private void processSpectrum(Results results, AudioBandSpecs[] bandsSpecs, int anchorBand) {
+        int points = results.mValuesLog.length;
+        int bandCount = bandsSpecs.length;
+        int currentBand = 0;
+        for (int i = 0; i < points; i++) {
+            double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+            if (freq > bandsSpecs[currentBand].mFreqStop) {
+                currentBand++;
+                if (currentBand >= bandCount)
+                    break;
+            }
+
+            if (freq >= bandsSpecs[currentBand].mFreqStart) {
+                results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+                results.mPointsPerBand[currentBand]++;
+            }
+        }
+
+        for (int b = 0; b < bandCount; b++) {
+            if (results.mPointsPerBand[b] > 0) {
+                results.mAverageEnergyPerBand[b] =
+                        results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+            }
+        }
+
+        //set offset relative to band anchor band level
+        for (int b = 0; b < bandCount; b++) {
+            if (anchorBand > -1 && anchorBand < bandCount) {
+                bandsSpecs[b].setOffset(results.mAverageEnergyPerBand[anchorBand]);
+            } else {
+                bandsSpecs[b].setOffset(0);
+            }
+        }
+
+        //test points in band.
+        currentBand = 0;
+        for (int i = 0; i < points; i++) {
+            double freq = (double) mSamplingRate * i / (double) mBlockSizeSamples;
+            if (freq >  bandsSpecs[currentBand].mFreqStop) {
+                currentBand++;
+                if (currentBand >= bandCount)
+                    break;
+            }
+
+            if (freq >= bandsSpecs[currentBand].mFreqStart) {
+                double value = results.mValuesLog[i];
+                if (bandsSpecs[currentBand].isInBounds(freq, value)) {
+                    results.mInBoundPointsPerBand[currentBand]++;
+                }
+            }
+        }
+    }
+
+    private String computeResults() {
+        StringBuilder sb = new StringBuilder();
+
+        int points = mFreqAverageNoise.getSize();
+        //mFreqAverageNoise size is determined by the latest data writen to it.
+        //Currently, this data is always mBlockSizeSamples/2.
+        if (points < 1) {
+            return "error: not enough points";
+        }
+
+        double[] tone = new double[points];
+        double[] noise = new double[points];
+        double[] reference = new double[points];
+        double[] background = new double[points];
+
+        mFreqAverageTone.getData(tone, false);
+        mFreqAverageNoise.getData(noise, false);
+        mFreqAverageUsbNoise.getData(reference, false);
+        mFreqAverageUsbBackground.getData(background, false);
+
+        //Convert to dB
+        double[] toneDb = new double[points];
+        double[] noiseDb = new double[points];
+        double[] referenceDb = new double[points];
+        double[] backgroundDb = new double[points];
+
+        double[] compensatedNoiseDb = new double[points];
+
+        for (int i = 0; i < points; i++) {
+            toneDb[i] = 20 * Math.log10(tone[i]);
+            noiseDb[i] = 20 * Math.log10(noise[i]);
+            referenceDb[i] = 20 * Math.log10(reference[i]);
+            backgroundDb[i] = 20 * Math.log10(background[i]);
+
+            compensatedNoiseDb[i] = noiseDb[i] - referenceDb[i];
+        }
+
+        mResultsMic.reset();
+        mResultsTone.reset();
+        mResultsBack.reset();
+
+        mResultsMic.mValuesLog = compensatedNoiseDb;
+        mResultsTone.mValuesLog = toneDb;
+        mResultsBack.mValuesLog = backgroundDb;
+
+        processSpectrum(mResultsMic, mBandSpecsMic, 1);
+        processSpectrum(mResultsTone, mBandSpecsTone, 1);
+        processSpectrum(mResultsBack, mBandSpecsBack, -1); //no reference for offset
+
+        //Tone test
+        boolean toneTestSuccess = true;
+        {
+            //rms level should be -36 dbfs +/- 3 db?
+            double rmsMaxDb =  20 * Math.log10(mRMSMaxTone);
+            sb.append(String.format("RMS level of tone: %.2f dBFS\n", rmsMaxDb));
+            sb.append(String.format("Target RMS level: %.2f dBFS +/- %.2f dB\n",
+                    TONE_RMS_EXPECTED,
+                    TONE_RMS_MAX_ERROR));
+            if (Math.abs(rmsMaxDb - TONE_RMS_EXPECTED) > TONE_RMS_MAX_ERROR) {
+                toneTestSuccess = false;
+                sb.append("RMS level test FAILED\n");
+            } else {
+                sb.append(" RMS level test SUCCESSFUL\n");
+            }
+            //check the spectrum is really a tone around 1 khz
+        }
+
+        sb.append("\n");
+        sb.append(mResultsTone.toString());
+        if (mResultsTone.testAll()) {
+            sb.append(" 1 Khz Tone Frequency Response Test SUCCESSFUL\n");
+        } else {
+            sb.append(" 1 Khz Tone Frequency Response Test FAILED\n");
+        }
+        sb.append("\n");
+
+        sb.append("\n");
+        sb.append(mResultsBack.toString());
+        if (mResultsBack.testAll()) {
+            sb.append(" Background environment Test SUCCESSFUL\n");
+        } else {
+            sb.append(" Background environment Test FAILED\n");
+        }
+
+        sb.append("\n");
+        sb.append(mResultsMic.toString());
+        if (mResultsMic.testAll()) {
+            sb.append(" Frequency Response Test SUCCESSFUL\n");
+        } else {
+            sb.append(" Frequency Response Test FAILED\n");
+        }
+        sb.append("\n");
+
+        recordTestResults(mResultsTone);
+        recordTestResults(mResultsMic);
+
+        boolean allTestsPassed = false;
+        if (mResultsMic.testAll() && mResultsTone.testAll() && toneTestSuccess &&
+                mResultsBack.testAll()) {
+            allTestsPassed = true;
+            String strSuccess = getResources().getString(R.string.audio_general_test_passed);
+            sb.append(strSuccess);
+        } else {
+            String strFailed = getResources().getString(R.string.audio_general_test_failed);
+            sb.append(strFailed);
+        }
+
+        sb.append("\n");
+        if (mSupportsUnprocessed) { //test is mandatory
+            sb.append(getResources().getText(
+                    R.string.audio_frequency_unprocessed_defined).toString());
+            if (allTestsPassed) {
+                getPassButton().setEnabled(true);
+            } else {
+                getPassButton().setEnabled(false);
+            }
+        } else {
+            //test optional
+            sb.append(getResources().getText(
+                    R.string.audio_frequency_unprocessed_not_defined).toString());
+            getPassButton().setEnabled(true);
+        }
+        return sb.toString();
+    }
+
+    Thread mTestThread;
+    private void startTest(int testId) {
         if (mTestThread != null && !mTestThread.isAlive()) {
             mTestThread = null; //kill it.
         }
 
         if (mTestThread == null) {
+            mRMS = 0;
+            mRMSMax = 0;
             Log.v(TAG,"Executing test Thread");
-            mTestThread = new Thread(mTest1Runnable);
+            switch(testId) {
+                case TEST_TONE:
+                    mTestThread = new Thread(new TestRunnable(TEST_TONE) {
+                        public void run() {
+                            super.run();
+                            if (!mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE,
+                                        "Testing Built in Microphone: Tone");
+                                mRMSTone = 0;
+                                mRMSMaxTone = 0;
+                                mFreqAverageTone.reset();
+                                mFreqAverageTone.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                                record(TEST_DURATION_TONE);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "Please Unplug USB Microphone");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+                case TEST_NOISE:
+                    mTestThread = new Thread(new TestRunnable(TEST_NOISE) {
+                        public void run() {
+                            super.run();
+                            if (!mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE,
+                                        "Testing Built in Microphone: Noise");
+                                mFreqAverageNoise.reset();
+                                mFreqAverageNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                                record(TEST_DURATION_NOISE);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "Please Unplug USB Microphone");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+                case TEST_USB_BACKGROUND:
+                    playerStopAll();
+                    mTestThread = new Thread(new TestRunnable(TEST_USB_BACKGROUND) {
+                        public void run() {
+                            super.run();
+                            if (mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE,
+                                        "Testing USB Microphone: background");
+                                mFreqAverageUsbBackground.reset();
+                                mFreqAverageUsbBackground.setCaptureType(
+                                        VectorAverage.CAPTURE_TYPE_AVERAGE);
+                                record(TEST_DURATION_USB_BACKGROUND);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "USB Microphone not detected.");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+                case TEST_USB_NOISE:
+                    mTestThread = new Thread(new TestRunnable(TEST_USB_NOISE) {
+                        public void run() {
+                            super.run();
+                            if (mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE, "Testing USB Microphone: Noise");
+                                mFreqAverageUsbNoise.reset();
+                                mFreqAverageUsbNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                                record(TEST_DURATION_USB_NOISE);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "USB Microphone not detected.");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+            }
             mTestThread.start();
         } else {
             Log.v(TAG,"test Thread already running.");
         }
     }
-
-    Thread mTestThread;
-    Runnable mTest1Runnable = new Runnable() {
-        public void run() {
-            Message msg = Message.obtain();
-            msg.what = TEST_STARTED;
-            mMessageHandler.sendMessage(msg);
-
-            sendMessage("Testing Built in Microphone");
-            mFreqAverageBuiltIn.reset();
-            mFreqAverageBuiltIn.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
-            play();
-
-            sendMessage("Testing Completed");
-
-            Message msg2 = Message.obtain();
-            msg2.what = TEST1_ENDED;
-            mMessageHandler.sendMessage(msg2);
+    public class TestRunnable implements Runnable {
+        public int mTestId;
+        public boolean mUsbMicConnected;
+        TestRunnable(int testId) {
+            Log.v(TAG,"New TestRunnable");
+            mTestId = testId;
         }
-
-        private void play() {
+        public void run() {
+            mCurrentTest = mTestId;
+            sendMessage(mTestId, TEST_STARTED,"");
+            mUsbMicConnected =
+                    UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+        };
+        public void record(int durationMs) {
             startRecording();
-
             try {
-                Thread.sleep(5000);
+                Thread.sleep(durationMs);
             } catch (InterruptedException e) {
                 e.printStackTrace();
                 //restore interrupted status
@@ -272,41 +785,40 @@
             }
             stopRecording();
         }
-
-        private void sendMessage(String str) {
+        public void sendMessage(int testId, int msgType, String str) {
             Message msg = Message.obtain();
-            msg.what = TEST1_MESSAGE;
+            msg.what = msgType;
             msg.obj = str;
+            msg.arg1 = testId;
             mMessageHandler.sendMessage(msg);
         }
-    };
+    }
 
     private Handler mMessageHandler = new Handler() {
         public void handleMessage(Message msg) {
             super.handleMessage(msg);
+            int testId = msg.arg1; //testId
+            String str = (String) msg.obj;
             switch (msg.what) {
             case TEST_STARTED:
-                showWait(true);
-                getPassButton().setEnabled(false);
+                showWait(testId, true);
+//                getPassButton().setEnabled(false);
+                break;
+            case TEST_MESSAGE:
+                    showMessage(testId, str);
                 break;
             case TEST_ENDED:
-                showWait(false);
-//                computeTest2Results();
+                showWait(testId, false);
+                playerStopAll();
+                showMessage(testId, str);
+                appendResultsToScreen(testId, "test finished");
+                computeAllResults();
                 break;
-            case TEST1_MESSAGE: {
-                    String str = (String)msg.obj;
-                    if (str != null) {
-                        mTest1Result.setText(str);
-                    }
-                }
-                break;
-            case TEST1_ENDED:
-                showWait(false);
-                computeTest1Results();
-                break;
-            case TEST_MESSAGE: {
-                }
-                break;
+            case TEST_ENDED_ERROR:
+                showWait(testId, false);
+                playerStopAll();
+                showMessage(testId, str);
+                computeAllResults();
             default:
                 Log.e(TAG, String.format("Unknown message: %d", msg.what));
             }
@@ -314,21 +826,32 @@
     };
 
     private class Results {
+        private int mBandCount;
         private String mLabel;
         public double[] mValuesLog;
-        int[] mPointsPerBand = new int[mBands];
-        double[] mAverageEnergyPerBand = new double[mBands];
-        int[] mInBoundPointsPerBand = new int[mBands];
-        public Results(String label) {
+        int[] mPointsPerBand; // = new int[mBands];
+        double[] mAverageEnergyPerBand;// = new double[mBands];
+        int[] mInBoundPointsPerBand;// = new int[mBands];
+        public Results(String label, int bandCount) {
             mLabel = label;
+            mBandCount = bandCount;
+            mPointsPerBand = new int[mBandCount];
+            mAverageEnergyPerBand = new double[mBandCount];
+            mInBoundPointsPerBand = new int[mBandCount];
+        }
+        public void reset() {
+            for (int i = 0; i < mBandCount; i++) {
+                mPointsPerBand[i] = 0;
+                mAverageEnergyPerBand[i] = 0;
+                mInBoundPointsPerBand[i] = 0;
+            }
         }
 
         //append results
         public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append(String.format("Channel %s\n", mLabel));
-            sb.append("Level in Band 1 : " + (testLevel() ? "OK" :"Not Optimal") + "\n");
-            for (int b = 0; b < mBands; b++) {
+            for (int b = 0; b < mBandCount; b++) {
                 double percent = 0;
                 if (mPointsPerBand[b] > 0) {
                     percent = 100.0 * (double) mInBoundPointsPerBand[b] / mPointsPerBand[b];
@@ -344,15 +867,8 @@
             return sb.toString();
         }
 
-        public boolean testLevel() {
-            if (mAverageEnergyPerBand[1] >= MIN_ENERGY_BAND_1) {
-                return true;
-            }
-            return false;
-        }
-
         public boolean testInBand(int b) {
-            if (b >= 0 && b < mBands && mPointsPerBand[b] > 0) {
+            if (b >= 0 && b < mBandCount && mPointsPerBand[b] > 0) {
                 if ((double) mInBoundPointsPerBand[b] / mPointsPerBand[b] >
                     MIN_FRACTION_POINTS_IN_BAND) {
                         return true;
@@ -362,10 +878,7 @@
         }
 
         public boolean testAll() {
-            if (!testLevel()) {
-                return false;
-            }
-            for (int b = 0; b < mBands; b++) {
+            for (int b = 0; b < mBandCount; b++) {
                 if (!testInBand(b)) {
                     return false;
                 }
@@ -375,98 +888,13 @@
     }
 
 
-    /**
-     * compute test1 results
-     */
-    private void computeTest1Results() {
-        Results resultsBuiltIn = new Results("BuiltIn");
-        if (computeResultsForVector(mFreqAverageBuiltIn, resultsBuiltIn, bandSpecsArray)) {
-            appendResultsToScreen(resultsBuiltIn.toString(), mTest1Result);
-            recordTestResults(resultsBuiltIn);
-        }
-        if (mSupportsUnprocessed) { //test is mandatory
-            appendResultsToScreen(getResources().getText(
-                    R.string.audio_frequency_unprocessed_defined).toString(), mTest1Result);
-            if (resultsBuiltIn.testAll()) {
-                //tst passed
-                getPassButton().setEnabled(true);
-                String strSuccess = getResources().getString(R.string.audio_general_test_passed);
-                appendResultsToScreen(strSuccess, mTest1Result);
-            } else {
-                getPassButton().setEnabled(false);
-                String strFailed = getResources().getString(R.string.audio_general_test_failed);
-                appendResultsToScreen(strFailed, mTest1Result);
-            }
-        } else {
-            //test optional
-            appendResultsToScreen(getResources().getText(
-                    R.string.audio_frequency_unprocessed_not_defined).toString(), mTest1Result);
-            getPassButton().setEnabled(true);
-        }
-    }
-
-    private boolean computeResultsForVector(VectorAverage freqAverage, Results results,
-            AudioBandSpecs[] bandSpecs) {
-
-        int points = freqAverage.getSize();
-        if (points > 0) {
-            //compute vector in db
-            double[] values = new double[points];
-            freqAverage.getData(values, false);
-            results.mValuesLog = new double[points];
-            for (int i = 0; i < points; i++) {
-                results.mValuesLog[i] = 20 * Math.log10(values[i]);
-            }
-
-            int currentBand = 0;
-            for (int i = 0; i < points; i++) {
-                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
-                if (freq > bandSpecs[currentBand].mFreqStop) {
-                    currentBand++;
-                    if (currentBand >= mBands)
-                        break;
-                }
-
-                if (freq >= bandSpecs[currentBand].mFreqStart) {
-                    results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
-                    results.mPointsPerBand[currentBand]++;
-                }
-            }
-
-            for (int b = 0; b < mBands; b++) {
-                if (results.mPointsPerBand[b] > 0) {
-                    results.mAverageEnergyPerBand[b] =
-                            results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
-                }
-            }
-
-            //set offset relative to band 1 level
-            for (int b = 0; b < mBands; b++) {
-                bandSpecs[b].setOffset(results.mAverageEnergyPerBand[1]);
-            }
-
-            //test points in band.
-            currentBand = 0;
-            for (int i = 0; i < points; i++) {
-                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
-                if (freq >  bandSpecs[currentBand].mFreqStop) {
-                    currentBand++;
-                    if (currentBand >= mBands)
-                        break;
-                }
-
-                if (freq >= bandSpecs[currentBand].mFreqStart) {
-                    double value = results.mValuesLog[i];
-                    if (bandSpecs[currentBand].isInBounds(freq, value)) {
-                        results.mInBoundPointsPerBand[currentBand]++;
-                    }
-                }
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
+//    /**
+//     * compute test results
+//     */
+//    private void computeTestResults(int testId) {
+//        String testName = getTestString(testId);
+//        appendResultsToScreen(testId, "test finished");
+//    }
 
     //append results
     private void appendResultsToScreen(String str, TextView text) {
@@ -474,6 +902,24 @@
         text.setText(currentText + "\n" + str);
     }
 
+    private void appendResultsToScreen(int testId, String str) {
+        switch(testId) {
+            case TEST_TONE:
+                appendResultsToScreen(str, mResultTestTone);
+                showToneRMS();
+                break;
+            case TEST_NOISE:
+                appendResultsToScreen(str, mResultTestNoise);
+                break;
+            case TEST_USB_BACKGROUND:
+                appendResultsToScreen(str, mResultTestUsbBackground);
+                break;
+            case TEST_USB_NOISE:
+                appendResultsToScreen(str, mResultTestUsbNoise);
+                break;
+        }
+    }
+
     /**
      * Store test results in log
      */
@@ -615,6 +1061,12 @@
         mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
         return true;
     }
+    private void showToneRMS() {
+        String str = String.format("RMS: %.3f dBFS. Max RMS: %.3f dBFS",
+                20 * Math.log10(mRMSTone),
+                20 * Math.log10(mRMSMaxTone));
+        showMessage(TEST_TONE, str);
+    }
 
     // ---------------------------------------------------------
     // Implementation of AudioRecord.OnPeriodicNotificationListener
@@ -627,9 +1079,10 @@
 
             //compute stuff.
             int clipcount = 0;
-            double sum = 0;
+//            double sum = 0;
             double maxabs = 0;
             int i;
+            double rmsTempSum = 0;
 
             for (i = 0; i < samplesNeeded; i++) {
                 double value = mAudioShortArray2[i] / MAX_VAL;
@@ -643,10 +1096,18 @@
                     clipcount++;
                 }
 
-                sum += value * value;
+                rmsTempSum += value * value;
                 //fft stuff
                 mData.mData[i] = value;
             }
+            double rms = Math.sqrt(rmsTempSum / samplesNeeded);
+
+            double alpha = 0.9;
+            double total_rms = rms * alpha + mRMS *(1-alpha);
+            mRMS = total_rms;
+            if (mRMS > mRMSMax) {
+                mRMSMax = mRMS;
+            }
 
             //for the current frame, compute FFT and send to the viewer.
 
@@ -660,8 +1121,25 @@
                 halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
             }
 
-            mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
-            mFreqAverageBuiltIn.setData(halfMagnitude, false);
+            switch(mCurrentTest) {
+                case TEST_TONE: {
+                    mFreqAverageTone.setData(halfMagnitude, false);
+                    //Update realtime info on screen
+                    mRMSTone = mRMS;
+                    mRMSMaxTone = mRMSMax;
+                   showToneRMS();
+                }
+                    break;
+                case TEST_NOISE:
+                    mFreqAverageNoise.setData(halfMagnitude, false);
+                    break;
+                case TEST_USB_BACKGROUND:
+                    mFreqAverageUsbBackground.setData(halfMagnitude, false);
+                    break;
+                case TEST_USB_NOISE:
+                    mFreqAverageUsbNoise.setData(halfMagnitude, false);
+                    break;
+            }
         }
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 1349694..cf8ec89 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -97,8 +97,10 @@
                     }
                 } break;
                 case COMMAND_DISALLOW_KEYGUARD_UNREDACTED_NOTIFICATIONS: {
-                    mDpm.setKeyguardDisabledFeatures(mAdmin,
-                            DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+                    boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
+                    mDpm.setKeyguardDisabledFeatures(mAdmin, enforced
+                            ? DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS
+                            : 0);
                 } break;
                 case COMMAND_SET_AUTO_TIME_REQUIRED: {
                     mDpm.setAutoTimeRequired(mAdmin,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java
index 985cbf6..3cabbd3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java
@@ -67,11 +67,8 @@
     @Override
     public void finish() {
         // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
-        // clear the password.
-        final ComponentName adminComponent = getAdminComponent();
-        if (mDpm.isAdminActive(adminComponent)) {
-            allowAppsControl();
-        }
+        // clear the restriction.
+        allowAppsControl();
         super.finish();
     }
 
@@ -120,9 +117,4 @@
         setupCheckDisabledForceStopTest(adapter);
         setupCheckDisabledAppStorageButtonsTest(adapter);
     }
-
-    @Override
-    protected void clearRemainingState(final DialogTestListItem test) {
-        allowAppsControl();
-    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
index 5585cbc..27a140c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
@@ -21,6 +21,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
 import android.provider.Settings;
@@ -32,6 +34,8 @@
 import com.android.cts.verifier.DialogTestListActivity;
 import com.android.cts.verifier.R;
 
+import java.util.List;
+
 public class KeyguardDisabledFeaturesActivity extends DialogTestListActivity {
 
     protected DevicePolicyManager mDpm;
@@ -131,11 +135,20 @@
 
     @Override
     protected void setupTests(ArrayTestListAdapter adapter) {
-        setupDisableTrustAgentsTest(adapter);
+        if (hasTrustAgents()) {
+            setupDisableTrustAgentsTest(adapter);
+        }
         setupDisableUnredactedWorkNotification(adapter);
         setupFingerprintTests(adapter);
     }
 
+    private boolean hasTrustAgents() {
+        PackageManager packageManager = getPackageManager();
+        Intent intent = new Intent("android.service.trust.TrustAgentService");
+        List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(intent, 0);
+        return resolveInfos.size() > 0;
+    }
+
     @Override
     protected void clearRemainingState(final DialogTestListItem test) {
         super.clearRemainingState(test);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java
index 9261284..5eaf862 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java
@@ -266,7 +266,8 @@
         return mTestId;
     }
 
-    public class DummyAccessibilityService extends AccessibilityService {
+    public static class DummyAccessibilityService extends AccessibilityService {
+
         @Override
         public void onAccessibilityEvent(AccessibilityEvent event) {
             // Do nothing
@@ -278,7 +279,7 @@
         }
     }
 
-    public class DummyInputMethod extends InputMethodService {
+    public static class DummyInputMethod extends InputMethodService {
         @Override
         public boolean onEvaluateFullscreenMode() {
             return false;
@@ -306,4 +307,4 @@
             this.command = command;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
index 34c7cc4..c5b4a93 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
@@ -122,8 +122,8 @@
     private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
         for (String restriction : UserRestrictions.getUserRestrictions()) {
             final Intent intent = UserRestrictions.getUserRestrictionTestIntent(this, restriction);
-            if (!UserRestrictions.isRestrictionValid(this, restriction) &&
-                    !mIsDeviceOwner && !UserRestrictions.isValidForPO(restriction)) {
+            if (!UserRestrictions.isRestrictionValid(this, restriction) ||
+                    (!mIsDeviceOwner && !UserRestrictions.isValidForPO(restriction))) {
                 continue;
             }
             final String title = UserRestrictions.getRestrictionLabel(this, restriction);
@@ -135,8 +135,8 @@
         for (Pair<Intent, Integer> policy : POLICIES) {
             final Intent intent = policy.first;
             String test = intent.getStringExtra(PolicyTransparencyTestActivity.EXTRA_TEST);
-            if (!isPolicyValid(test) &&
-                    !mIsDeviceOwner && !ALSO_VALID_FOR_PO.contains(test)) {
+            if (!isPolicyValid(test) ||
+                    (!mIsDeviceOwner && !ALSO_VALID_FOR_PO.contains(test))) {
                 continue;
             }
             final String title = getString(policy.second);
@@ -191,4 +191,4 @@
                 : CommandReceiverActivity.COMMAND_PROFILE_OWNER_CLEAR_POLICIES);
         startActivity(intent);
     }
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
index 49c0c20..b7c10bb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
@@ -56,7 +56,7 @@
     private DevicePolicyManager mDevicePolicyManager;
     private UserManager mUserManager;
     private static final String TAG = "DeviceOwnerPositiveTestActivity";
-    private static final int REQUEST_VPN_CODE = 1;
+    private static final int REQUEST_VPN_CODE = 54321;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -81,12 +81,13 @@
 
     @Override
     protected void onActivityResult(int requestCode, int result, Intent data) {
-        if (requestCode == REQUEST_VPN_CODE && result == RESULT_OK) {
+        if (requestCode == REQUEST_VPN_CODE) {
+            // We don't care about the result - ideally it should automatically cancel, but if
+            // some custom component doesn't do that, try to establish the connection anyway
+            // and see what happens.
             establishVpn();
         } else {
-            // vpn connection canceled by user
-            Log.w(TAG, "Test failed, canceled by user");
-            populateInfo(R.string.device_owner_vpn_connection_canceled);
+            Log.w(TAG, "Unexpected request code: " + requestCode);
         }
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
index 9a76f04..24d88b7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -447,6 +447,11 @@
                                 // Now that it's subscribed, remove the rule and verify that it
                                 // unsubscribes.
                                 mNm.removeAutomaticZenRule(id);
+                                try {
+                                    Thread.sleep(3000);
+                                } catch (InterruptedException e) {
+                                    logFail("unexpected InterruptedException");
+                                }
                                 MockConditionProvider.probeSubscribe(mContext,
                                         new MockConditionProvider.ParcelableListResultCatcher() {
                                             @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index 802df56..6c294e5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -17,6 +17,7 @@
 
 import android.app.Activity;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -38,6 +39,9 @@
 public class MockListener extends NotificationListenerService {
     static final String TAG = "MockListener";
 
+    public static final ComponentName COMPONENT_NAME =
+            new ComponentName("com.android.cts.verifier", MockListener.class.getName());
+
     static final String SERVICE_BASE = "android.service.notification.cts.";
     static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
     static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED";
@@ -47,13 +51,20 @@
     static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
     static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE";
     static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL";
-    public static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
-    public static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+    static final String SERVICE_SNOOZE = SERVICE_BASE + "SERVICE_SNOOZE";
+    static final String SERVICE_HINTS = SERVICE_BASE + "SERVICE_HINTS";
+    static final String SERVICE_PROBE_HINTS = SERVICE_BASE + "SERVICE_PROBE_HINTS";
+    static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
+    static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+    static final String SERVICE_SNOOZE_ONE = SERVICE_BASE + "SERVICE_SNOOZE_ONE";
+    static final String SERVICE_UNSNOOZE_ONE = SERVICE_BASE + "SERVICE_UNSNOOZE_ONE";
+    static final String SERVICE_SNOOZE_UNTIL = SERVICE_BASE + "SERVICE_SNOOZE_UNTIL";
 
     static final String EXTRA_PAYLOAD = "PAYLOAD";
     static final String EXTRA_INT = "INT";
     static final String EXTRA_TAG = "TAG";
     static final String EXTRA_CODE = "CODE";
+    static final String EXTRA_LONG = "LONG";
 
     static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
 
@@ -67,6 +78,7 @@
     public static final String JSON_AMBIENT = "ambient";
     public static final String JSON_MATCHES_ZEN_FILTER = "matches_zen_filter";
     public static final String JSON_REASON = "reason";
+    public static final String JSON_HINTS = "hints";
 
     private ArrayList<String> mPosted = new ArrayList<String>();
     private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
@@ -92,31 +104,24 @@
         mReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
+                final String action = intent.getAction();
+                final Bundle bundle = new Bundle();
+                Log.d(TAG, action);
                 if (SERVICE_CHECK.equals(action)) {
-                    Log.d(TAG, "SERVICE_CHECK");
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_POSTED.equals(action)) {
-                    Log.d(TAG, "SERVICE_POSTED");
-                    Bundle bundle = new Bundle();
                     bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_DND.equals(action)) {
-                    Log.d(TAG, "SERVICE_DND");
-                    Bundle bundle = new Bundle();
                     bundle.putInt(EXTRA_INT, mDND);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_ORDER.equals(action)) {
-                    Log.d(TAG, "SERVICE_ORDER");
-                    Bundle bundle = new Bundle();
                     bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_PAYLOADS.equals(action)) {
-                    Log.d(TAG, "SERVICE_PAYLOADS");
-                    Bundle bundle = new Bundle();
                     ArrayList<String> payloadData = new ArrayList<>(mNotifications.size());
                     for (JSONObject payload: mNotifications.values()) {
                         payloadData.add(payload.toString());
@@ -125,14 +130,10 @@
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_REMOVED.equals(action)) {
-                    Log.d(TAG, "SERVICE_REMOVED");
-                    Bundle bundle = new Bundle();
                     bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_REMOVED_REASON.equals(action)) {
-                    Log.d(TAG, "SERVICE_REMOVED_REASON");
-                    Bundle bundle = new Bundle();
                     ArrayList<String> payloadData = new ArrayList<>(mRemovedReason.size());
                     for (JSONObject payload: mRemovedReason.values()) {
                         payloadData.add(payload.toString());
@@ -141,7 +142,6 @@
                     setResultExtras(bundle);
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_CLEAR_ONE.equals(action)) {
-                    Log.d(TAG, "SERVICE_CLEAR_ONE");
                     String tag = intent.getStringExtra(EXTRA_TAG);
                     String key = mNotificationKeys.get(tag);
                     if (key != null) {
@@ -150,11 +150,30 @@
                         Log.w(TAG, "Notification does not exist: " + tag);
                     }
                 } else if (SERVICE_CLEAR_ALL.equals(action)) {
-                    Log.d(TAG, "SERVICE_CLEAR_ALL");
                     MockListener.this.cancelAllNotifications();
                 } else if (SERVICE_RESET.equals(action)) {
-                    Log.d(TAG, "SERVICE_RESET");
                     resetData();
+                } else if (SERVICE_SNOOZE.equals(action)) {
+                    MockListener.this.requestUnbind();
+                } else if (SERVICE_HINTS.equals(action)) {
+                    MockListener.this.requestListenerHints(intent.getIntExtra(EXTRA_CODE, 0));
+                } else if (SERVICE_PROBE_HINTS.equals(action)) {
+                    bundle.putInt(EXTRA_INT, MockListener.this.getCurrentListenerHints());
+                    setResultExtras(bundle);
+                    setResultCode(Activity.RESULT_OK);
+                } else if (SERVICE_SNOOZE_ONE.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    MockListener.this.snoozeNotification(key);
+                } else if (SERVICE_UNSNOOZE_ONE.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    MockListener.this.unsnoozeNotification(key);
+                } else if (SERVICE_SNOOZE_UNTIL.equals(action)) {
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    MockListener.this.snoozeNotification(key,
+                            intent.getLongExtra(EXTRA_LONG, (long) 0));
                 } else {
                     Log.w(TAG, "unknown action");
                     setResultCode(Activity.RESULT_CANCELED);
@@ -172,6 +191,12 @@
         filter.addAction(SERVICE_CLEAR_ONE);
         filter.addAction(SERVICE_CLEAR_ALL);
         filter.addAction(SERVICE_RESET);
+        filter.addAction(SERVICE_SNOOZE);
+        filter.addAction(SERVICE_HINTS);
+        filter.addAction(SERVICE_PROBE_HINTS);
+        filter.addAction(SERVICE_SNOOZE_ONE);
+        filter.addAction(SERVICE_UNSNOOZE_ONE);
+        filter.addAction(SERVICE_SNOOZE_UNTIL);
         registerReceiver(mReceiver, filter);
     }
 
@@ -202,6 +227,7 @@
         mNotifications.clear();
         mRemoved.clear();
         mOrder.clear();
+        mRemovedReason.clear();
     }
 
     @Override
@@ -307,10 +333,41 @@
         requestStringListResult(context, SERVICE_REMOVED_REASON, catcher);
     }
 
+    public static void probeListenerHints(Context context, IntegerResultCatcher catcher) {
+        requestIntegerResult(context, SERVICE_PROBE_HINTS, catcher);
+    }
+
+    public static void setHints(Context context, int hints) {
+        Intent broadcast = new Intent(SERVICE_HINTS);
+        broadcast.putExtra(EXTRA_CODE, hints);
+        context.sendBroadcast(broadcast);
+    }
+
+    public static void snooze(Context context) {
+        sendCommand(context, SERVICE_SNOOZE, null, 0);
+    }
+
     public static void clearOne(Context context, String tag, int code) {
         sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
     }
 
+    public static void snoozeOne(Context context, String tag) {
+        sendCommand(context, SERVICE_SNOOZE_ONE, tag, 0);
+    }
+
+    public static void unsnoozeOne(Context context, String tag) {
+        sendCommand(context, SERVICE_UNSNOOZE_ONE, tag, 0);
+    }
+
+    public static void snoozeOneUntil(Context context, String tag, long until) {
+        Intent broadcast = new Intent(SERVICE_SNOOZE_UNTIL);
+        if (tag != null) {
+            broadcast.putExtra(EXTRA_TAG, tag);
+            broadcast.putExtra(EXTRA_LONG, until);
+        }
+        context.sendBroadcast(broadcast);
+    }
+
     public static void clearAll(Context context) {
         sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 6bf623a..fe23fe0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -79,6 +79,13 @@
         tests.add(new DismissOneTest());
         tests.add(new DismissOneWithReasonTest());
         tests.add(new DismissAllTest());
+        tests.add(new SnoozeNotificationTest());
+        tests.add(new UnsnoozeNotificationTest());
+        tests.add(new SnoozeNotificationForTimeTest());
+        tests.add(new EnableHintsTest());
+        tests.add(new SnoozeTest());
+        tests.add(new UnsnoozeTest());
+        tests.add(new EnableHintsTest());
         tests.add(new IsDisabledTest());
         tests.add(new ServiceStoppedTest());
         tests.add(new NotificationNotReceivedTest());
@@ -350,7 +357,6 @@
                                     } catch (JSONException e) {
                                         e.printStackTrace();
                                     }
-
                                 }
                                 status = pass ? PASS : FAIL;
                                 next();
@@ -427,6 +433,12 @@
         }
 
         @Override
+        void setUp(){
+            MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+            delay();
+        }
+
+        @Override
         void test() {
             String listeners = Secure.getString(getContentResolver(),
                     ENABLED_NOTIFICATION_LISTENERS);
@@ -461,7 +473,11 @@
                                 logFail();
                                 status = FAIL;
                             } else {
-                                status = PASS;
+                                if (mNm.getEffectsSuppressor() == null) {
+                                    status = PASS;
+                                } else {
+                                    status = FAIL;
+                                }
                             }
                             next();
                         }
@@ -515,4 +531,362 @@
             delay();
         }
     }
+
+    private class SnoozeTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_snooze);
+
+        }
+
+        @Override
+        void setUp() {
+            status = READY;
+            MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.snooze(mContext);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerStatus(mContext,
+                        new MockListener.StatusCatcher() {
+                            @Override
+                            public void accept(int result) {
+                                if (result == Activity.RESULT_OK) {
+                                    logFail();
+                                    status = FAIL;
+                                } else {
+                                    if (mNm.getEffectsSuppressor() == null) {
+                                        status = PASS;
+                                    } else {
+                                        logFail();
+                                        status = RETEST;
+                                        delay();
+                                    }
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            delay();
+        }
+    }
+
+    private class UnsnoozeTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_unsnooze);
+
+        }
+
+        @Override
+        void setUp() {
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.requestRebind(MockListener.COMPONENT_NAME);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerStatus(mContext,
+                        new MockListener.StatusCatcher() {
+                            @Override
+                            public void accept(int result) {
+                                if (result == Activity.RESULT_OK) {
+                                    status = PASS;
+                                    next();
+                                } else {
+                                    logFail();
+                                    status = RETEST;
+                                    delay();
+                                }
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            delay();
+        }
+    }
+
+    private class EnableHintsTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_hints);
+
+        }
+
+        @Override
+        void setUp() {
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerHints(mContext,
+                        new MockListener.IntegerResultCatcher() {
+                            @Override
+                            public void accept(int result) {
+                                if (result == MockListener.HINT_HOST_DISABLE_CALL_EFFECTS) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();  // in case the catcher never returns
+        }
+
+        @Override
+        void tearDown() {
+            delay();
+        }
+    }
+
+    private class SnoozeNotificationTest extends InteractiveTestCase {
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_snooze_one);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            if (status == READY) {
+                MockListener.snoozeOne(mContext, mTag1);
+                status = RETEST;
+            } else {
+                MockListener.probeListenerRemoved(mContext,
+                        new MockListener.StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)
+                                        && !result.contains(mTag2)
+                                        && !result.contains(mTag3)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancel(mTag1, mId1);
+            mNm.cancel(mTag2, mId2);
+            mNm.cancel(mTag2, mId3);
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class UnsnoozeNotificationTest extends InteractiveTestCase {
+        final static int READY_TO_SNOOZE = 0;
+        final static int SNOOZED = 1;
+        final static int READY_TO_UNSNOOZE = 2;
+        final static int UNSNOOZED = 3;
+        int state = -1;
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_unsnooze_one);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            delay();
+        }
+
+        @Override
+        void test() {
+            status = RETEST;
+
+            if (state == READY_TO_SNOOZE) {
+                MockListener.snoozeOne(mContext, mTag1);
+                state = SNOOZED;
+            } else if (state == SNOOZED) {
+                MockListener.probeListenerRemovedWithReason(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (String payloadData : result) {
+                                    JSONObject payload = null;
+                                    try {
+                                        payload = new JSONObject(payloadData);
+                                        pass &= checkEquals(mTag1,
+                                                payload.getString(JSON_TAG),
+                                                "data dismissal test: notification tag (%s, %s)");
+                                        pass &= checkEquals(MockListener.REASON_SNOOZED,
+                                                payload.getInt(JSON_TAG),
+                                                "data dismissal test: reason (%d, %d)");
+                                    } catch (JSONException e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                                if (!pass) {
+                                    logFail();
+                                    status = FAIL;
+                                    next();
+                                    return;
+                                } else {
+                                    state = READY_TO_UNSNOOZE;
+                                }
+                            }
+                        });
+            } else if (state == READY_TO_UNSNOOZE) {
+                MockListener.unsnoozeOne(mContext, mTag1);
+                state = UNSNOOZED;
+            } else {
+                MockListener.probeListenerPosted(mContext,
+                        new MockListener.StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
+
+    private class SnoozeNotificationForTimeTest extends InteractiveTestCase {
+        final static int READY_TO_SNOOZE = 0;
+        final static int SNOOZED = 1;
+        final static int READY_TO_CHECK_FOR_UNSNOOZE = 2;
+        int state = -1;
+        long snoozeTime = 3000;
+        @Override
+        View inflate(ViewGroup parent) {
+            return createAutoItem(parent, R.string.nls_snooze_one_time);
+        }
+
+        @Override
+        void setUp() {
+            sendNotifications();
+            status = READY;
+            state = READY_TO_SNOOZE;
+            delay();
+        }
+
+        @Override
+        void test() {
+            status = RETEST;
+            if (state == READY_TO_SNOOZE) {
+                MockListener.snoozeOneUntil(mContext, mTag1,
+                        System.currentTimeMillis() + snoozeTime);
+                state = SNOOZED;
+            } else if (state == SNOOZED){
+                MockListener.probeListenerRemovedWithReason(mContext,
+                        new StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result == null || result.size() == 0) {
+                                    status = FAIL;
+                                    return;
+                                }
+                                boolean pass = true;
+                                for (String payloadData : result) {
+                                    JSONObject payload = null;
+                                    try {
+                                        payload = new JSONObject(payloadData);
+                                        pass &= checkEquals(mTag1,
+                                                payload.getString(JSON_TAG),
+                                                "data dismissal test: notification tag (%s, %s)");
+                                        pass &= checkEquals(MockListener.REASON_SNOOZED,
+                                                payload.getInt(JSON_TAG),
+                                                "data dismissal test: reason (%d, %d)");
+                                    } catch (JSONException e) {
+                                        e.printStackTrace();
+                                    }
+                                }
+                                if (!pass) {
+                                    logFail();
+                                    status = FAIL;
+                                    next();
+                                    return;
+                                } else {
+                                    state = READY_TO_CHECK_FOR_UNSNOOZE;
+                                }
+                            }
+                        });
+            } else {
+                MockListener.probeListenerPosted(mContext,
+                        new MockListener.StringListResultCatcher() {
+                            @Override
+                            public void accept(List<String> result) {
+                                if (result != null && result.size() != 0
+                                        && result.contains(mTag1)) {
+                                    status = PASS;
+                                } else {
+                                    logFail();
+                                    status = FAIL;
+                                }
+                                next();
+                            }
+                        });
+            }
+            delay();
+        }
+
+        @Override
+        void tearDown() {
+            mNm.cancelAll();
+            MockListener.resetListenerData(mContext);
+            delay();
+        }
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java
new file mode 100644
index 0000000..5be1792
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.usb;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+/**
+ * Utilities for the USB CTS verifier tests.
+ */
+public class Util {
+    private static final String LOG_TAG = Util.class.getSimpleName();
+
+    /**
+     * Run a {@link Invokable} and expect a {@link Throwable}.
+     *
+     * @param r             The {@link Invokable} to run
+     * @param expectedClass The expected {@link Throwable} type
+     */
+    public static void runAndAssertException(@NonNull Invokable r,
+            @NonNull Class<? extends Throwable> expectedClass) throws Throwable {
+        try {
+            r.run();
+        } catch (Throwable e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                Log.e(LOG_TAG, "Expected: " + expectedClass.getName() + ", got: "
+                        + e.getClass().getName());
+                throw e;
+            }
+        }
+
+        throw new AssertionError("No throwable thrown");
+    }
+
+
+    /**
+     * A {@link Runnable} that can throw an {@link Throwable}.
+     */
+    public interface Invokable {
+        /**
+         * Run the code that might cause an exception.
+         */
+        void run() throws Throwable;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java
new file mode 100644
index 0000000..f5e0fef
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.usb.accessory;
+
+import android.app.Activity;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Utility to receive callbacks when an USB accessory is attached.
+ */
+public class AccessoryAttachmentHandler extends Activity {
+    private static final ArrayList<AccessoryAttachmentObserver> sObservers = new ArrayList<>();
+
+    /**
+     * Register an observer to be called when an USB accessory connects.
+     *
+     * @param observer The observer that should be called when an USB accessory connects.
+     */
+    static void addObserver(@NonNull AccessoryAttachmentObserver observer) {
+        synchronized (sObservers) {
+            sObservers.add(observer);
+        }
+    }
+
+    /**
+     * Remove an observer that was added in {@link #addObserver}.
+     *
+     * @param observer The observer to remove
+     */
+    static void removeObserver(@NonNull AccessoryAttachmentObserver observer) {
+        synchronized (sObservers) {
+            sObservers.remove(observer);
+        }
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        UsbAccessory accessory = getIntent().getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+        synchronized (sObservers) {
+            ArrayList<AccessoryAttachmentObserver> observers =
+                    (ArrayList<AccessoryAttachmentObserver>) sObservers.clone();
+
+            for (AccessoryAttachmentObserver observer : observers) {
+                observer.onAttached(accessory);
+            }
+        }
+
+        finish();
+    }
+
+    /**
+     * Callback when an accessory is attached
+     */
+    interface AccessoryAttachmentObserver {
+        void onAttached(UsbAccessory accessory);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
index 2e11f98..8ac009b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,460 +16,231 @@
 
 package com.android.cts.verifier.usb.accessory;
 
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.TestResult;
+import static com.android.cts.verifier.usb.Util.runAndAssertException;
 
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.Toast;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
 
 /**
- * Test for USB accessories. The test activity interacts with a cts-usb-accessory program that
- * acts as an accessory by exchanging a series of messages.
+ * Guide the user to run test for the USB accessory interface.
  */
-public class UsbAccessoryTestActivity extends PassFailButtons.Activity {
+public class UsbAccessoryTestActivity extends PassFailButtons.Activity implements
+        AccessoryAttachmentHandler.AccessoryAttachmentObserver {
+    private static final String LOG_TAG = UsbAccessoryTestActivity.class.getSimpleName();
+    private static final int MAX_BUFFER_SIZE = 16384;
 
-    private static final String TAG = "UsbAccessoryTest";
-
-    private static final int FILE_DESCRIPTOR_PROBLEM_DIALOG_ID = 1;
-    private static final int STATE_START = 0;
-    private static final int STATE_CONNECTED = 1;
-    private static final int STATE_WAITING_FOR_RECONNECT = 2;
-    private static final int STATE_RECONNECTED = 3;
-    private static final int STATE_PASSED = 4;
-
-    private static final String ACTION_USB_PERMISSION =
-            "com.android.cts.verifier.usb.USB_PERMISSION";
-
-    private ArrayAdapter<String> mReceivedMessagesAdapter;
-    private ArrayAdapter<String> mSentMessagesAdapter;
-    private MessageHandler mHandler;
-    private Handler mMainHandler;
-
-    private UsbManager mUsbManager;
-    private PendingIntent mPermissionIntent;
-    private boolean mPermissionRequestPending;
-    private UsbReceiver mUsbReceiver;
-    private int mState = STATE_START;
-    private AlertDialog mDisconnectDialog;
-    private AlertDialog mConnectDialog;
-
-    private UsbAccessory mAccessory;
-    private ParcelFileDescriptor mFileDescriptor;
-
-    private Runnable mTimeoutRunnable = new Runnable() {
-        @Override
-        public void run() {
-            Toast.makeText(UsbAccessoryTestActivity.this,
-                    R.string.usb_reconnect_timeout, Toast.LENGTH_SHORT).show();
-            TestResult.setFailedResult(UsbAccessoryTestActivity.this, getTestId(), getTestDetails());
-        }
-    };
+    private TextView mStatus;
+    private ProgressBar mProgress;
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Log.d(TAG, "onCreate");
-        // Test success only works properly if launched from TestListActivity
-        String action = getIntent().getAction();
-        if (ACTION_USB_PERMISSION.equals(action)
-                || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
-            finish();
-            return;
-        }
 
         setContentView(R.layout.usb_main);
-        setInfoResources(R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
-        setPassFailButtonClickListeners();
+        setInfoResources(
+                R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
 
-        // Don't allow a test pass until the accessory and the Android device exchange messages...
+        mStatus = (TextView) findViewById(R.id.status);
+        mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+        mStatus.setText(R.string.usb_accessory_test_step1);
         getPassButton().setEnabled(false);
 
-        if (!hasUsbAccessorySupport()) {
-            showNoUsbAccessoryDialog();
-        }
-
-        mReceivedMessagesAdapter = new ArrayAdapter<String>(this, R.layout.usb_message_row);
-        mSentMessagesAdapter = new ArrayAdapter<String>(this, R.layout.usb_message_row);
-        mHandler = new MessageHandler();
-
-        mUsbManager = (UsbManager) getSystemService(USB_SERVICE);
-        mPermissionIntent = PendingIntent.getBroadcast(this, 0,
-                new Intent(ACTION_USB_PERMISSION), 0);
-
-        mUsbReceiver = new UsbReceiver();
-        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
-        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
-        registerReceiver(mUsbReceiver, filter);
-
-        setupListViews();
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(this)
-            .setIcon(android.R.drawable.ic_dialog_alert)
-            .setTitle(R.string.usb_reconnect_title)
-            .setCancelable(false)
-            .setNegativeButton(R.string.usb_reconnect_abort,
-                    new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    setTestResultAndFinish(false);
-                }
-            });
-        mConnectDialog = builder
-            .setMessage(R.string.usb_connect_message)
-            .create();
-        mDisconnectDialog = builder
-            .setMessage(R.string.usb_disconnect_message)
-            .create();
-
-        mMainHandler = new Handler(Looper.getMainLooper());
-    }
-
-    private boolean hasUsbAccessorySupport() {
-        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
-    }
-
-    private void showNoUsbAccessoryDialog() {
-        new AlertDialog.Builder(this)
-            .setIcon(android.R.drawable.ic_dialog_alert)
-            .setTitle(R.string.usb_not_available_title)
-            .setMessage(R.string.usb_not_available_message)
-            .setCancelable(false)
-            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    finish();
-                }
-            })
-            .show();
-    }
-
-    private void setupListViews() {
-        ListView sentMessages = (ListView) findViewById(R.id.usb_sent_messages);
-        ListView receivedMessages = (ListView) findViewById(R.id.usb_received_messages);
-
-        View emptySentView = findViewById(R.id.usb_empty_sent_messages);
-        View emptyReceivedView = findViewById(R.id.usb_empty_received_messages);
-        sentMessages.setEmptyView(emptySentView);
-        receivedMessages.setEmptyView(emptyReceivedView);
-
-        receivedMessages.setAdapter(mReceivedMessagesAdapter);
-        sentMessages.setAdapter(mSentMessagesAdapter);
-    }
-
-    class UsbReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.d(TAG, "Received broadcast: intent=" + intent);
-            if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
-                if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
-                    UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-                    openAccessory(accessory);
-                } else {
-                    Log.i(TAG, "Permission denied...");
-                }
-                mPermissionRequestPending = false;
-            } else if (mState == STATE_WAITING_FOR_RECONNECT &&
-                    UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(intent.getAction())) {
-                UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-                if (accessory.equals(mAccessory)) {
-                    closeAccessory();
-                    mDisconnectDialog.dismiss();
-                    mConnectDialog.show();
-                    mMainHandler.postDelayed(mTimeoutRunnable, 10000 /* 10 seconds */);
-                }
-            }
-        }
-    }
-
-    public void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        Log.d(TAG, "onNewIntent: state=" + mState + ", intent=" + intent);
-        if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
-            UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-            openAccessory(accessory);
-        }
-    }
-
-    private void openAccessory(UsbAccessory accessory) {
-        mAccessory = accessory;
-        mFileDescriptor = mUsbManager.openAccessory(accessory);
-        if (mState == STATE_START) {
-            setState(STATE_CONNECTED);
-        } else if (mState == STATE_WAITING_FOR_RECONNECT) {
-            setState(STATE_RECONNECTED);
-            mConnectDialog.dismiss();
-        }
-        if (mFileDescriptor != null) {
-            FileDescriptor fileDescriptor = mFileDescriptor.getFileDescriptor();
-            FileInputStream inputStream = new FileInputStream(fileDescriptor);
-            FileOutputStream outputStream = new FileOutputStream(fileDescriptor);
-            new MessageThread(inputStream, outputStream, mHandler).start();
-        } else {
-            showDialog(FILE_DESCRIPTOR_PROBLEM_DIALOG_ID);
-        }
-    }
-
-    private void closeAccessory() {
-        mAccessory = null;
-        if (mFileDescriptor != null) {
-            try {
-                mFileDescriptor.close();
-            } catch (IOException e) {
-                Log.e(TAG, "Exception while closing file descriptor", e);
-            } finally {
-                mFileDescriptor = null;
-            }
-        }
-    }
-
-    static class MessageThread extends Thread {
-
-        private final InputStream mInputStream;
-
-        private final OutputStream mOutputStream;
-
-        private final MessageHandler mHandler;
-
-        private int mNextMessageNumber = 0;
-
-        MessageThread(InputStream inputStream, OutputStream outputStream, MessageHandler handler) {
-            this.mInputStream = inputStream;
-            this.mOutputStream = outputStream;
-            this.mHandler = handler;
-        }
-
-        @Override
-        public void run() {
-            mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_STARTING);
-
-            try {
-                // Wait a bit or else the messages can appear to quick and be confusing...
-                Thread.sleep(2000);
-                sendMessage();
-
-                // Wait for response and send message acks...
-                int numRead = 0;
-                byte[] buffer = new byte[16384];
-                boolean done = false;
-                while (numRead >= 0 && !done) {
-                    numRead = mInputStream.read(buffer);
-                    if (numRead > 0) {
-                        done = handleReceivedMessage(buffer, numRead);
-                    }
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "Exception while reading from input stream", e);
-                mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_EXCEPTION);
-            } catch (InterruptedException e) {
-                Log.e(TAG, "Exception while reading from input stream", e);
-                mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_EXCEPTION);
-            }
-            mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_ENDING);
-        }
-
-        private boolean handleReceivedMessage(byte[] buffer, int numRead) throws IOException {
-            // TODO: Check the contents of the message?
-            String text = new String(buffer, 0, numRead).trim();
-            mHandler.sendReceivedMessage(text);
-
-            // Send back a response..
-            if (mNextMessageNumber <= 10) {
-                sendMessage();
-                return false;
-            } else {
-                mHandler.sendEmptyMessage(MessageHandler.STAGE_PASSED);
-                return true;
-            }
-        }
-
-        private void sendMessage() throws IOException {
-            String text = "Message from Android device #" + mNextMessageNumber++;
-            mOutputStream.write(text.getBytes());
-            mHandler.sendSentMessage(text);
-        }
-    }
-
-    class MessageHandler extends Handler {
-
-        static final int RECEIVED_MESSAGE = 1;
-
-        static final int SENT_MESSAGE = 2;
-
-        static final int MESSAGE_THREAD_STARTING = 3;
-
-        static final int MESSAGE_THREAD_EXCEPTION = 4;
-
-        static final int MESSAGE_THREAD_ENDING = 5;
-
-        static final int STAGE_PASSED = 6;
-
-        @Override
-        public void handleMessage(Message msg) {
-            super.handleMessage(msg);
-            switch (msg.what) {
-                case RECEIVED_MESSAGE:
-                    mReceivedMessagesAdapter.add((String) msg.obj);
-                    break;
-
-                case SENT_MESSAGE:
-                    mSentMessagesAdapter.add((String) msg.obj);
-                    break;
-
-                case MESSAGE_THREAD_STARTING:
-                    showToast(R.string.usb_message_thread_started);
-                    break;
-
-                case MESSAGE_THREAD_EXCEPTION:
-                    showToast(R.string.usb_message_thread_exception);
-                    break;
-
-                case MESSAGE_THREAD_ENDING:
-                    showToast(R.string.usb_message_thread_ended);
-                    break;
-
-                case STAGE_PASSED:
-                    if (mState == STATE_RECONNECTED) {
-                        showToast(R.string.usb_test_passed);
-                        getPassButton().setEnabled(true);
-                        setState(STATE_PASSED);
-                        mMainHandler.removeCallbacks(mTimeoutRunnable);
-                    } else if (mState == STATE_CONNECTED) {
-                        mDisconnectDialog.show();
-                        setState(STATE_WAITING_FOR_RECONNECT);
-                    }
-                    break;
-
-                default:
-                    throw new IllegalArgumentException("Bad message type: " + msg.what);
-            }
-        }
-
-        private void showToast(int messageId) {
-            Toast.makeText(UsbAccessoryTestActivity.this, messageId, Toast.LENGTH_SHORT).show();
-        }
-
-        void sendReceivedMessage(String text) {
-            Message message = Message.obtain(this, RECEIVED_MESSAGE);
-            message.obj = text;
-            sendMessage(message);
-        }
-
-        void sendSentMessage(String text) {
-            Message message = Message.obtain(this, SENT_MESSAGE);
-            message.obj = text;
-            sendMessage(message);
-        }
+        AccessoryAttachmentHandler.addObserver(this);
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
-        Log.d(TAG, "onResume: state=" + stateToString(mState));
-        if (mState == STATE_START) {
-            UsbAccessory[] accessories = mUsbManager.getAccessoryList();
-            UsbAccessory accessory = accessories != null && accessories.length > 0
-                    ? accessories[0]
-                    : null;
-            if (accessory != null) {
-                if (mUsbManager.hasPermission(accessory)) {
-                    openAccessory(accessory);
-                } else {
-                    if (!mPermissionRequestPending) {
-                        mUsbManager.requestPermission(accessory, mPermissionIntent);
-                        mPermissionRequestPending = true;
-                    }
+    public void onAttached(UsbAccessory accessory) {
+        mStatus.setText(R.string.usb_accessory_test_step2);
+        mProgress.setVisibility(View.VISIBLE);
+
+        AccessoryAttachmentHandler.removeObserver(this);
+
+        UsbManager usbManager = getSystemService(UsbManager.class);
+
+        try {
+            assertEquals("Android device running CTS verifier", accessory.getDescription());
+            assertEquals("Android", accessory.getManufacturer());
+            assertEquals("Android device", accessory.getModel());
+            assertEquals("0", accessory.getSerial());
+            assertEquals("https://source.android.com/compatibility/cts/verifier.html",
+                    accessory.getUri());
+            assertEquals("1", accessory.getVersion());
+
+            assertTrue(Arrays.asList(usbManager.getAccessoryList()).contains(accessory));
+
+            runAndAssertException(() -> usbManager.openAccessory(null), NullPointerException.class);
+
+            ParcelFileDescriptor accessoryFd = usbManager.openAccessory(accessory);
+            assertNotNull(accessoryFd);
+
+            try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(accessoryFd)) {
+                try (OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
+                        accessoryFd)) {
+                    byte[] origBuffer32 = new byte[32];
+                    (new Random()).nextBytes(origBuffer32);
+
+                    byte[] origBufferMax = new byte[MAX_BUFFER_SIZE];
+                    (new Random()).nextBytes(origBufferMax);
+
+                    byte[] bufferMax = new byte[MAX_BUFFER_SIZE];
+                    byte[] buffer32 = new byte[32];
+                    byte[] buffer16 = new byte[16];
+
+                    // Echo a transfer
+                    nextTest(is, os, "echo 32 bytes");
+
+                    os.write(origBuffer32);
+
+                    int numRead = is.read(buffer32);
+                    assertEquals(32, numRead);
+                    assertArrayEquals(origBuffer32, buffer32);
+
+                    // Receive less data than available
+                    nextTest(is, os, "echo 32 bytes");
+
+                    os.write(origBuffer32);
+
+                    numRead = is.read(buffer16);
+                    assertEquals(16, numRead);
+                    assertArrayEquals(Arrays.copyOf(origBuffer32, 16), buffer16);
+
+                    // If a transfer was only partially read, the rest of the transfer is lost.
+                    // We cannot read the second part, hence proceed to the next test.
+
+                    // Send two transfers in a row
+                    nextTest(is, os, "echo two 16 byte transfers as one");
+
+                    os.write(Arrays.copyOf(origBuffer32, 16));
+                    os.write(Arrays.copyOfRange(origBuffer32, 16, 32));
+
+                    numRead = is.read(buffer32);
+                    assertEquals(32, numRead);
+                    assertArrayEquals(origBuffer32, buffer32);
+
+                    // Receive two transfers in a row into a buffer that is bigger than the transfer
+                    nextTest(is, os, "echo 32 bytes as two 16 byte transfers");
+
+                    os.write(origBuffer32);
+
+                    // Even though the buffer would hold 32 bytes the input stream will read the
+                    // transfers individually
+                    numRead = is.read(buffer32);
+                    assertEquals(16, numRead);
+                    assertArrayEquals(Arrays.copyOf(origBuffer32, 16),
+                            Arrays.copyOf(buffer32, 16));
+
+                    numRead = is.read(buffer32);
+                    assertEquals(16, numRead);
+                    assertArrayEquals(Arrays.copyOfRange(origBuffer32, 16, 32),
+                            Arrays.copyOf(buffer32, 16));
+
+                    // Echo a buffer with the maximum size
+                    nextTest(is, os, "echo max bytes");
+
+                    os.write(origBufferMax);
+
+                    numRead = is.read(bufferMax);
+                    assertEquals(MAX_BUFFER_SIZE, numRead);
+                    assertArrayEquals(origBufferMax, bufferMax);
+
+                    // Echo a buffer with twice the maximum size
+                    nextTest(is, os, "echo max*2 bytes");
+
+                    byte[] oversizeBuffer = new byte[MAX_BUFFER_SIZE * 2];
+                    System.arraycopy(origBufferMax, 0, oversizeBuffer, 0, MAX_BUFFER_SIZE);
+                    System.arraycopy(origBufferMax, 0, oversizeBuffer, MAX_BUFFER_SIZE,
+                            MAX_BUFFER_SIZE);
+                    os.write(oversizeBuffer);
+
+                    // The other side can not write more than the maximum size at once, hence we get
+                    // two transfers in return
+                    numRead = is.read(bufferMax);
+                    assertEquals(MAX_BUFFER_SIZE, numRead);
+                    assertArrayEquals(origBufferMax, bufferMax);
+
+                    numRead = is.read(bufferMax);
+                    assertEquals(MAX_BUFFER_SIZE, numRead);
+                    assertArrayEquals(origBufferMax, bufferMax);
+
+                    nextTest(is, os, "done");
                 }
             }
+
+            accessoryFd.close();
+
+            setTestResultAndFinish(true);
+        } catch (Throwable t) {
+            fail(null, t);
         }
     }
 
-    @Override
-    protected void onPause() {
-        super.onPause();
-        Log.d(TAG, "onPause: state=" + stateToString(mState));
-    }
+    /**
+     * Signal to the companion device that we want to switch to the next test.
+     *
+     * @param is       The input stream from the companion device
+     * @param os       The output stream from the companion device
+     * @param testName The name of the new test
+     */
+    private boolean nextTest(@NonNull InputStream is, @NonNull OutputStream os,
+            @NonNull String testName) throws IOException {
+        Log.i(LOG_TAG, "Init new test " + testName);
 
-    @Override
-    protected void onStop() {
-        super.onStop();
-        Log.d(TAG, "onStop: state=" + stateToString(mState));
-        closeAccessory();
-    }
+        ByteBuffer nameBuffer = Charset.forName("UTF-8").encode(CharBuffer.wrap(testName));
+        byte[] sizeBuffer = {(byte) nameBuffer.limit()};
 
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        setContentView(R.layout.usb_main);
-        setupListViews();
-    }
+        os.write(sizeBuffer);
+        os.write(Arrays.copyOf(nameBuffer.array(), nameBuffer.limit()));
 
-    @Override
-    public Dialog onCreateDialog(int id, Bundle args) {
-        switch (id) {
-            case FILE_DESCRIPTOR_PROBLEM_DIALOG_ID:
-                return new AlertDialog.Builder(this)
-                    .setIcon(android.R.drawable.ic_dialog_alert)
-                    .setTitle(R.string.usb_accessory_test)
-                    .setMessage(R.string.usb_file_descriptor_error)
-                    .create();
-
-            default:
-                return super.onCreateDialog(id, args);
+        int ret = is.read();
+        if (ret <= 0) {
+            Log.i(LOG_TAG, "Last test failed " + ret);
+            return false;
         }
+
+        os.write(0);
+
+        Log.i(LOG_TAG, "Running " + testName);
+
+        return true;
     }
 
     @Override
     protected void onDestroy() {
+        AccessoryAttachmentHandler.removeObserver(this);
+
         super.onDestroy();
-        Log.d(TAG, "onDestroy");
-        if (mUsbReceiver != null) {
-            unregisterReceiver(mUsbReceiver);
-        }
     }
 
-    private void setState(int newState) {
-        Log.d(TAG, "Transition: " + stateToString(mState) + " -> " + stateToString(newState));
-        mState = newState;
+    /**
+     * Indicate that the test failed.
+     */
+    private void fail(@Nullable String s, @Nullable Throwable e) {
+        Log.e(LOG_TAG, s, e);
+        setTestResultAndFinish(false);
     }
-
-
-    private static String stateToString(int state) {
-        switch (state) {
-            case STATE_START: return "START";
-            case STATE_CONNECTED: return "CONNECTED";
-            case STATE_WAITING_FOR_RECONNECT: return "WAITING_FOR_RECONNECT";
-            case STATE_RECONNECTED: return "RECONNECTED";
-            case STATE_PASSED: return "PASSED";
-            default: return "UNKNOWN";
-        }
-    }
-
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
index d762096..6a1a16a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.verifier.usb.device;
 
+import static com.android.cts.verifier.usb.Util.runAndAssertException;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -45,6 +47,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.cts.verifier.PassFailButtons;
@@ -72,37 +77,35 @@
     private static final int MAX_BUFFER_SIZE = 16384;
 
     private UsbManager mUsbManager;
-    private final BroadcastReceiver mUsbDeviceConnectionReceiver;
+    private BroadcastReceiver mUsbDeviceConnectionReceiver;
     private Thread mTestThread;
+    private TextView mStatus;
+    private ProgressBar mProgress;
 
     private static long now() {
         return System.nanoTime() / 1000000;
     }
 
-    /**
-     * Run a {@link Invokable} and expect a {@link Throwable} of a certain type.
-     *
-     * @param r             The {@link Invokable} to run
-     * @param expectedClass The expected {@link Throwable} type
-     */
-    private static void assertException(@NonNull Invokable r,
-            @NonNull Class<? extends Throwable> expectedClass) throws Throwable {
-        try {
-            r.run();
-        } catch (Throwable e) {
-            if (e.getClass().isAssignableFrom(expectedClass)) {
-                return;
-            } else {
-                Log.e(LOG_TAG, "Expected: " + expectedClass.getName() + ", got: "
-                        + e.getClass().getName());
-                throw e;
-            }
-        }
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
 
-        throw new AssertionError("No throwable thrown");
-    }
+        setContentView(R.layout.usb_main);
+        setInfoResources(R.string.usb_device_test, R.string.usb_device_test_info, -1);
 
-    public UsbDeviceTestActivity() {
+        mStatus = (TextView) findViewById(R.id.status);
+        mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+
+        mUsbManager = getSystemService(UsbManager.class);
+
+        getPassButton().setEnabled(false);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USB_PERMISSION);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+        mStatus.setText(R.string.usb_device_test_step1);
+
         mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -111,6 +114,10 @@
 
                     switch (intent.getAction()) {
                         case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+                            if (!AoapInterface.isDeviceInAoapMode(device)) {
+                                mStatus.setText(R.string.usb_device_test_step2);
+                            }
+
                             mUsbManager.requestPermission(device,
                                     PendingIntent.getBroadcast(UsbDeviceTestActivity.this, 0,
                                             new Intent(ACTION_USB_PERMISSION), 0));
@@ -121,6 +128,8 @@
 
                             if (granted) {
                                 if (!AoapInterface.isDeviceInAoapMode(device)) {
+                                    mStatus.setText(R.string.usb_device_test_step3);
+
                                     UsbDeviceConnection connection = mUsbManager.openDevice(device);
                                     try {
                                         makeThisDeviceAnAccessory(connection);
@@ -128,6 +137,13 @@
                                         connection.close();
                                     }
                                 } else {
+                                    mStatus.setText(R.string.usb_device_test_step4);
+                                    mProgress.setIndeterminate(true);
+                                    mProgress.setVisibility(View.VISIBLE);
+
+                                    unregisterReceiver(mUsbDeviceConnectionReceiver);
+                                    mUsbDeviceConnectionReceiver = null;
+
                                     // Do not run test on main thread
                                     mTestThread = new Thread() {
                                         @Override
@@ -147,22 +163,6 @@
                 }
             }
         };
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.usb_main);
-        setInfoResources(R.string.usb_device_test, R.string.usb_device_test_info, -1);
-
-        mUsbManager = getSystemService(UsbManager.class);
-
-        getPassButton().setEnabled(false);
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_USB_PERMISSION);
-        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
 
         registerReceiver(mUsbDeviceConnectionReceiver, filter);
     }
@@ -390,22 +390,22 @@
      * @throws Throwable
      */
     private void ctrlTransferTests(@NonNull UsbDeviceConnection connection) throws Throwable {
-        assertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 1, 0),
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 1, 0),
                 IllegalArgumentException.class);
 
-        assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], -1, 0),
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], -1, 0),
                 IllegalArgumentException.class);
 
-        assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 2, 0),
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 2, 0),
                 IllegalArgumentException.class);
 
-        assertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 0, 1, 0),
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 0, 1, 0),
                 IllegalArgumentException.class);
 
-        assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 0, -1, 0),
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 0, -1, 0),
                 IllegalArgumentException.class);
 
-        assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 1, 1, 0),
+        runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 1, 1, 0),
                 IllegalArgumentException.class);
     }
 
@@ -729,7 +729,7 @@
      */
     private void timeoutWhileWaitingForUsbRequest(@NonNull UsbDeviceConnection connection)
             throws Throwable {
-        assertException(() -> connection.requestWait(-1), IllegalArgumentException.class);
+        runAndAssertException(() -> connection.requestWait(-1), IllegalArgumentException.class);
 
         long startTime = now();
         UsbRequest req = connection.requestWait(100);
@@ -981,18 +981,19 @@
 
         // Illegal arguments
         final UsbRequest req1 = new UsbRequest();
-        assertException(() -> req1.initialize(null, in), NullPointerException.class);
-        assertException(() -> req1.initialize(connection, null), NullPointerException.class);
+        runAndAssertException(() -> req1.initialize(null, in), NullPointerException.class);
+        runAndAssertException(() -> req1.initialize(connection, null), NullPointerException.class);
         boolean isInited = req1.initialize(connection, in);
         assertTrue(isInited);
-        assertException(() -> req1.queue(null, 0), NullPointerException.class);
-        assertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
+        runAndAssertException(() -> req1.queue(null, 0), NullPointerException.class);
+        runAndAssertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
                 IllegalArgumentException.class);
         req1.close();
 
         // Cannot queue closed request
-        assertException(() -> req1.queue(ByteBuffer.allocate(1), 1), NullPointerException.class);
-        assertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
+        runAndAssertException(() -> req1.queue(ByteBuffer.allocate(1), 1),
+                NullPointerException.class);
+        runAndAssertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
                 NullPointerException.class);
     }
 
@@ -1096,19 +1097,20 @@
 
         // Illegal arguments
         final UsbRequest req1 = new UsbRequest();
-        assertException(() -> req1.initialize(null, in), NullPointerException.class);
-        assertException(() -> req1.initialize(connection, null), NullPointerException.class);
+        runAndAssertException(() -> req1.initialize(null, in), NullPointerException.class);
+        runAndAssertException(() -> req1.initialize(connection, null), NullPointerException.class);
         boolean isInited = req1.initialize(connection, in);
         assertTrue(isInited);
-        assertException(() -> req1.enqueue(ByteBuffer.allocate(16384 + 1).asReadOnlyBuffer()),
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(16384 + 1).asReadOnlyBuffer()),
                 IllegalArgumentException.class);
-        assertException(() -> req1.enqueue(ByteBuffer.allocate(1).asReadOnlyBuffer()),
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(1).asReadOnlyBuffer()),
                 IllegalArgumentException.class);
         req1.close();
 
         // Cannot queue closed request
-        assertException(() -> req1.enqueue(ByteBuffer.allocate(1)), IllegalStateException.class);
-        assertException(() -> req1.enqueue(ByteBuffer.allocateDirect(1)),
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(1)),
+                IllegalStateException.class);
+        runAndAssertException(() -> req1.enqueue(ByteBuffer.allocateDirect(1)),
                 IllegalStateException.class);
 
         // Initialize
@@ -1629,27 +1631,27 @@
         receiveOversizedBulkTransfer(connection, in);
 
         // Illegal arguments
-        assertException(() -> connection.bulkTransfer(out, new byte[1], 2, 0),
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], 2, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(in, new byte[1], 2, 0),
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], 2, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(out, new byte[2], 1, 2, 0),
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[2], 1, 2, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(in, new byte[2], 1, 2, 0),
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[2], 1, 2, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(out, new byte[1], -1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], -1, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(in, new byte[1], -1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], -1, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(out, new byte[1], 1, -1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], 1, -1, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(in, new byte[1], 1, -1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], 1, -1, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(out, new byte[1], -1, -1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], -1, -1, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(in, new byte[1], -1, -1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], -1, -1, 0),
                 IllegalArgumentException.class);
-        assertException(() -> connection.bulkTransfer(null, new byte[1], 1, 0),
+        runAndAssertException(() -> connection.bulkTransfer(null, new byte[1], 1, 0),
                 NullPointerException.class);
 
         // Transmissions that do nothing
@@ -1768,9 +1770,11 @@
         released = connection.releaseInterface(iface);
         assertTrue(released);
 
-        assertException(() -> connection.claimInterface(null, true), NullPointerException.class);
-        assertException(() -> connection.claimInterface(null, false), NullPointerException.class);
-        assertException(() -> connection.releaseInterface(null), NullPointerException.class);
+        runAndAssertException(() -> connection.claimInterface(null, true),
+                NullPointerException.class);
+        runAndAssertException(() -> connection.claimInterface(null, false),
+                NullPointerException.class);
+        runAndAssertException(() -> connection.releaseInterface(null), NullPointerException.class);
     }
 
     /**
@@ -1803,7 +1807,7 @@
         boolean released = connection.releaseInterface(iface);
         assertTrue(released);
 
-        assertException(() -> connection.setConfiguration(null), NullPointerException.class);
+        runAndAssertException(() -> connection.setConfiguration(null), NullPointerException.class);
     }
 
     /**
@@ -1832,7 +1836,7 @@
         released = connection.releaseInterface(iface);
         assertTrue(released);
 
-        assertException(() -> connection.setInterface(null), NullPointerException.class);
+        runAndAssertException(() -> connection.setInterface(null), NullPointerException.class);
     }
 
     /**
@@ -2010,14 +2014,10 @@
 
     @Override
     protected void onDestroy() {
-        unregisterReceiver(mUsbDeviceConnectionReceiver);
-        super.onDestroy();
-    }
+        if (mUsbDeviceConnectionReceiver != null) {
+            unregisterReceiver(mUsbDeviceConnectionReceiver);
+        }
 
-    /**
-     * A {@link Runnable} that can throw an {@link Throwable}.
-     */
-    private interface Invokable {
-        void run() throws Throwable;
+        super.onDestroy();
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastActivity.java
new file mode 100644
index 0000000..8250594
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastActivity.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.cts.verifier.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.voicemail.VoicemailBroadcastReceiver.ReceivedListener;
+
+/**
+ * This test ask the tester to set the CTS verifier as the default dialer and leave a voicemail. The
+ * test will pass if the verifier is able to receive a broadcast for the incoming voicemail. This
+ * depends on telephony to send the broadcast to the default dialer when receiving a Message Waiting
+ * Indicator SMS.
+ */
+public class VoicemailBroadcastActivity extends PassFailButtons.Activity {
+
+    private String mDefaultDialer;
+
+    private ImageView mSetDefaultDialerImage;
+    private ImageView mLeaveVoicemailImage;
+    private TextView mLeaveVoicemailText;
+    private ImageView mRestoreDefaultDialerImage;
+    private TextView mRestoreDefaultDialerText;
+
+    private Button mSetDefaultDialerButton;
+    private Button mRestoreDefaultDialerButton;
+
+    private BroadcastReceiver mDefaultDialerChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String packageName =
+                    intent.getStringExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
+            if (!getPassButton().isEnabled()) {
+                updateSetDefaultDialerState(packageName);
+            } else {
+                if (packageName.equals(getPackageName())) {
+                    mRestoreDefaultDialerImage
+                            .setImageDrawable(getDrawable(R.drawable.fs_indeterminate));
+                } else {
+                    mRestoreDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_good));
+                }
+            }
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        View view = getLayoutInflater().inflate(R.layout.voicemail_broadcast, null);
+        setContentView(view);
+        setInfoResources(R.string.voicemail_broadcast_test,
+                R.string.voicemail_broadcast_instructions, -1);
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+
+        mSetDefaultDialerImage = (ImageView) findViewById(R.id.set_default_dialer_image);
+        mLeaveVoicemailImage = (ImageView) findViewById(R.id.leave_voicemail_image);
+        mLeaveVoicemailText = (TextView) findViewById(R.id.leave_voicemail_text);
+        mRestoreDefaultDialerImage = (ImageView) findViewById(R.id.restore_default_dialer_image);
+        mRestoreDefaultDialerText = (TextView) findViewById(R.id.restore_default_dialer_text);
+
+        mSetDefaultDialerButton = (Button) view.findViewById(R.id.set_default_dialer);
+        mRestoreDefaultDialerButton = (Button) view.findViewById(R.id.restore_default_dialer);
+
+        final TelecomManager telecomManager = getSystemService(TelecomManager.class);
+        mDefaultDialer = telecomManager.getDefaultDialerPackage();
+        updateSetDefaultDialerState(mDefaultDialer);
+        if (mDefaultDialer.equals(getPackageName())) {
+            // The CTS verifier is already the default dialer (probably due to the tester exiting
+            // mid test. We don't know what the default dialer should be so just prompt the tester
+            // to restore it through settings, and remove the button.
+            mRestoreDefaultDialerText
+                    .setText(R.string.voicemail_restore_default_dialer_no_default_description);
+            mRestoreDefaultDialerButton.setVisibility(View.GONE);
+        }
+
+        mSetDefaultDialerButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (telecomManager.getDefaultDialerPackage().equals(getPackageName())) {
+                    Toast.makeText(VoicemailBroadcastActivity.this,
+                            R.string.voicemail_default_dialer_already_set, Toast.LENGTH_SHORT)
+                            .show();
+                    return;
+                }
+
+                final Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
+                intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME,
+                        getPackageName());
+                startActivityForResult(intent, 0);
+            }
+        });
+
+        mRestoreDefaultDialerButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (telecomManager.getDefaultDialerPackage().equals(mDefaultDialer)) {
+                    Toast.makeText(VoicemailBroadcastActivity.this,
+                            R.string.voicemail_default_dialer_already_restored, Toast.LENGTH_SHORT)
+                            .show();
+                    return;
+                }
+
+                final Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
+                intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME,
+                        mDefaultDialer);
+                startActivityForResult(intent, 0);
+            }
+        });
+
+        VoicemailBroadcastReceiver.setListener(new ReceivedListener() {
+            @Override
+            public void onReceived() {
+
+                Toast.makeText(VoicemailBroadcastActivity.this,
+                        R.string.voicemail_broadcast_received, Toast.LENGTH_SHORT).show();
+                mLeaveVoicemailImage.setImageDrawable(getDrawable(R.drawable.fs_good));
+                mLeaveVoicemailText.setText(R.string.voicemail_broadcast_received);
+                getPassButton().setEnabled(true);
+            }
+        });
+
+        registerReceiver(mDefaultDialerChangedReceiver,
+                new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED));
+    }
+
+    @Override
+    protected void onDestroy() {
+        VoicemailBroadcastReceiver.setListener(null);
+        unregisterReceiver(mDefaultDialerChangedReceiver);
+        super.onDestroy();
+    }
+
+    private void updateSetDefaultDialerState(String packageName) {
+        if (packageName.equals(getPackageName())) {
+            mSetDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_good));
+        } else {
+            mSetDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_indeterminate));
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastReceiver.java
new file mode 100644
index 0000000..1785576
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receiver used by {@link VoicemailBroadcastActivity} to receive {@link
+ * android.telephony.TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION}, which must be a manifest
+ * receiver.
+ */
+public class VoicemailBroadcastReceiver extends BroadcastReceiver {
+
+    public interface ReceivedListener {
+
+        void onReceived();
+    }
+
+    private static ReceivedListener sListener;
+
+    public static void setListener(ReceivedListener listener) {
+        sListener = listener;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (sListener != null) {
+            sListener.onReceived();
+        }
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/res/layout/main.xml b/apps/CtsVerifierUSBCompanion/res/layout/main.xml
index e3d45b2..6eb2cec 100644
--- a/apps/CtsVerifierUSBCompanion/res/layout/main.xml
+++ b/apps/CtsVerifierUSBCompanion/res/layout/main.xml
@@ -47,6 +47,13 @@
             android:text="@string/device_test_button" />
 
     <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/deviceTest"
+        android:id="@+id/accessoryTest"
+        android:text="@string/accessory_test_button" />
+
+    <Button
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@id/status"
diff --git a/apps/CtsVerifierUSBCompanion/res/values/strings.xml b/apps/CtsVerifierUSBCompanion/res/values/strings.xml
index 99b2d24..56bc71f 100644
--- a/apps/CtsVerifierUSBCompanion/res/values/strings.xml
+++ b/apps/CtsVerifierUSBCompanion/res/values/strings.xml
@@ -18,6 +18,7 @@
 <resources>
     <string name="status_label">Status:</string>
     <string name="device_test_button">Start device test companion</string>
+    <string name="accessory_test_button">Start accessory test companion</string>
     <string name="abort_button">Abort</string>
     <string name="app_name">Cts Verifier USB Companion</string>
     <string name="status_no_test">No test run</string>
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
new file mode 100644
index 0000000..dc5cc3d
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifierusbcompanion;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.support.annotation.NonNull;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * Companion code for com.android.cts.verifier.usb.device.UsbAccessoryTestActivity
+ */
+class AccessoryTestCompanion extends TestCompanion {
+    private static final int MAX_BUFFER_SIZE = 16384;
+
+    private static final String ACTION_USB_PERMISSION =
+            "com.android.cts.verifierusbcompanion.USB_PERMISSION";
+
+    private UsbManager mUsbManager;
+    private BroadcastReceiver mUsbDeviceConnectionReceiver;
+    private UsbDevice mDevice;
+
+    AccessoryTestCompanion(@NonNull Context context, @NonNull TestObserver observer) {
+        super(context, observer);
+    }
+
+    /**
+     * @throws Throwable
+     */
+    @Override
+    protected void runTest() throws Throwable {
+        updateStatus("Waiting for device under test to connect");
+
+        mUsbManager = getContext().getSystemService(UsbManager.class);
+
+        mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                synchronized (AccessoryTestCompanion.this) {
+                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+                    switch (intent.getAction()) {
+                        case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+                            if (mUsbManager.hasPermission(device)) {
+                                onDeviceAccessPermitted(device);
+                            } else {
+                                mUsbManager.requestPermission(device,
+                                        PendingIntent.getBroadcast(getContext(), 0,
+                                                new Intent(ACTION_USB_PERMISSION), 0));
+                            }
+                            break;
+                        case ACTION_USB_PERMISSION:
+                            boolean granted = intent.getBooleanExtra(
+                                    UsbManager.EXTRA_PERMISSION_GRANTED, false);
+
+                            if (granted) {
+                                onDeviceAccessPermitted(device);
+                            } else {
+                                fail("Permission to connect to " + device.getProductName()
+                                        + " not granted");
+                            }
+                            break;
+                    }
+                }
+            }
+        };
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_USB_PERMISSION);
+        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+        getContext().registerReceiver(mUsbDeviceConnectionReceiver, filter);
+
+        synchronized (this) {
+            while (mDevice == null) {
+                wait();
+            }
+        }
+
+        UsbInterface iface = null;
+        for (int i = 0; i < mDevice.getConfigurationCount(); i++) {
+            if (mDevice.getInterface(i).getName().equals("Android Accessory Interface")) {
+                iface = mDevice.getInterface(i);
+                break;
+            }
+        }
+
+        UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+
+        UsbDeviceConnection connection = mUsbManager.openDevice(mDevice);
+
+        try {
+            String testName;
+            do {
+                testName = nextTest(connection, in, out, true);
+
+                updateStatus("Running test \"" + testName + "\"");
+
+                switch (testName) {
+                    case "echo 32 bytes": {
+                        byte[] buffer = new byte[32];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+                    }
+                    break;
+
+                    case "echo two 16 byte transfers as one": {
+                        byte[] buffer = new byte[48];
+
+                        // We receive the individual transfers even if we wait for more data
+                        int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+                        assertEquals(16, numTransferred);
+                        numTransferred = connection.bulkTransfer(in, buffer, 16, 32, 0);
+                        assertEquals(16, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+                    }
+                    break;
+
+                    case "echo 32 bytes as two 16 byte transfers": {
+                        byte[] buffer = new byte[32];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+                        assertEquals(32, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, 16, 0);
+                        assertEquals(16, numTransferred);
+                        numTransferred = connection.bulkTransfer(out, buffer, 16, 16, 0);
+                        assertEquals(16, numTransferred);
+                    }
+                    break;
+
+                    case "echo max bytes": {
+                        byte[] buffer = new byte[MAX_BUFFER_SIZE];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+                                0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+                    }
+                    break;
+
+                    case "echo max*2 bytes": {
+                        byte[] buffer = new byte[MAX_BUFFER_SIZE * 2];
+
+                        int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+                                0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        // Oversized transfers get split into two
+                        numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+                                MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+                        numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE,
+                                MAX_BUFFER_SIZE, 0);
+                        assertEquals(MAX_BUFFER_SIZE, numTransferred);
+                    }
+                    break;
+
+                    default:
+                        break;
+                }
+            } while (!testName.equals("done"));
+        } finally {
+            connection.close();
+        }
+    }
+
+    /**
+     * If access to a device was permitted either make the device an accessory if it already is,
+     * start the test.
+     *
+     * @param device The device access was permitted to
+     */
+    private void onDeviceAccessPermitted(@NonNull UsbDevice device) {
+        if (!AoapInterface.isDeviceInAoapMode(device)) {
+            UsbDeviceConnection connection = mUsbManager.openDevice(device);
+            try {
+                makeThisDeviceAnAccessory(connection);
+            } finally {
+                connection.close();
+            }
+        } else {
+            getContext().unregisterReceiver(mUsbDeviceConnectionReceiver);
+            mUsbDeviceConnectionReceiver = null;
+
+            synchronized (AccessoryTestCompanion.this) {
+                mDevice = device;
+
+                AccessoryTestCompanion.this.notifyAll();
+            }
+        }
+    }
+
+    @NonNull private String nextTest(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, boolean isSuccess) {
+        byte[] sizeBuffer = new byte[1];
+
+        updateStatus("Waiting for next test");
+
+        int numTransferred = connection.bulkTransfer(in, sizeBuffer, 1, 0);
+        assertEquals(1, numTransferred);
+
+        int nameSize = sizeBuffer[0];
+
+        byte[] nameBuffer = new byte[nameSize];
+        numTransferred = connection.bulkTransfer(in, nameBuffer, nameSize, 0);
+        assertEquals(nameSize, numTransferred);
+
+        numTransferred = connection.bulkTransfer(out, new byte[]{(byte) (isSuccess ? 1 : 0)}, 1, 0);
+        assertEquals(1, numTransferred);
+
+        numTransferred = connection.bulkTransfer(in, new byte[1], 1, 0);
+        assertEquals(1, numTransferred);
+
+        String name = Charset.forName("UTF-8").decode(ByteBuffer.wrap(nameBuffer)).toString();
+
+        updateStatus("Next test is " + name);
+
+        return name;
+    }
+
+    /**
+     * Search an {@link UsbInterface} for an {@link UsbEndpoint endpoint} of a certain direction.
+     *
+     * @param iface     The interface to search
+     * @param direction The direction the endpoint is for.
+     *
+     * @return The first endpoint found or {@link null}.
+     */
+    @NonNull private UsbEndpoint getEndpoint(@NonNull UsbInterface iface, int direction) {
+        for (int i = 0; i < iface.getEndpointCount(); i++) {
+            UsbEndpoint ep = iface.getEndpoint(i);
+            if (ep.getDirection() == direction) {
+                return ep;
+            }
+        }
+
+        throw new IllegalStateException("Could not find " + direction + " endpoint in "
+                + iface.getName());
+    }
+
+    /**
+     * Converts the device under test into an Android accessory. Accessories are USB hosts that are
+     * detected on the device side via {@link UsbManager#getAccessoryList()}.
+     *
+     * @param connection The connection to the USB device
+     */
+    private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
+                "Android");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
+                "Android device");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
+                "Android device running CTS verifier");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
+                "https://source.android.com/compatibility/cts/verifier.html");
+        AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
+        AoapInterface.sendAoapStart(connection);
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java
new file mode 100644
index 0000000..6f8d1a1
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifierusbcompanion;
+
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+class AoapInterface {
+    /**
+     * Use Google Vendor ID when in accessory mode
+     */
+    private static final int USB_ACCESSORY_VENDOR_ID = 0x18D1;
+
+    /**
+     * Product ID to use when in accessory mode
+     */
+    private static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00;
+
+    /**
+     * Product ID to use when in accessory mode and adb is enabled
+     */
+    private static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01;
+
+    /**
+     * Indexes for strings sent by the host via ACCESSORY_SEND_STRING
+     */
+    public static final int ACCESSORY_STRING_MANUFACTURER = 0;
+    public static final int ACCESSORY_STRING_MODEL = 1;
+    public static final int ACCESSORY_STRING_DESCRIPTION = 2;
+    public static final int ACCESSORY_STRING_VERSION = 3;
+    public static final int ACCESSORY_STRING_URI = 4;
+    public static final int ACCESSORY_STRING_SERIAL = 5;
+
+    /**
+     * Control request for retrieving device's protocol version
+     *
+     * requestType:    USB_DIR_IN | USB_TYPE_VENDOR
+     * request:        ACCESSORY_GET_PROTOCOL
+     * value:          0
+     * index:          0
+     * data            version number (16 bits little endian)
+     * 1 for original accessory support
+     * 2 adds HID and device to host audio support
+     */
+    private static final int ACCESSORY_GET_PROTOCOL = 51;
+
+    /**
+     * Control request for host to send a string to the device
+     *
+     * requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     * request:        ACCESSORY_SEND_STRING
+     * value:          0
+     * index:          string ID
+     * data            zero terminated UTF8 string
+     *
+     * The device can later retrieve these strings via the
+     * ACCESSORY_GET_STRING_* ioctls
+     */
+    private static final int ACCESSORY_SEND_STRING = 52;
+
+    /**
+     * Control request for starting device in accessory mode.
+     * The host sends this after setting all its strings to the device.
+     *
+     * requestType:    USB_DIR_OUT | USB_TYPE_VENDOR
+     * request:        ACCESSORY_START
+     * value:          0
+     * index:          0
+     * data            none
+     */
+    private static final int ACCESSORY_START = 53;
+
+    private static final String TAG = AoapInterface.class.getSimpleName();
+
+    public static int getProtocol(UsbDeviceConnection conn) {
+        byte[] buffer = new byte[2];
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
+        if (len != 2) {
+            return -1;
+        }
+        return (buffer[1] << 8) | buffer[0];
+    }
+
+    public static void sendString(UsbDeviceConnection conn, int index, String string) {
+        byte[] buffer = (string + "\0").getBytes();
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_SEND_STRING, 0, index,
+                buffer, buffer.length, 10000);
+        if (len != buffer.length) {
+            throw new RuntimeException("Failed to send string " + index + ": \"" + string + "\"");
+        } else {
+            Log.i(TAG, "Sent string " + index + ": \"" + string + "\"");
+        }
+    }
+
+    public static void sendAoapStart(UsbDeviceConnection conn) {
+        int len = conn.controlTransfer(
+                UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+                AoapInterface.ACCESSORY_START, 0, 0, null, 0, 10000);
+        if (len < 0) {
+            throw new RuntimeException("control transfer for accessory start failed:" + len);
+        }
+    }
+
+    public static boolean isDeviceInAoapMode(UsbDevice device) {
+        final int vid = device.getVendorId();
+        final int pid = device.getProductId();
+        return vid == USB_ACCESSORY_VENDOR_ID
+                && (pid == USB_ACCESSORY_PRODUCT_ID
+                || pid == USB_ACCESSORY_ADB_PRODUCT_ID);
+    }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
index 4b1bb39..a87f9ce 100644
--- a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
@@ -16,10 +16,10 @@
 
 package com.android.cts.verifierusbcompanion;
 
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.Button;
@@ -31,6 +31,7 @@
 public class Main extends Activity implements TestCompanion.TestObserver {
     private TextView mStatusMessage;
     private Button mDeviceTestButton;
+    private Button mAccessoryTestButton;
     private Button mAbortButton;
     private TestCompanion mCurrentTest;
 
@@ -44,11 +45,13 @@
 
         mStatusMessage = (TextView) findViewById(R.id.status_message);
         mDeviceTestButton = (Button) findViewById(R.id.deviceTest);
+        mAccessoryTestButton = (Button) findViewById(R.id.accessoryTest);
         mAbortButton = (Button) findViewById(R.id.abort);
 
         mStatusMessage.setText(getString(R.string.status_no_test));
 
         mDeviceTestButton.setOnClickListener(view -> runDeviceTest());
+        mAccessoryTestButton.setOnClickListener(view -> runAccessoryTest());
         mAbortButton.setOnClickListener(view -> abortCurrentTest());
     }
 
@@ -60,19 +63,27 @@
     }
 
     /**
-     * Abort the {@link DeviceTestCompanion}
+     * Run the {@link DeviceTestCompanion}
      */
     private void runDeviceTest() {
         runTestCompanion(new DeviceTestCompanion(this, this));
     }
 
     /**
+     * Run the {@link AccessoryTestCompanion}
+     */
+    private void runAccessoryTest() {
+        runTestCompanion(new AccessoryTestCompanion(this, this));
+    }
+
+    /**
      * Run a test.
      * @param test The test to run
      */
     private void runTestCompanion(@NonNull TestCompanion test) {
         mAbortButton.setVisibility(View.VISIBLE);
         mDeviceTestButton.setVisibility(View.GONE);
+        mAccessoryTestButton.setVisibility(View.GONE);
 
         mCurrentTest = test;
         test.start();
@@ -84,6 +95,7 @@
     private void resetUI() {
         mAbortButton.setVisibility(View.GONE);
         mDeviceTestButton.setVisibility(View.VISIBLE);
+        mAccessoryTestButton.setVisibility(View.VISIBLE);
     }
 
     @Override
diff --git a/apps/cts-usb-accessory/Android.mk b/apps/cts-usb-accessory/Android.mk
deleted file mode 100644
index 7699b1a..0000000
--- a/apps/cts-usb-accessory/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Copyright (C) 2011 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.
-#
-
-# Build for Linux (desktop) host
-ifeq ($(HOST_OS),linux)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := cts-usb-accessory.c
-
-LOCAL_MODULE := cts-usb-accessory
-
-LOCAL_C_INCLUDES += \
-	bionic/libc/kernel/uapi \
-	bionic/libc/kernel/android/uapi \
-	bionic/libc/kernel/uapi/asm-x86 \
-
-LOCAL_STATIC_LIBRARIES := libusbhost libcutils
-LOCAL_LDLIBS += -lpthread
-LOCAL_CFLAGS := -g -O0
-LOCAL_CXX_STL := none
-
-include $(BUILD_HOST_EXECUTABLE)
-
-endif
diff --git a/apps/cts-usb-accessory/cts-usb-accessory.c b/apps/cts-usb-accessory/cts-usb-accessory.c
deleted file mode 100644
index 0fbfce7..0000000
--- a/apps/cts-usb-accessory/cts-usb-accessory.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <pthread.h>
-#include <time.h>
-
-#include <usbhost/usbhost.h>
-#include <linux/usb/f_accessory.h>
-
-#define USB_CONTROL_READ_TIMEOUT_MS 200
-
-static struct usb_device *sDevice = NULL;
-static int sAfterUnplug = 0;
-static char* sDeviceSerial = NULL;
-
-static void* message_thread(void* arg) {
-    int *endpoints = (int *)arg;
-    int ret = 0;
-    int num = 0;
-    char message[50];
-
-    while (sDevice && ret >= 0) {
-        char buffer[16384];
-        ret = usb_device_bulk_transfer(sDevice, endpoints[0], buffer, sizeof(buffer), 1000);
-        if (ret < 0 && errno == ETIMEDOUT) {
-            ret = 0;
-        }
-        if (ret > 0) {
-            printf("[RECV] ");
-            fwrite(buffer, 1, ret, stdout);
-            printf("\n");
-
-            // Respond by sending a message back
-            sprintf(message, "Message from Android accessory #%d", num++);
-            printf("[SENT] %s\n", message);
-            fflush(stdout);
-            usb_device_bulk_transfer(sDevice, endpoints[1], message, strlen(message), 1000);
-        }
-    }
-
-    return NULL;
-}
-
-static void milli_sleep(int millis) {
-    struct timespec tm;
-
-    tm.tv_sec = 0;
-    tm.tv_nsec = millis * 1000000;
-    nanosleep(&tm, NULL);
-}
-
-static int send_string(struct usb_device *device, int index, const char* string) {
-    int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
-            ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 1000);
-
-    // some devices can't handle back-to-back requests, so delay a bit
-    milli_sleep(10);
-    return ret;
-}
-
-static int usb_device_added(const char *devname, void* client_data) {
-    struct usb_descriptor_header* desc;
-    struct usb_descriptor_iter iter;
-    uint16_t vendorId, productId;
-    int ret;
-    pthread_t th;
-
-    struct usb_device *device = usb_device_open(devname);
-    if (!device) {
-        fprintf(stderr, "usb_device_open failed\n");
-        return 0;
-    }
-
-    char* serial = usb_device_get_serial(device, USB_CONTROL_READ_TIMEOUT_MS);
-    if (sDeviceSerial && (!serial || strcmp(sDeviceSerial, serial))) {
-        free(serial);
-        return 0;
-    }
-    free(serial);
-
-    vendorId = usb_device_get_vendor_id(device);
-    productId = usb_device_get_product_id(device);
-
-    if (!sDevice && (vendorId == 0x18D1 && (productId == 0x2D00 || productId == 0x2D01))) {
-        struct usb_descriptor_header* desc;
-        struct usb_descriptor_iter iter;
-        struct usb_interface_descriptor *intf = NULL;
-        struct usb_endpoint_descriptor *ep1 = NULL;
-        struct usb_endpoint_descriptor *ep2 = NULL;
-
-        printf("Found Android device in accessory mode (%x:%x)...\n",
-               vendorId, productId);
-        sDevice = device;
-        sDeviceSerial = usb_device_get_serial(sDevice, USB_CONTROL_READ_TIMEOUT_MS);
-
-        usb_descriptor_iter_init(device, &iter);
-        while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
-            if (desc->bDescriptorType == USB_DT_INTERFACE) {
-                intf = (struct usb_interface_descriptor *)desc;
-            } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
-                if (ep1)
-                    ep2 = (struct usb_endpoint_descriptor *)desc;
-                else
-                    ep1 = (struct usb_endpoint_descriptor *)desc;
-            }
-        }
-
-        if (!intf) {
-            fprintf(stderr, "Interface not found\n");
-            exit(1);
-        }
-        if (!ep1 || !ep2) {
-            fprintf(stderr, "Endpoints not found\n");
-            exit(1);
-        }
-
-        if (usb_device_claim_interface(device, intf->bInterfaceNumber)) {
-            fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno);
-            exit(1);
-        }
-
-        int endpoints[2];
-        if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
-            endpoints[0] = ep1->bEndpointAddress;
-            endpoints[1] = ep2->bEndpointAddress;
-        } else {
-            endpoints[0] = ep2->bEndpointAddress;
-            endpoints[1] = ep1->bEndpointAddress;
-        }
-        pthread_create(&th, NULL, message_thread, (void *)endpoints);
-    } else {
-        printf("Found possible Android device (%x:%x) "
-                "- attempting to switch to accessory mode...\n", vendorId, productId);
-
-        uint16_t protocol = 0;
-        ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
-                ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 1000);
-        if (ret == 2) {
-            printf("Device supports protocol version %d\n", protocol);
-        } else {
-            fprintf(stderr, "Failed to read protocol version\n");
-        }
-
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_VERSION, "1.0");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_URI,
-                        "http://source.android.com/compatibility/cts-intro.html");
-        ret = (ret < 0) ? ret :
-                send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
-
-        ret = (ret < 0) ? ret :
-                usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
-                        ACCESSORY_START, 0, 0, 0, 0, 1000);
-        if (ret < 0) {
-            fprintf(stderr, "Failed to start accessory mode\n");
-        }
-        return 0;
-    }
-
-    if (device != sDevice)
-        usb_device_close(device);
-
-    return 0;
-}
-
-static int usb_device_removed(const char *devname, void* client_data) {
-    if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) {
-        usb_device_close(sDevice);
-        sDevice = NULL;
-        if (sAfterUnplug) {
-            // exit when we are disconnected the second time
-            free(sDeviceSerial);
-            return 1;
-        } else {
-            sAfterUnplug = 1;
-        }
-    }
-    return 0;
-}
-
-
-int main(int argc, char* argv[]) {
-    printf("CTS USB Accessory Tester\n");
-
-    struct usb_host_context* context = usb_host_init();
-    if (!context) {
-        fprintf(stderr, "usb_host_init failed");
-        return 1;
-    }
-
-    // this will never return so it is safe to pass thiz directly
-    usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL);
-    return 0;
-}
diff --git a/build/compatibility_test_suite.mk b/build/compatibility_test_suite.mk
index f109185..7cdd220 100644
--- a/build/compatibility_test_suite.mk
+++ b/build/compatibility_test_suite.mk
@@ -46,7 +46,7 @@
 LOCAL_GENERATED_SOURCES := $(suite_info_java)
 
 # Add the base libraries
-LOCAL_JAVA_LIBRARIES += tradefed-prebuilt hosttestlib compatibility-host-util
+LOCAL_JAVA_LIBRARIES += tradefed hosttestlib compatibility-host-util
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/common/host-side/manifest-generator/tests/Android.mk b/common/host-side/manifest-generator/tests/Android.mk
index 2eb5d2f..1601fc8 100644
--- a/common/host-side/manifest-generator/tests/Android.mk
+++ b/common/host-side/manifest-generator/tests/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-manifest-generator junit
+LOCAL_JAVA_LIBRARIES := compatibility-manifest-generator junit-host
 
 LOCAL_MODULE := compatibility-manifest-generator-tests
 
diff --git a/tools/cts-tradefed/res/config/cts-unit-tests.xml b/common/host-side/tradefed/res/config/cts-unit-tests.xml
similarity index 94%
rename from tools/cts-tradefed/res/config/cts-unit-tests.xml
rename to common/host-side/tradefed/res/config/cts-unit-tests.xml
index f621a7b..4bec93e 100644
--- a/tools/cts-tradefed/res/config/cts-unit-tests.xml
+++ b/common/host-side/tradefed/res/config/cts-unit-tests.xml
@@ -21,6 +21,7 @@
         <option name="class" value="com.android.compatibility.common.util.HostUnitTests" />
         <option name="class" value="com.android.compatibility.common.util.UnitTests" />
         <option name="class" value="com.android.compatibility.tradefed.CtsTradefedTest" />
+        <option name="class" value="com.drawelements.deqp.runner.DeqpTestRunnerTest" />
     </test>
     <logger class="com.android.tradefed.log.FileLogger" />
 
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index 0887d07..c1087a1 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -208,6 +208,19 @@
     }
 
     /**
+     * @return a {@link File} representing the test file in the test modules directory.
+     * @throws FileNotFoundException if the test file cannot be found
+     */
+    public File getTestFile(String filename) throws FileNotFoundException {
+        File testFile = new File(getTestsDir(), filename);
+        if (!testFile.exists()) {
+            throw new FileNotFoundException(String.format(
+                    "Compatibility test file %s does not exist", filename));
+        }
+        return testFile;
+    }
+
+    /**
      * @return a {@link File} in the resultDir for logging invocation failures
      */
     public File getInvocationFailureFile() throws FileNotFoundException {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index 01a35b4..dc6a321 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -216,7 +216,7 @@
         helpBuilder.append("Options:\n");
         helpBuilder.append("  --session <session_id>: The session used to create a subplan.\n");
         helpBuilder.append("  --name/-n <subplan_name>: The name of the new subplan.\n");
-        helpBuilder.append("  --result-type/-r <status>: Which results to include in the");
+        helpBuilder.append("  --result-type <status>: Which results to include in the");
         helpBuilder.append(" subplan. One of passed, failed, not_executed. Repeatable.\n");
 
         return helpBuilder.toString();
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 7310f56..3c0b21b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -404,7 +404,6 @@
 
         // NOTE: Everything after this line only applies to the master ResultReporter.
 
-
         synchronized(this) {
             // The master ResultReporter tracks the progress of all invocations across
             // shard ResultReporters. Writing results should not proceed until all
@@ -456,16 +455,16 @@
 
         long startTime = mResult.getStartTime();
         try {
+            // Zip the full test results directory.
+            copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
+            copyFormattingFiles(mResultDir);
+
             File resultFile = ResultHandler.writeResults(mBuildHelper.getSuiteName(),
                     mBuildHelper.getSuiteVersion(), mBuildHelper.getSuitePlan(),
                     mBuildHelper.getSuiteBuild(), mResult, mResultDir, startTime,
                     elapsedTime + startTime, mReferenceUrl, getLogUrl(),
                     mBuildHelper.getCommandLineArgs());
             info("Test Result: %s", resultFile.getCanonicalPath());
-
-            // Zip the full test results directory.
-            copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
-            copyFormattingFiles(mResultDir);
             File zippedResults = zipResults(mResultDir);
             info("Full Result: %s", zippedResults.getCanonicalPath());
 
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
index 7d6d77f..4b4c0be 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
@@ -57,12 +57,20 @@
     public static final String FAILED = "failed";
     public static final String NOT_EXECUTED = "not_executed";
     // static mapping of result types to TestStatuses
-    private static final Map<String, TestStatus> mStatusMap;
+    private static final Map<String, TestStatus> STATUS_MAP;
     static {
         Map<String, TestStatus> statusMap = new HashMap<String, TestStatus>();
         statusMap.put(PASSED, TestStatus.PASS);
         statusMap.put(FAILED, TestStatus.FAIL);
-        mStatusMap = Collections.unmodifiableMap(statusMap);
+        STATUS_MAP = Collections.unmodifiableMap(statusMap);
+    }
+
+    // TODO(aaronholden): remove this temporary workaround for b/33090757
+    private static final Set<String> MULTITEST_MODULES;
+    static {
+        Set<String> multiTestModuleSet = new HashSet<String>();
+        multiTestModuleSet.add("CtsDeqpTestCases");
+        MULTITEST_MODULES = Collections.unmodifiableSet(multiTestModuleSet);
     }
 
     @Option (name = "name", shortName = 'n', description = "the name of the subplan to create",
@@ -73,7 +81,7 @@
             importance=Importance.IF_UNSET)
     private Integer mSessionId = null;
 
-    @Option (name = "result-type", shortName = 'r',
+    @Option (name = "result-type",
             description = "the result type to include. One of passed, failed, not_executed."
             + " Option may be repeated",
             importance=Importance.IF_UNSET)
@@ -219,9 +227,21 @@
                 }
             } else {
                 // module should not run, exclude entire module
-                TestFilter moduleExclude =
-                        new TestFilter(module.getAbi(), module.getName(), null /*test*/);
-                subPlan.addExcludeFilter(moduleExclude.toString());
+                // TODO(aaronholden): remove this special case from SubPlanCreator, and filter
+                // individual tests only when the module should run. Tracked by b/33211104
+                if (MULTITEST_MODULES.contains(module.getName())) {
+                    for (ICaseResult caseResult : module.getResults()) {
+                        for (ITestResult testResult : caseResult.getResults()) {
+                            TestFilter testExclude = new TestFilter(module.getAbi(),
+                                    module.getName(), testResult.getFullName());
+                            subPlan.addExcludeFilter(testExclude.toString());
+                        }
+                    }
+                } else {
+                    TestFilter moduleExclude =
+                            new TestFilter(module.getAbi(), module.getName(), null /*test*/);
+                    subPlan.addExcludeFilter(moduleExclude.toString());
+                }
             }
         }
         return subPlan;
@@ -280,7 +300,7 @@
         for (String resultType : mResultTypes) {
             // no test status exists for not-executed tests
             if (resultType != NOT_EXECUTED) {
-                statusesToRun.add(mStatusMap.get(resultType));
+                statusesToRun.add(STATUS_MAP.get(resultType));
             }
         }
         return statusesToRun;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
index 5c0658f..06cca2f 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
@@ -221,6 +221,11 @@
         IModuleListener moduleListener = new ModuleListener(this, listener);
 
         CLog.d("Running module %s", toString());
+        // Run DynamicConfigPusher setup once more, in case cleaner has previously
+        // removed dynamic config file from the target (see b/32877809)
+        for (ITargetPreparer preparer : mDynamicConfigPreparers) {
+            runPreparerSetup(preparer);
+        }
         // Setup
         for (ITargetPreparer preparer : mPreparers) {
             runPreparerSetup(preparer);
diff --git a/common/host-side/tradefed/tests/Android.mk b/common/host-side/tradefed/tests/Android.mk
index e0b44a3..17bdd50 100644
--- a/common/host-side/tradefed/tests/Android.mk
+++ b/common/host-side/tradefed/tests/Android.mk
@@ -41,6 +41,6 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := easymock
 
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt compatibility-mock-tradefed junit compatibility-host-util
+LOCAL_JAVA_LIBRARIES := tradefed compatibility-mock-tradefed junit-host compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index 1752e20..dcdede0 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -18,6 +18,8 @@
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelperTest;
 import com.android.compatibility.common.tradefed.command.CompatibilityConsoleTest;
 import com.android.compatibility.common.tradefed.config.ConfigurationFactoryTest;
+import com.android.compatibility.common.tradefed.presubmit.PresubmitSetupValidation;
+import com.android.compatibility.common.tradefed.result.ChecksumReporterTest;
 import com.android.compatibility.common.tradefed.result.ConsoleReporterTest;
 import com.android.compatibility.common.tradefed.result.ResultReporterTest;
 import com.android.compatibility.common.tradefed.result.SubPlanCreatorTest;
@@ -27,8 +29,8 @@
 import com.android.compatibility.common.tradefed.testtype.ModuleDefTest;
 import com.android.compatibility.common.tradefed.testtype.ModuleRepoTest;
 import com.android.compatibility.common.tradefed.testtype.SubPlanTest;
-import com.android.compatibility.common.tradefed.util.OptionHelperTest;
 import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
+import com.android.compatibility.common.tradefed.util.OptionHelperTest;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -42,20 +44,37 @@
 
     public UnitTests() {
         super();
+        // build
         addTestSuite(CompatibilityBuildHelperTest.class);
+
+        // command
         addTestSuite(CompatibilityConsoleTest.class);
-        addTestSuite(CompatibilityTestTest.class);
+
+        //config
         addTestSuite(ConfigurationFactoryTest.class);
+
+        // presubmit
+        addTestSuite(PresubmitSetupValidation.class);
+
+        //result
+        addTestSuite(ChecksumReporterTest.class);
         addTestSuite(ConsoleReporterTest.class);
         addTestSuite(ResultReporterTest.class);
-        addTestSuite(OptionHelperTest.class);
-        addTestSuite(CollectorUtilTest.class);
-        addTestSuite(ModuleDefTest.class);
-        addTestSuite(ModuleRepoTest.class);
+        addTestSuite(SubPlanCreatorTest.class);
+
+        // targetprep
         addTestSuite(PropertyCheckTest.class);
         addTestSuite(SettingsPreparerTest.class);
+
+        // testtype
+        addTestSuite(CompatibilityTestTest.class);
+        addTestSuite(ModuleDefTest.class);
+        addTestSuite(ModuleRepoTest.class);
         addTestSuite(SubPlanTest.class);
-        addTestSuite(SubPlanCreatorTest.class);
+
+        // util
+        addTestSuite(CollectorUtilTest.class);
+        addTestSuite(OptionHelperTest.class);
     }
 
     public static Test suite() {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
new file mode 100644
index 0000000..3342ba0
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.presubmit;
+
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that validate the CTS presubmit setup to ensure no CL will break the presubmit setup
+ * itself.
+ */
+public class PresubmitSetupValidation extends TestCase {
+    private static final String PRESUBMIT_CTS_UNIT_TESTS = "cts-unit-tests";
+
+    /**
+     * Test that the base cts unit tests configuration is still working, and has a reporter
+     * template placeholder.
+     */
+    public void testCtsPresubmit_unit_tests() {
+        IConfigurationFactory factory = ConfigurationFactory.getInstance();
+        String[] presubmitCommand = {PRESUBMIT_CTS_UNIT_TESTS, "--template:map", "reporters=empty"};
+        try {
+            factory.createConfigurationFromArgs(presubmitCommand);
+        } catch (ConfigurationException e) {
+            CLog.e(e);
+            fail(String.format("ConfigException '%s': One of your change is breaking the presubmit "
+                    + "CTS unit tests configuration.", e.getMessage()));
+        }
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
new file mode 100644
index 0000000..d5062b3
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.compatibility.common.util.ChecksumReporter;
+import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
+import com.android.compatibility.common.util.ICaseResult;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.IModuleResult;
+import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestStatus;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class ChecksumReporterTest extends TestCase {
+
+    private static final String ROOT_PROPERTY = "TESTS_ROOT";
+    private static final String ROOT_DIR_NAME = "root";
+    private static final String SUITE_NAME = "TESTS";
+    private static final String BUILD_NUMBER = "2";
+    private static final String SUITE_PLAN = "cts";
+    private static final String BASE_DIR_NAME = "android-tests";
+    private static final String TESTCASES = "testcases";
+
+    private ChecksumReporter mReporter;
+    private File mRoot = null;
+    private IBuildInfo mBuildInfo;
+    private ReportLog mReportLog = null;
+    private IInvocationResult mInvocationResult;
+    private IModuleResult mModuleResult;
+    private ITestResult mFailedTest;
+
+    @Override
+    public void setUp() throws Exception {
+        mReporter = new ChecksumReporter(100, .001, (short)1);
+        mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
+        File baseDir = new File(mRoot, BASE_DIR_NAME);
+        baseDir.mkdirs();
+        File testDir = new File(baseDir, TESTCASES);
+        testDir.mkdirs();
+        System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
+
+        ResultReporter resultReporter = new ResultReporter();
+        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
+            @Override
+            protected String getSuiteInfoName() {
+                return SUITE_NAME;
+            }
+            @Override
+            protected String getSuiteInfoBuildNumber() {
+                return BUILD_NUMBER;
+            }
+            @Override
+            protected String getSuiteInfoVersion() {
+                return BUILD_NUMBER;
+            }
+        };
+        OptionSetter setter = new OptionSetter(provider);
+        setter.setOptionValue("plan", SUITE_PLAN);
+        setter.setOptionValue("dynamic-config-url", "");
+        mBuildInfo = provider.getBuild();
+
+        resultReporter.invocationStarted(mBuildInfo);
+        mInvocationResult = resultReporter.getResult();
+        mModuleResult = mInvocationResult.getOrCreateModule("Module-1");
+        mModuleResult.setDone(true);
+        mModuleResult.setNotExecuted(0);
+        ICaseResult caseResult = mModuleResult.getOrCreateResult("Case-1");
+        ITestResult test1 = caseResult.getOrCreateResult("Test1");
+        test1.passed(mReportLog);
+        mFailedTest = caseResult.getOrCreateResult("Test2");
+        mFailedTest.failed("stack-trace - error happened");
+
+        IModuleResult moduleResult2 = mInvocationResult.getOrCreateModule("Module-2");
+        ICaseResult caseResult2 = moduleResult2.getOrCreateResult("Case-2");
+        mModuleResult.setDone(false);
+        mModuleResult.setNotExecuted(1);
+        ITestResult test3 = caseResult2.getOrCreateResult("Test3");
+        test3.passed(mReportLog);
+
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mReporter = null;
+        FileUtil.recursiveDelete(mRoot);
+    }
+
+    public void testStoreAndRetrieveTestResults() {
+        mReporter.addInvocation(mInvocationResult);
+        VerifyInvocationResults(mInvocationResult, mReporter);
+    }
+
+    /***
+     * By definition this test is flaky since the checksum has a false positive probability of .1%
+     */
+    public void testInvalidChecksums() {
+        mReporter.addInvocation(mInvocationResult);
+        IModuleResult module = mInvocationResult.getModules().get(1);
+        module.setDone(!module.isDone());
+        String fingerprint = mInvocationResult.getBuildFingerprint();
+        assertFalse("Checksum should contain module: " + module.getName(),
+                mReporter.containsModuleResult(module, fingerprint));
+
+        mFailedTest.setResultStatus(TestStatus.PASS);
+        assertFalse("Checksum should not contain test: " + mFailedTest.getName(),
+                mReporter.containsTestResult(mFailedTest, mModuleResult, fingerprint));
+        assertFalse("Module checksum should verify number of tests",
+                mReporter.containsModuleResult(mModuleResult, fingerprint));
+    }
+
+    public void testFileSerialization() throws IOException, ChecksumValidationException {
+        mReporter.addInvocation(mInvocationResult);
+
+        File file1 = new File(mRoot, "file1.txt");
+        try (FileWriter fileWriter = new FileWriter(file1, false)) {
+            fileWriter.append("This is a test file");
+        }
+
+        mReporter.addDirectory(mRoot);
+        mReporter.saveToFile(mRoot);
+
+        ChecksumReporter storedChecksum = ChecksumReporter.load(mRoot);
+        VerifyInvocationResults(mInvocationResult, storedChecksum);
+        assertTrue("Serializing checksum maintains file hash",
+                storedChecksum.containsFile(file1, mRoot.getName()));
+    }
+
+    public void testFileCRCOperations() throws IOException {
+        File subDirectory = new File(mRoot, "child");
+        subDirectory.mkdir();
+        File file1 = new File(mRoot, "file1.txt");
+        try (FileWriter fileWriter = new FileWriter(file1, false)) {
+            fileWriter.append("This is a test file");
+        }
+
+        File file2 = new File(subDirectory, "file2.txt");
+        try (FileWriter fileWriter = new FileWriter(file2, false)) {
+            fileWriter.append("This is another test file with a different crc");
+        }
+
+        mReporter.addDirectory(mRoot);
+        String folderName = mRoot.getName();
+        assertTrue(mReporter.containsFile(file1, folderName));
+        assertTrue(mReporter.containsFile(file2, folderName + "/child"));
+        assertFalse("Should not contain non-existent file",
+                mReporter.containsFile(new File(mRoot, "fake.txt"), folderName));
+
+        File file3 = new File(mRoot, "file3.txt");
+        try (FileWriter fileWriter = new FileWriter(file3, false)) {
+            fileWriter.append("This is a test file added after crc calculated");
+        }
+        assertFalse("Should not contain file created after crc calculated",
+                mReporter.containsFile(file3, mRoot + "/"));
+
+    }
+
+    private void VerifyInvocationResults(IInvocationResult invocation, ChecksumReporter reporter) {
+        for (IModuleResult module : invocation.getModules()) {
+            String buildFingerprint = invocation.getBuildFingerprint();
+            assertTrue("Checksum should contain module: " + module.getName(),
+                    reporter.containsModuleResult(module, buildFingerprint));
+            for (ICaseResult caseResult : module.getResults()) {
+                for (ITestResult result : caseResult.getResults()) {
+                    assertTrue("Checksum should contain test: " + result.getName(),
+                            reporter.containsTestResult(result, module, buildFingerprint));
+                }
+            }
+        }
+    }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
index f48a403..84f9faf 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
@@ -26,7 +26,6 @@
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionSetter;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.util.AbiUtils;
 import com.android.tradefed.util.FileUtil;
 
@@ -321,7 +320,6 @@
 
     public void testCopyFormattingFiles() throws Exception {
         File resultDir = new File(mBuildHelper.getResultsDir(), RESULT_DIR);
-        CLog.e("%s", resultDir);
         resultDir.mkdirs();
         ResultReporter.copyFormattingFiles(resultDir);
         for (String filename : FORMATTING_FILES) {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
index ae00eb4..e3240c1 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
@@ -94,8 +94,8 @@
         optionParser.parse(Arrays.asList(
             "-n", SP_NAME,
             "--session", SP_SESSION,
-            "-r", SP_RESULT_TYPE_FAILED,
-            "-r", SP_RESULT_TYPE_NOT_EXECUTED));
+            "--result-type", SP_RESULT_TYPE_FAILED,
+            "--result-type", SP_RESULT_TYPE_NOT_EXECUTED));
     }
 
     @Override
diff --git a/common/host-side/util/Android.mk b/common/host-side/util/Android.mk
index 5f5fb6f..771e334 100644
--- a/common/host-side/util/Android.mk
+++ b/common/host-side/util/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-hostsidelib jsonlib
 
-LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed
 
 LOCAL_MODULE := compatibility-host-util
 
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java b/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java
new file mode 100644
index 0000000..faac61f
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import com.android.annotations.Nullable;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.hash.BloomFilter;
+import com.google.common.hash.Funnels;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/***
+ * Calculate and store checksum values for files and test results
+ */
+public final class ChecksumReporter implements Serializable {
+
+    public static final String NAME = "checksum.data";
+    public static final String PREV_NAME = "checksum.previous.data";
+
+    private static final double DEFAULT_FPP = 0.05;
+    private static final String SEPARATOR = "/";
+    private static final String ID_SEPARATOR = "@";
+    private static final String NAME_SEPARATOR = ".";
+
+    private static final short CURRENT_VERSION = 1;
+    // Serialized format Id (ie magic number) used to identify serialized data.
+    static final short SERIALIZED_FORMAT_CODE = 650;
+
+    private final BloomFilter<CharSequence> mResultChecksum;
+    private final HashMap<String, byte[]> mFileChecksum;
+    private final short mVersion;
+
+    /***
+     * Calculate checksum of test results and files in result directory and write to disk
+     * @param dir test results directory
+     * @param result test results
+     * @return true if successful, false if unable to calculate or store the checksum
+     */
+    public static boolean tryCreateChecksum(File dir, IInvocationResult result) {
+        try {
+            int totalCount = countTestResults(result);
+            ChecksumReporter checksumReporter =
+                    new ChecksumReporter(totalCount, DEFAULT_FPP, CURRENT_VERSION);
+            checksumReporter.addInvocation(result);
+            checksumReporter.addDirectory(dir);
+            checksumReporter.saveToFile(dir);
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    /***
+     * Create Checksum Reporter from data saved on disk
+     * @param directory
+     * @return
+     * @throws ChecksumValidationException
+     */
+    public static ChecksumReporter load(File directory) throws ChecksumValidationException {
+        ChecksumReporter reporter = new ChecksumReporter(directory);
+        if (reporter.getCapacity() > 1.1) {
+            throw new ChecksumValidationException("Capacity exceeded.");
+        }
+        return reporter;
+    }
+
+    /***
+     * Deserialize checksum from file
+     * @param directory the parent directory containing the checksum file
+     * @throws ChecksumValidationException
+     */
+    public ChecksumReporter(File directory) throws ChecksumValidationException {
+        File file = new File(directory, ChecksumReporter.NAME);
+        try (FileInputStream fileStream = new FileInputStream(file);
+            InputStream outputStream = new BufferedInputStream(fileStream);
+            ObjectInput objectInput = new ObjectInputStream(outputStream)) {
+            short magicNumber = objectInput.readShort();
+            switch (magicNumber) {
+                case SERIALIZED_FORMAT_CODE:
+                   mVersion = objectInput.readShort();
+                    mResultChecksum = (BloomFilter<CharSequence>) objectInput.readObject();
+                    mFileChecksum = (HashMap<String, byte[]>) objectInput.readObject();
+                    break;
+                default:
+                    throw new ChecksumValidationException("Unknown format of serialized data.");
+            }
+        } catch (Exception e) {
+            throw new ChecksumValidationException("Unable to load checksum from file", e);
+        }
+        if (mVersion > CURRENT_VERSION) {
+            throw new ChecksumValidationException(
+                    "File contains a newer version of ChecksumReporter");
+        }
+    }
+
+    /***
+     * Create new instance of ChecksumReporter
+     * @param testCount the number of test results that will be stored
+     * @param fpp the false positive percentage for result lookup misses
+     */
+    public ChecksumReporter(int testCount, double fpp, short version) {
+        mResultChecksum = BloomFilter.create(Funnels.unencodedCharsFunnel(),
+                testCount, fpp);
+        mFileChecksum = new HashMap<>();
+        mVersion = version;
+    }
+
+    /***
+     * Add each test result from each module and test case
+     */
+    public void addInvocation(IInvocationResult invocationResult) {
+        for (IModuleResult module : invocationResult.getModules()) {
+            String buildFingerprint = invocationResult.getBuildFingerprint();
+            addModuleResult(module, buildFingerprint);
+            for (ICaseResult caseResult : module.getResults()) {
+                for (ITestResult testResult : caseResult.getResults()) {
+                    addTestResult(testResult, module, buildFingerprint);
+                }
+            }
+        }
+    }
+
+    /***
+     * Calculate CRC of file and store the result
+     * @param file crc calculated on this file
+     * @param path part of the key to identify the files crc
+     */
+    public void addFile(File file, String path) {
+        byte[] crc;
+        try {
+            crc = calculateFileChecksum(file);
+        } catch (ChecksumValidationException e) {
+            crc = new byte[0];
+        }
+        String key = path + SEPARATOR + file.getName();
+        mFileChecksum.put(key, crc);
+    }
+
+    @VisibleForTesting
+    public boolean containsFile(File file, String path) {
+        String key = path + SEPARATOR + file.getName();
+        if (mFileChecksum.containsKey(key))
+        {
+            try {
+                byte[] crc = calculateFileChecksum(file);
+                return Arrays.equals(mFileChecksum.get(key), crc);
+            } catch (ChecksumValidationException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /***
+     * Adds all child files recursively through all sub directories
+     * @param directory target that is deeply searched for files
+     */
+    public void addDirectory(File directory) {
+        addDirectory(directory, directory.getName());
+    }
+
+    /***
+     * @param path the relative path to the current directory from the base directory
+     */
+    private void addDirectory(File directory, String path) {
+        for(String childName : directory.list()) {
+            File child = new File(directory, childName);
+            if (child.isDirectory()) {
+                addDirectory(child, path + SEPARATOR + child.getName());
+            } else {
+                addFile(child, path);
+            }
+        }
+    }
+
+    /***
+     * Calculate checksum of test result and store the value
+     * @param testResult the target of the checksum
+     * @param moduleResult the module that contains the test result
+     * @param buildFingerprint the fingerprint the test execution is running against
+     */
+    public void addTestResult(
+        ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
+
+        String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
+        mResultChecksum.put(signature);
+    }
+
+    @VisibleForTesting
+    public boolean containsTestResult(
+            ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
+
+        String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
+        return mResultChecksum.mightContain(signature);
+    }
+
+    /***
+     * Calculate checksm of module result and store value
+     * @param moduleResult  the target of the checksum
+     * @param buildFingerprint the fingerprint the test execution is running against
+     */
+    public void addModuleResult(IModuleResult moduleResult, String buildFingerprint) {
+        mResultChecksum.put(
+                generateModuleResultSignature(moduleResult, buildFingerprint));
+        mResultChecksum.put(
+                generateModuleSummarySignature(moduleResult, buildFingerprint));
+    }
+
+    @VisibleForTesting
+    public Boolean containsModuleResult(IModuleResult moduleResult, String buildFingerprint) {
+        return mResultChecksum.mightContain(
+                generateModuleResultSignature(moduleResult, buildFingerprint));
+    }
+
+    /***
+     * Write the checksum data to disk.
+     * Overwrites existing file
+     * @param directory
+     * @throws IOException
+     */
+    public void saveToFile(File directory) throws IOException {
+        File file = new File(directory, NAME);
+
+        try (FileOutputStream fileStream = new FileOutputStream(file, false);
+             OutputStream outputStream = new BufferedOutputStream(fileStream);
+             ObjectOutput objectOutput = new ObjectOutputStream(outputStream)) {
+            objectOutput.writeShort(SERIALIZED_FORMAT_CODE);
+            objectOutput.writeShort(mVersion);
+            objectOutput.writeObject(mResultChecksum);
+            objectOutput.writeObject(mFileChecksum);
+        }
+    }
+
+    @VisibleForTesting
+    double getCapacity() {
+        // If default FPP changes:
+        // increment the CURRENT_VERSION and set the denominator based on this.mVersion
+        return mResultChecksum.expectedFpp() / DEFAULT_FPP;
+    }
+
+    static String generateTestResultSignature(ITestResult testResult, IModuleResult module,
+            String buildFingerprint) {
+        StringBuilder sb = new StringBuilder();
+        String stacktrace = testResult.getStackTrace();
+
+        stacktrace = stacktrace == null ? "" : stacktrace.trim();
+        // Line endings for stacktraces are somewhat unpredictable and there is no need to
+        // actually read the result they are all removed for consistency.
+        stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
+        sb.append(buildFingerprint).append(SEPARATOR)
+                .append(module.getId()).append(SEPARATOR)
+                .append(testResult.getFullName()).append(SEPARATOR)
+                .append(testResult.getResultStatus().getValue()).append(SEPARATOR)
+                .append(stacktrace).append(SEPARATOR);
+        return sb.toString();
+    }
+
+    static String generateTestResultSignature(
+            String packageName, String suiteName, String caseName, String testName, String abi,
+            String status,
+            String stacktrace,
+            String buildFingerprint) {
+
+        String testId = buildTestId(suiteName, caseName, testName, abi);
+        StringBuilder sb = new StringBuilder();
+
+        stacktrace = stacktrace == null ? "" : stacktrace.trim();
+        // Line endings for stacktraces are somewhat unpredictable and there is no need to
+        // actually read the result they are all removed for consistency.
+        stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
+        sb.append(buildFingerprint)
+                .append(SEPARATOR)
+                .append(packageName)
+                .append(SEPARATOR)
+                .append(testId)
+                .append(SEPARATOR)
+                .append(status)
+                .append(SEPARATOR)
+                .append(stacktrace)
+                .append(SEPARATOR);
+        return sb.toString();
+    }
+
+    private static String buildTestId(
+            String suiteName, String caseName, String testName, @Nullable String abi) {
+        String name = Joiner.on(NAME_SEPARATOR).skipNulls().join(
+                Strings.emptyToNull(suiteName),
+                Strings.emptyToNull(caseName),
+                Strings.emptyToNull(testName));
+        return Joiner.on(ID_SEPARATOR).skipNulls().join(
+                Strings.emptyToNull(name),
+                Strings.emptyToNull(abi));
+    }
+
+
+    private static String generateModuleResultSignature(IModuleResult module,
+            String buildFingerprint) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(buildFingerprint).append(SEPARATOR)
+                .append(module.getId()).append(SEPARATOR)
+                .append(module.isDone()).append(SEPARATOR)
+                .append(module.getNotExecuted()).append(SEPARATOR)
+                .append(module.countResults(TestStatus.FAIL));
+        return sb.toString();
+    }
+
+    private static String generateModuleSummarySignature(IModuleResult module,
+            String buildFingerprint) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(buildFingerprint).append(SEPARATOR)
+                .append(module.getId()).append(SEPARATOR)
+                .append(module.countResults(TestStatus.FAIL));
+        return sb.toString();
+    }
+
+    static byte[] calculateFileChecksum(File file) throws ChecksumValidationException {
+
+        try (FileInputStream fis = new FileInputStream(file);
+             InputStream inputStream = new BufferedInputStream(fis)) {
+            MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
+            int cnt;
+            int bufferSize = 8192;
+            byte [] buffer = new byte[bufferSize];
+            while ((cnt = inputStream.read(buffer)) != -1) {
+                hashSum.update(buffer, 0, cnt);
+            }
+
+            byte[] partialHash = new byte[32];
+            hashSum.digest(partialHash, 0, 32);
+            return partialHash;
+        } catch (NoSuchAlgorithmException e) {
+            throw new ChecksumValidationException("Unable to hash file.", e);
+        } catch (IOException e) {
+            throw new ChecksumValidationException("Unable to hash file.", e);
+        } catch (DigestException e) {
+            throw new ChecksumValidationException("Unable to hash file.", e);
+        }
+    }
+
+
+    private static int countTestResults(IInvocationResult invocation) {
+        int count = 0;
+        for (IModuleResult module : invocation.getModules()) {
+            // Two entries per module (result & summary)
+            count += 2;
+            for (ICaseResult caseResult : module.getResults()) {
+                count += caseResult.getResults().size();
+            }
+        }
+        return count;
+    }
+
+    public static class ChecksumValidationException extends Exception {
+        public ChecksumValidationException(String detailMessage) {
+            super(detailMessage);
+        }
+
+        public ChecksumValidationException(String detailMessage, Throwable throwable) {
+            super(detailMessage, throwable);
+        }
+    }
+}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java b/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java
index 739dd48..96eca2d 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java
@@ -114,4 +114,25 @@
      * Return the number of completed test modules for this invocation.
      */
     int getModuleCompleteCount();
+
+    /**
+     * Return status of checksum from previous session
+     */
+    RetryChecksumStatus getRetryChecksumStatus();
+
+    /**
+     * Set status of checksum from previous session
+     */
+    void setRetryChecksumStatus(RetryChecksumStatus retryStatus);
+
+    /**
+     * Return the directory of the previous sessions results
+     */
+    File getRetryDirectory();
+
+    /**
+     * Set the directory of the previous sessions results
+     */
+    void setRetryDirectory(File resultDir);
+
 }
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java b/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java
index f74c61d..c11c27d 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java
@@ -15,6 +15,7 @@
  */
 package com.android.compatibility.common.util;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -37,6 +38,8 @@
     private String mTestPlan;
     private String mCommandLineArgs;
     private int mNotExecuted = 0;
+    private RetryChecksumStatus mRetryChecksumStatus = RetryChecksumStatus.NotRetry;
+    private File mRetryDirectory = null;
 
     /**
      * {@inheritDoc}
@@ -201,4 +204,36 @@
         }
         return completeModules;
     }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public RetryChecksumStatus getRetryChecksumStatus() {
+        return mRetryChecksumStatus;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRetryChecksumStatus(RetryChecksumStatus retryStatus) {
+        mRetryChecksumStatus = retryStatus;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public File getRetryDirectory() {
+        return mRetryDirectory;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setRetryDirectory(File resultDir) {
+        mRetryDirectory = resultDir;
+    }
 }
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
index 4a73d60..46fa9db 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -15,8 +15,11 @@
  */
 package com.android.compatibility.common.util;
 
+import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
 import com.android.tradefed.util.AbiUtils;
 
+import com.google.common.base.Strings;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlPullParserFactory;
@@ -30,9 +33,11 @@
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
@@ -97,26 +102,43 @@
     private static final String SUMMARY_TAG = "Summary";
     private static final String TEST_TAG = "Test";
 
+
     /**
      * @param resultsDir
      */
     public static List<IInvocationResult> getResults(File resultsDir) {
+        return getResults(resultsDir, false);
+    }
+
+    /**
+     * @param resultsDir
+     * @param useChecksum
+     */
+    public static List<IInvocationResult> getResults(
+            File resultsDir, Boolean useChecksum) {
         List<IInvocationResult> results = new ArrayList<>();
-        File[] files = resultsDir.listFiles();
-        if (files == null || files.length == 0) {
-            // No results, just return the empty list
-            return results;
-        }
+        List<File> files = getResultDirectories(resultsDir);
+
         for (File resultDir : files) {
-            if (!resultDir.isDirectory()) {
-                continue;
-            }
             try {
                 File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
                 if (!resultFile.exists()) {
                     continue;
                 }
+                Boolean invocationUseChecksum = useChecksum;
                 IInvocationResult invocation = new InvocationResult();
+                invocation.setRetryDirectory(resultDir);
+                ChecksumReporter checksumReporter = null;
+                if (invocationUseChecksum) {
+                    try {
+                        checksumReporter = ChecksumReporter.load(resultDir);
+                        invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithChecksum);
+                    } catch (ChecksumValidationException e) {
+                        // Unable to read checksum form previous execution
+                        invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithoutChecksum);
+                        invocationUseChecksum = false;
+                    }
+                }
                 XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
                 XmlPullParser parser = factory.newPullParser();
                 parser.setInput(new FileReader(resultFile));
@@ -202,10 +224,22 @@
                                 }
                             }
                             parser.require(XmlPullParser.END_TAG, NS, TEST_TAG);
+                            Boolean checksumMismatch = invocationUseChecksum
+                                && !checksumReporter.containsTestResult(
+                                    test, module, invocation.getBuildFingerprint());
+                            if (checksumMismatch) {
+                                test.removeResult();
+                            }
                         }
                         parser.require(XmlPullParser.END_TAG, NS, CASE_TAG);
                     }
                     parser.require(XmlPullParser.END_TAG, NS, MODULE_TAG);
+                    Boolean checksumMismatch = invocationUseChecksum
+                        && !checksumReporter.containsModuleResult(
+                                module, invocation.getBuildFingerprint());
+                    if (checksumMismatch) {
+                        module.setDone(false);
+                    }
                 }
                 parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
                 results.add(invocation);
@@ -218,11 +252,9 @@
             }
         }
         // Sort the table entries on each entry's timestamp.
-        Collections.sort(results, new Comparator<IInvocationResult>() {
-            public int compare(IInvocationResult result1, IInvocationResult result2) {
-                return Long.compare(result1.getStartTime(), result2.getStartTime());
-            }
-        });
+        Collections.sort(results,  (result1, result2) -> Long.compare(
+                result1.getStartTime(),
+                result2.getStartTime()));
         return results;
     }
 
@@ -304,6 +336,10 @@
         serializer.startTag(NS, BUILD_TAG);
         for (Entry<String, String> entry : result.getInvocationInfo().entrySet()) {
             serializer.attribute(NS, entry.getKey(), entry.getValue());
+            if (Strings.isNullOrEmpty(result.getBuildFingerprint()) &&
+                entry.getKey().equals(BUILD_FINGERPRINT)) {
+                result.setBuildFingerprint(entry.getValue());
+            }
         }
         serializer.endTag(NS, BUILD_TAG);
 
@@ -381,20 +417,60 @@
             serializer.endTag(NS, MODULE_TAG);
         }
         serializer.endDocument();
+        createChecksum(resultDir, result);
         return resultFile;
     }
 
+    private static void createChecksum(File resultDir, IInvocationResult invocationResult) {
+        RetryChecksumStatus retryStatus = invocationResult.getRetryChecksumStatus();
+        switch (retryStatus) {
+            case NotRetry: case RetryWithChecksum:
+                // Do not disrupt the process if there is a problem generating checksum.
+                ChecksumReporter.tryCreateChecksum(resultDir, invocationResult);
+                break;
+            case RetryWithoutChecksum:
+                // If the previous run has an invalid checksum file,
+                // copy it into current results folder for future troubleshooting
+                File retryDirectory = invocationResult.getRetryDirectory();
+                Path retryChecksum = FileSystems.getDefault().getPath(
+                        retryDirectory.getAbsolutePath(), ChecksumReporter.NAME);
+                if (!retryChecksum.toFile().exists()) {
+                    // if no checksum file, check for a copy from a previous retry
+                    retryChecksum = FileSystems.getDefault().getPath(
+                            retryDirectory.getAbsolutePath(), ChecksumReporter.PREV_NAME);
+                }
+
+                if (retryChecksum.toFile().exists()) {
+                    File checksumCopy = new File(resultDir, ChecksumReporter.PREV_NAME);
+                    try (FileOutputStream stream = new FileOutputStream(checksumCopy)) {
+                        Files.copy(retryChecksum, stream);
+                    } catch (IOException e) {
+                        // Do not disrupt the process if there is a problem copying checksum
+                    }
+                }
+        }
+    }
+
+
     /**
      * Find the IInvocationResult for the given sessionId.
      */
     public static IInvocationResult findResult(File resultsDir, Integer sessionId)
             throws FileNotFoundException {
+        return findResult(resultsDir, sessionId, true);
+    }
+
+    /**
+     * Find the IInvocationResult for the given sessionId.
+     */
+    private static IInvocationResult findResult(
+            File resultsDir, Integer sessionId, Boolean useChecksum) throws FileNotFoundException {
         if (sessionId < 0) {
             throw new IllegalArgumentException(
                 String.format("Invalid session id [%d] ", sessionId));
         }
 
-        List<IInvocationResult> results = getResults(resultsDir);
+        List<IInvocationResult> results = getResults(resultsDir, useChecksum);
         if (results == null || sessionId >= results.size()) {
             throw new RuntimeException(String.format("Could not find session [%d]", sessionId));
         }
@@ -402,6 +478,33 @@
     }
 
     /**
+     * Get a list of child directories that contain test invocation results
+     * @param resultsDir the root test result directory
+     * @return
+     */
+    public static List<File> getResultDirectories(File resultsDir) {
+        List<File> directoryList = new ArrayList<>();
+        File[] files = resultsDir.listFiles();
+        if (files == null || files.length == 0) {
+            // No results, just return the empty list
+            return directoryList;
+        }
+        for (File resultDir : files) {
+            if (!resultDir.isDirectory()) {
+                continue;
+            }
+            // Only include if it contain results file
+            File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+            if (!resultFile.exists()) {
+                continue;
+            }
+            directoryList.add(resultDir);
+        }
+        Collections.sort(directoryList, (d1, d2) -> d1.getName().compareTo(d2.getName()));
+        return directoryList;
+    }
+
+    /**
      * Return the given time as a {@link String} suitable for displaying.
      * <p/>
      * Example: Fri Aug 20 15:13:03 PDT 2010
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/RetryChecksumStatus.java b/common/host-side/util/src/com/android/compatibility/common/util/RetryChecksumStatus.java
new file mode 100644
index 0000000..a86ab37
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/RetryChecksumStatus.java
@@ -0,0 +1,8 @@
+package com.android.compatibility.common.util;
+
+
+public enum RetryChecksumStatus {
+    NotRetry,
+    RetryWithChecksum,
+    RetryWithoutChecksum
+}
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
index 9bd3a4b..b5806c7 100644
--- a/common/host-side/util/tests/Android.mk
+++ b/common/host-side/util/tests/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util junit json-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util junit-host json-prebuilt tradefed
 
 LOCAL_MODULE := compatibility-host-util-tests
 
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 386a4ce..f2fa303 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -151,9 +151,7 @@
 
     @Override
     public void tearDown() throws Exception {
-        if (resultsDir != null) {
-            FileUtil.recursiveDelete(resultsDir);
-        }
+        FileUtil.recursiveDelete(resultsDir);
     }
 
     public void testSerialization() throws Exception {
@@ -253,6 +251,7 @@
             if (writer != null) {
                 writer.close();
             }
+            FileUtil.recursiveDelete(resultsDir);
         }
     }
 
diff --git a/common/util/Android.mk b/common/util/Android.mk
index c95508b..faf4596 100644
--- a/common/util/Android.mk
+++ b/common/util/Android.mk
@@ -42,7 +42,7 @@
 
 LOCAL_MODULE := compatibility-common-util-hostsidelib
 
-LOCAL_STATIC_JAVA_LIBRARIES := junit kxml2-2.3.0 platform-test-annotations-host
+LOCAL_STATIC_JAVA_LIBRARIES := junit-host kxml2-2.3.0 platform-test-annotations-host
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/common/util/src/com/android/compatibility/common/util/ITestResult.java b/common/util/src/com/android/compatibility/common/util/ITestResult.java
index 98d93c5..d5c95e8 100644
--- a/common/util/src/com/android/compatibility/common/util/ITestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ITestResult.java
@@ -146,4 +146,8 @@
      */
     boolean isRetry();
 
+    /**
+     * Clear the existing result and default to 'failed'
+     */
+    void removeResult();
 }
diff --git a/common/util/src/com/android/compatibility/common/util/TestResult.java b/common/util/src/com/android/compatibility/common/util/TestResult.java
index c59ba1f..18a8b4c 100644
--- a/common/util/src/com/android/compatibility/common/util/TestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/TestResult.java
@@ -255,6 +255,15 @@
      * {@inheritDoc}
      */
     @Override
+    public void removeResult() {
+        setResultStatus(TestStatus.FAIL);
+        setStackTrace("");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public int compareTo(ITestResult another) {
         return getName().compareTo(another.getName());
     }
diff --git a/common/util/tests/Android.mk b/common/util/tests/Android.mk
index 0e0af50..5e3370b 100644
--- a/common/util/tests/Android.mk
+++ b/common/util/tests/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := junit kxml2-2.3.0 tradefed-prebuilt compatibility-common-util-hostsidelib
+LOCAL_JAVA_LIBRARIES := junit-host kxml2-2.3.0 tradefed compatibility-common-util-hostsidelib
 
 LOCAL_MODULE := compatibility-common-util-tests
 
diff --git a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
index cf1892a..df50d11 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
@@ -16,6 +16,8 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.tradefed.util.FileUtil;
+
 import junit.framework.TestCase;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -81,24 +83,28 @@
     public void testCorrectConfig() throws Exception {
         DynamicConfig config = new DynamicConfig();
         File file = createFileFromStr(correctConfig);
-        config.initializeConfig(file);
-
-        assertEquals("Wrong Config", config.getValue("test-config-1"), "test config 1");
-        assertEquals("Wrong Config", config.getValue("test-config-2"), "testconfig2");
-        assertEquals("Wrong Config List", config.getValues("config-list").get(0), "config0");
-        assertEquals("Wrong Config List", config.getValues("config-list").get(2), "config2");
-        assertEquals("Wrong Config List", config.getValues("config-list-2").get(2), "C");
+        try {
+            config.initializeConfig(file);
+            assertEquals("Wrong Config", config.getValue("test-config-1"), "test config 1");
+            assertEquals("Wrong Config", config.getValue("test-config-2"), "testconfig2");
+            assertEquals("Wrong Config List", config.getValues("config-list").get(0), "config0");
+            assertEquals("Wrong Config List", config.getValues("config-list").get(2), "config2");
+            assertEquals("Wrong Config List", config.getValues("config-list-2").get(2), "C");
+        } finally {
+            FileUtil.deleteFile(file);
+        }
     }
 
     public void testConfigWithWrongNodeName() throws Exception {
         DynamicConfig config = new DynamicConfig();
         File file = createFileFromStr(configWrongNodeName);
-
         try {
             config.initializeConfig(file);
             fail("Cannot detect error when config file has wrong node name");
         } catch (XmlPullParserException e) {
             //expected
+        } finally {
+            FileUtil.deleteFile(file);
         }
     }
 
@@ -107,6 +113,7 @@
         FileOutputStream stream = new FileOutputStream(file);
         stream.write(configStr.getBytes());
         stream.flush();
+        stream.close();
         return file;
     }
 }
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
index c8d4682..0da5f2d 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
@@ -20,9 +20,6 @@
 
 import junit.framework.TestCase;
 
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.util.List;
 import java.util.Arrays;
 
 /**
@@ -38,7 +35,8 @@
     private static final String SUMMARY_XML =
             HEADER_XML + "\r\n" +
             "<Summary>\r\n" +
-            "  <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
+            "  <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" "
+            + "message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
             "    <Value>1.0</Value>\r\n" +
             "  </Metric>\r\n" +
             "</Summary>";
@@ -66,7 +64,7 @@
 
     public void testSerialize_summaryOnly() throws Exception {
         mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
-        assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:68"),
+        assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:66"),
                 ReportLog.serialize(mReportLog));
     }
 
@@ -78,7 +76,7 @@
     public void testSerialize_full() throws Exception {
         mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
         mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
-        assertEquals(String.format(FULL_XML, "testSerialize_full:79"),
+        assertEquals(String.format(FULL_XML, "testSerialize_full:77"),
                 ReportLog.serialize(mReportLog));
     }
 
diff --git a/hostsidetests/aadb/Android.mk b/hostsidetests/aadb/Android.mk
index f20f603..5cc2c10 100644
--- a/hostsidetests/aadb/Android.mk
+++ b/hostsidetests/aadb/Android.mk
@@ -22,7 +22,7 @@
 # Adb test cases, but name 'aadb' ensures adb tests run before all other modules depending on adb
 LOCAL_MODULE := CtsAadbHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.aadb
 
diff --git a/hostsidetests/abioverride/Android.mk b/hostsidetests/abioverride/Android.mk
index f77303b..88c44d9 100644
--- a/hostsidetests/abioverride/Android.mk
+++ b/hostsidetests/abioverride/Android.mk
@@ -27,9 +27,7 @@
 
 LOCAL_CTS_TEST_PACKAGE := android.host.abioverride
 
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
-
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java b/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
index 26d35a4..c2f14f0 100644
--- a/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
+++ b/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
@@ -16,7 +16,7 @@
 
 package android.abioverride.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -72,7 +72,8 @@
         super.setUp();
         ITestDevice device = getDevice();
         device.uninstallPackage(PACKAGE);
-        File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        File app = buildHelper.getTestFile(APK_NAME);
         String[] options = {};
         device.installPackage(app, false, options);
     }
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 258192d..6afcce8 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsAppSecurityHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_JAVA_RESOURCE_DIRS := res
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index 1032c62..881f5b8b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -24,7 +24,6 @@
 import static android.appsecurity.cts.SplitTests.PKG;
 
 import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
-import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -293,8 +292,18 @@
     }
 
     private String getAdoptionDisk() throws Exception {
-        final String disks = getDevice().executeShellCommand("sm list-disks adoptable");
-        if (disks == null || disks.length() == 0) {
+        // In the case where we run multiple test we cleanup the state of the device. This
+        // results in the execution of sm forget all which causes the MountService to "reset"
+        // all its knowledge about available drives. This can cause the adoptable drive to
+        // become temporarily unavailable.
+        int attempt = 0;
+        String disks = getDevice().executeShellCommand("sm list-disks adoptable");
+        while ((disks == null || disks.isEmpty()) && attempt++ < 15) {
+            Thread.sleep(1000);
+            disks = getDevice().executeShellCommand("sm list-disks adoptable");
+        }
+
+        if (disks == null || disks.isEmpty()) {
             throw new AssertionError("Devices that claim to support adoptable storage must have "
                     + "adoptable media inserted during CTS to verify correct behavior");
         }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index e6f6a6d..36b0921 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -103,7 +103,8 @@
     }
 
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 
     @Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index 3c6cac5..a064287 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 
 /**
  * Set of tests that verify behavior of
@@ -31,9 +31,8 @@
         super.setUp();
 
         getDevice().uninstallPackage(PROVIDER_PKG);
-
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, PROVIDER_APK), false));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(PROVIDER_APK), false));
     }
 
     @Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
index 009d81b..ceb7539 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -68,8 +68,7 @@
 
     protected void reinstallClientPackage() throws Exception {
         getDevice().uninstallPackage(CLIENT_PKG);
-
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(CLIENT_APK), false));
     }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 65e8a03..ed46225 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -66,7 +66,8 @@
     }
 
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 
     @Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
index 53a54dd..1f7c6be 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -101,7 +101,8 @@
     private static final String LOG_TAG = "AppsecurityHostTests";
 
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 
     /**
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 072a533..0e53c46 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -36,7 +36,7 @@
     private static final String APK_24 = "CtsUsePermissionApp24.apk";
 
     private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
+    private CompatibilityBuildHelper mBuildHelper;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -45,7 +45,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -53,7 +53,7 @@
         super.setUp();
 
         assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
+        assertNotNull(mBuildHelper);
 
         getDevice().uninstallPackage(PKG);
     }
@@ -67,8 +67,7 @@
 
     public void testFail() throws Exception {
         // Sanity check that remote failure is host failure
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testFail");
@@ -79,8 +78,7 @@
 
     public void testKill() throws Exception {
         // Sanity check that remote kill is host failure
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testKill");
@@ -90,17 +88,13 @@
     }
 
     public void testCompatDefault22() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22),
-                false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                 "testCompatDefault");
     }
 
     public void testCompatRevoked22() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22),
-                false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                     "testCompatRevoked_part1");
@@ -112,72 +106,61 @@
     }
 
     public void testNoRuntimePrompt22() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22),
-                false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                 "testNoRuntimePrompt");
     }
 
     public void testDefault23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testDefault");
     }
 
     public void testGranted23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testGranted");
     }
 
     public void testInteractiveGrant23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testInteractiveGrant");
     }
 
     public void testRuntimeGroupGrantSpecificity23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRuntimeGroupGrantSpecificity");
     }
 
     public void testRuntimeGroupGrantExpansion23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRuntimeGroupGrantExpansion");
     }
 
     public void testCancelledPermissionRequest23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testCancelledPermissionRequest");
     }
 
     public void testRequestGrantedPermission23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestGrantedPermission");
     }
 
     public void testDenialWithPrejudice23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testDenialWithPrejudice");
     }
 
     public void testRevokeAffectsWholeGroup23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testRevokeAffectsWholeGroup_part1");
@@ -188,8 +171,7 @@
     }
 
     public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                     "testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1");
@@ -201,89 +183,75 @@
     }
 
     public void testRequestNonRuntimePermission23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestNonRuntimePermission");
     }
 
     public void testRequestNonExistentPermission23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestNonExistentPermission");
     }
 
     public void testRequestPermissionFromTwoGroups23() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRequestPermissionFromTwoGroups");
     }
 
 //    public void testOnlyRequestedPermissionsGranted24() throws Exception {
-//        assertNull(getDevice().installPackage(
-//                MigrationHelper.getTestFile(mCtsBuild, APK_24), false, false));
+//        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_24), false, false));
 //        runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest24",
 //                "testOnlyRequestedPermissionsGranted");
 //    }
 
     public void testUpgradeKeepsPermissions() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                 "testAllPermissionsGrantedByDefault");
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testAllPermissionsGrantedOnUpgrade");
     }
 
     public void testNoDowngradePermissionModel() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         try {
-            assertNull(getDevice().installPackage(
-                    MigrationHelper.getTestFile(mCtsBuild, APK_22), true, false));
+            assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), true, false));
             fail("Permission mode downgrade not allowed");
         } catch (AssertionError expected) {
         }
     }
 
     public void testNoResidualPermissionsOnUninstall() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testNoResidualPermissionsOnUninstall_part1");
         assertNull(getDevice().uninstallPackage(PKG));
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testNoResidualPermissionsOnUninstall_part2");
     }
 
     public void testRevokePropagatedOnUpgradeOldToNewModel() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
         try {
             runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
                     "testRevokePropagatedOnUpgradeOldToNewModel_part1");
             fail("App must be killed on a permission revoke");
         } catch (AssertionError expected) {
         }
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRevokePropagatedOnUpgradeOldToNewModel_part2");
     }
 
     public void testRevokePropagatedOnUpgradeNewToNewModel() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRevokePropagatedOnUpgradeNewToNewModel_part1");
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
         runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
                 "testRevokePropagatedOnUpgradeNewToNewModel_part2");
     }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
index 53d3066..ca218ef 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -47,7 +47,7 @@
             + " com.android.cts.priv.ctsshim";
 
     private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
+    private CompatibilityBuildHelper mBuildHelper;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -56,7 +56,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -64,13 +64,12 @@
         super.setUp();
 
         assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
+        assertNotNull(mBuildHelper);
 
         getDevice().uninstallPackage(SHIM_PKG);
         getDevice().uninstallPackage(TEST_PKG);
 
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(TEST_APK), false));
         getDevice().executeShellCommand("pm enable " + SHIM_PKG);
     }
 
@@ -86,7 +85,7 @@
     public void testPrivilegedAppUpgradeRestricted() throws Exception {
         getDevice().uninstallPackage(SHIM_PKG);
         assertEquals(RESTRICTED_UPGRADE_FAILURE, getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_FAIL_APK), true));
+                mBuildHelper.getTestFile(SHIM_UPDATE_FAIL_APK), true));
     }
 
     public void testSystemAppPriorities() throws Exception {
@@ -102,7 +101,7 @@
         
         try {
             assertNull(getDevice().installPackage(
-                    MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+                    mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
             runDeviceTests(TEST_PKG, ".PrivilegedUpdateTest", "testPrivilegedAppUpgradePriorities");
         } finally {
             getDevice().uninstallPackage(SHIM_PKG);
@@ -121,7 +120,7 @@
         runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testPrivAppAndEnabled");
         try {
             assertNull(getDevice().installPackage(
-                    MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+                    mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
             getDevice().executeShellCommand("pm disable-user " + SHIM_PKG);
             runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testUpdatedPrivAppAndDisabled");
             getDevice().executeShellCommand("pm enable " + SHIM_PKG);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index 86cc8e8..00ccd4c 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -334,7 +334,8 @@
         }
 
         T addApk(String apk) throws FileNotFoundException {
-            mApks.add(MigrationHelper.getTestFile(mBuild, apk));
+            CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+            mApks.add(buildHelper.getTestFile(apk));
             return (T) this;
         }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
index c8e608e..cf8a354 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -16,7 +16,7 @@
 
 package android.appsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -35,7 +35,7 @@
     private static final String APK_COMPAT = "CtsUsesLibraryAppCompat.apk";
 
     private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
+    private CompatibilityBuildHelper mBuildHelper;
 
     @Override
     public void setAbi(IAbi abi) {
@@ -44,7 +44,7 @@
 
     @Override
     public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+        mBuildHelper = new CompatibilityBuildHelper(buildInfo);
     }
 
     @Override
@@ -52,7 +52,7 @@
         super.setUp();
 
         assertNotNull(mAbi);
-        assertNotNull(mCtsBuild);
+        assertNotNull(mBuildHelper);
 
         getDevice().uninstallPackage(PKG);
     }
@@ -65,20 +65,17 @@
     }
 
     public void testUsesLibrary() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
         runDeviceTests(PKG, ".UsesLibraryTest", "testUsesLibrary");
     }
 
     public void testMissingLibrary() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
         runDeviceTests(PKG, ".UsesLibraryTest", "testMissingLibrary");
     }
 
     public void testDuplicateLibrary() throws Exception {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
         runDeviceTests(PKG, ".UsesLibraryTest", "testDuplicateLibrary");
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index 69fc9e9..f2b1eda 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -433,6 +433,7 @@
                 (AccessibilityEvent event) -> event.getEventType()
                         == AccessibilityEvent.TYPE_VIEW_SCROLLED,
                 GLOBAL_TIMEOUT_MILLIS);
+        node.refresh();
         waitForIdle();
     }
 
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index d0b7ef5..c4a0913 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -21,9 +21,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsAtraceHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.atrace
 
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index 4fc041c..3ab7d95 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -16,7 +16,7 @@
 
 package android.atrace.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
@@ -201,7 +201,8 @@
             getDevice().uninstallPackage(TEST_PKG);
 
             // install the test app
-            File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+            CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+            File testAppFile = buildHelper.getTestFile(TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
                     String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/compilation/Android.mk b/hostsidetests/compilation/Android.mk
index 64e7063..723e5c3 100644
--- a/hostsidetests/compilation/Android.mk
+++ b/hostsidetests/compilation/Android.mk
@@ -27,7 +27,7 @@
 
 LOCAL_MODULE := CtsCompilationTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_STATIC_JAVA_LIBRARIES := guavalib
 
diff --git a/hostsidetests/compilation/assets/primary.prof b/hostsidetests/compilation/assets/primary.prof
index dbd70c7..18792ba 100644
--- a/hostsidetests/compilation/assets/primary.prof
+++ b/hostsidetests/compilation/assets/primary.prof
Binary files differ
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
index 2c1f697..67acb25 100644
--- a/hostsidetests/cpptools/Android.mk
+++ b/hostsidetests/cpptools/Android.mk
@@ -23,7 +23,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsCppToolsTestCases
 
-LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.tests.cpptools
 
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index d6fb30b..1828e2c 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.adminhostside
 
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
new file mode 100644
index 0000000..9b3daed
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
@@ -0,0 +1,71 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# IMPORTANT: We build two apps from the same source but with different package name.
+# This allow us to have different device owner and profile owner, some APIs may behave differently
+# in this situation.
+
+# === App 1 ===
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCorpOwnedManagedProfile
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
+
+# === App 2 ===
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCorpOwnedManagedProfile2
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.cts.comp2 \
+                    --rename-instrumentation-target-package com.android.cts.comp2
+
+include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml
new file mode 100644
index 0000000..3924d84
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.comp" >
+    <!-- package="com.android.cts.comp2"
+         We have com.android.cts.comp2 that have the exact same source but with different package
+         name, see Android.mk for details. -->
+    <application
+        android:testOnly="true">
+
+        <uses-library android:name="android.test.runner" />
+        <receiver
+                android:name="com.android.cts.comp.AdminReceiver"
+                android:exported="false"
+                android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data
+                    android:name="android.app.device_admin"
+                    android:resource="@xml/device_admin"/>
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
+            </intent-filter>
+        </receiver>
+
+        <service android:name=".CrossUserService"
+                android:exported="false">
+        </service>
+
+        <service android:name=".ExportedCrossUserService"
+                android:exported="true">
+        </service>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.cts.comp"
+            android:label="Corp owned managed profile CTS tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml
new file mode 100644
index 0000000..ff086d6
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml
@@ -0,0 +1,4 @@
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+    <uses-policies>
+    </uses-policies>
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java
new file mode 100644
index 0000000..ad52708
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+
+public class AdminReceiver extends DeviceAdminReceiver {
+    // These two apps are built with this source.
+    public static final String COMP_DPC_PACKAGE_NAME = "com.android.cts.comp";
+    public static final String COMP_DPC_2_PACKAGE_NAME = "com.android.cts.comp2";
+
+    public static ComponentName getComponentName(Context context) {
+        return new ComponentName(context, AdminReceiver.class);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java
new file mode 100644
index 0000000..8e1f0e6
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.comp;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for device-owner based tests.
+ */
+public abstract class BaseDeviceOwnerCompTest extends AndroidTestCase {
+
+    protected DevicePolicyManager mDevicePolicyManager;
+    protected List<UserHandle> mOtherProfiles;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertDeviceOwner(mDevicePolicyManager);
+
+        // A managed profile must have been created.
+        mOtherProfiles = mContext.getSystemService(UserManager.class)
+                .getUserProfiles();
+        mOtherProfiles.remove(Process.myUserHandle());
+        assertTrue(mOtherProfiles.size() > 0);
+    }
+
+    private void assertDeviceOwner(DevicePolicyManager dpm) {
+        assertNotNull(dpm);
+        assertTrue(dpm.isAdminActive(AdminReceiver.getComponentName(getContext())));
+        assertTrue(dpm.isDeviceOwnerApp(getContext().getPackageName()));
+        assertFalse(dpm.isManagedProfile(AdminReceiver.getComponentName(getContext())));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java
new file mode 100644
index 0000000..6a3eb05
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.comp;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for profile-owner based tests.
+ * <p>
+ * This class handles making sure that the test is the profile owner and that it has an active admin
+ * registered, so that all tests may assume these are done.
+ */
+public class BaseManagedProfileCompTest extends AndroidTestCase {
+
+    protected DevicePolicyManager mDevicePolicyManager;
+    protected List<UserHandle> mOtherProfiles;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDevicePolicyManager = (DevicePolicyManager)
+                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+        assertManagedProfile();
+
+        mOtherProfiles = mContext.getSystemService(UserManager.class)
+                .getUserProfiles();
+        mOtherProfiles.remove(Process.myUserHandle());
+        assertTrue(mOtherProfiles.size() > 0);  // The primary profile should be there.
+    }
+
+    private void assertManagedProfile() {
+        assertNotNull(mDevicePolicyManager);
+        assertTrue(mDevicePolicyManager.isAdminActive(
+                AdminReceiver.getComponentName(getContext())));
+        assertTrue(mDevicePolicyManager.isProfileOwnerApp(getContext().getPackageName()));
+        assertTrue(mDevicePolicyManager.isManagedProfile(
+                AdminReceiver.getComponentName(getContext())));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java
new file mode 100644
index 0000000..3b95b94
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.UserHandle;
+
+/**
+ * Handle the cross user call from the device admin in other side.
+ */
+public class CrossUserService extends Service {
+
+    private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() {
+        public String echo(String msg) {
+            return msg;
+        }
+
+        public UserHandle getUserHandle() {
+            return Process.myUserHandle();
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java
new file mode 100644
index 0000000..935a657
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp;
+
+import android.os.UserHandle;
+
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite;
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite;
+
+import java.util.List;
+
+/**
+ * Testing various scenarios when a device owner tries to bind a service from profile owner.
+ */
+public class DeviceOwnerBindDeviceAdminServiceTest extends BaseDeviceOwnerCompTest {
+
+    public void testBindDeviceAdminServiceForUser_corpOwnedManagedProfile() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+        // COMP mode - DO should be allowed to bind to the managed profile user.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(1, allowedTargetUsers.size());
+        UserHandle managedProfileUserHandle = allowedTargetUsers.get(0);
+        assertTrue(mOtherProfiles.contains(managedProfileUserHandle));
+
+        new BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+                mContext, managedProfileUserHandle)
+                .execute();
+    }
+
+    public void testBindDeviceAdminServiceForUser_byodPlusDeviceOwner() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+        // DO+BYOD mode - the DO and the PO should not be allowed to bind to each other.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(0, allowedTargetUsers.size());
+
+        for (UserHandle userHandle : mOtherProfiles) {
+            new BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+                    mContext, userHandle, AdminReceiver.COMP_DPC_2_PACKAGE_NAME)
+                    .execute();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java
new file mode 100644
index 0000000..e7a9e73
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Dummy service that is exported.
+ */
+public class ExportedCrossUserService extends Service {
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
new file mode 100644
index 0000000..bc8d3d3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp;
+
+interface ICrossUserService {
+    String echo(String msg);
+    android.os.UserHandle getUserHandle();
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java
new file mode 100644
index 0000000..e301a4f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp;
+
+import android.os.UserHandle;
+
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite;
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite;
+
+import java.util.List;
+
+/**
+ * Testing various scenarios when a profile owner from the managed profile tries to bind a service
+ * from the device owner.
+ */
+public class ManagedProfileBindDeviceAdminServiceTest extends BaseManagedProfileCompTest {
+
+    public void testBindDeviceAdminServiceForUser_corpOwnedManagedProfile() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+        // COMP mode - Managed Profile PO should be allowed to bind to the DO.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(1, allowedTargetUsers.size());
+        UserHandle primaryProfileUserHandle = allowedTargetUsers.get(0);
+        assertTrue(mOtherProfiles.contains(primaryProfileUserHandle));
+
+        new BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+                mContext, primaryProfileUserHandle).execute();
+    }
+
+    public void testBindDeviceAdminServiceForUser_byodPlusDeviceOwner() throws Exception {
+        assertEquals(AdminReceiver.COMP_DPC_2_PACKAGE_NAME, mContext.getPackageName());
+
+        // DO+BYOD mode - the DO and the PO should not be allowed to bind to each other.
+        List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+                AdminReceiver.getComponentName(mContext));
+        assertEquals(0, allowedTargetUsers.size());
+
+        for (UserHandle userHandle : mOtherProfiles) {
+            new BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+                    mContext, userHandle, AdminReceiver.COMP_DPC_PACKAGE_NAME)
+                    .execute();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java
new file mode 100644
index 0000000..fe739c1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp.bindservice;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+
+import com.android.cts.comp.AdminReceiver;
+import com.android.cts.comp.CrossUserService;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Test suite for the case that device owner and profile owner are different packages.
+ */
+public class BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite {
+
+    private static final ServiceConnection EMPTY_SERVICE_CONNECTION = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {}
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {}
+    };
+
+    private final Context mContext;
+    private final DevicePolicyManager mDpm;
+    private final String mDpcPackageInOtherSide;
+    private final UserHandle mTargetUserHandle;
+
+    /**
+     * @param context
+     * @param targetUserHandle      Which user are we talking to.
+     * @param dpcPackageInOtherSide The dpc package installed in other side, it must not be this
+     *                              package.
+     */
+    public BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+            Context context, UserHandle targetUserHandle, String dpcPackageInOtherSide) {
+        MoreAsserts.assertNotEqual(context.getPackageName(), dpcPackageInOtherSide);
+        mContext = context;
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+        mDpcPackageInOtherSide = dpcPackageInOtherSide;
+        mTargetUserHandle = targetUserHandle;
+    }
+
+    public void execute() throws Exception {
+        checkCannotBind_deviceOwnerProfileOwnerDifferentPackage();
+        checkCannotBind_talkToNonManagingPackage();
+    }
+
+    /**
+     * Device owner and profile owner try to talk to each other. It should fail as they are
+     * different packages.
+     */
+    private void checkCannotBind_deviceOwnerProfileOwnerDifferentPackage() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent();
+            serviceIntent.setClassName(mDpcPackageInOtherSide, CrossUserService.class.getName());
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex(
+                    "Not allowed to bind to target user id", ex.getMessage());
+        }
+    }
+
+    /**
+     * Talk to our own instance in other end. It should fail as it is not the same app that
+     * is managing that profile.
+     */
+    private void checkCannotBind_talkToNonManagingPackage() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex(
+                    "Not allowed to bind to target user id", ex.getMessage());
+        }
+    }
+
+    private boolean bind(Intent serviceIntent, ServiceConnection serviceConnection,
+            UserHandle userHandle) {
+        return mDpm.bindDeviceAdminServiceAsUser(AdminReceiver.getComponentName(mContext),
+                serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE, userHandle);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java
new file mode 100644
index 0000000..ce9efcf
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.comp.bindservice;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+import com.android.cts.comp.AdminReceiver;
+import com.android.cts.comp.CrossUserService;
+import com.android.cts.comp.ExportedCrossUserService;
+import com.android.cts.comp.ICrossUserService;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+/**
+ * Test suite for the case where we have the same package for both device owner and profile owner.
+ */
+public class BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite {
+    private static final String TAG = "BindServiceTest";
+
+    private static final ServiceConnection EMPTY_SERVICE_CONNECTION = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {}
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {}
+    };
+
+    private final Context mContext;
+    private static final String NON_MANAGING_PACKAGE = AdminReceiver.COMP_DPC_2_PACKAGE_NAME;
+    private final UserHandle mTargetUserHandle;
+    private final DevicePolicyManager mDpm;
+
+    /**
+     * @param context
+     * @param targetUserHandle Which user we are talking to.
+     */
+    public BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+            Context context, UserHandle targetUserHandle) {
+        mContext = context;
+        mTargetUserHandle = targetUserHandle;
+        mDpm = mContext.getSystemService(DevicePolicyManager.class);
+    }
+
+    public void execute() throws Exception {
+        checkCannotBind_exportedCrossUserService();
+        checkCannotBind_nonManagingPackage();
+        checkCannotBind_sameUser();
+        checkCrossProfileCall_echo();
+        checkCrossProfileCall_getUserHandle();
+    }
+
+    /**
+     * Make sure we cannot bind exported service.
+     */
+    private void checkCannotBind_exportedCrossUserService() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent(mContext, ExportedCrossUserService.class);
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex("Invalid intent", ex.getMessage());
+        }
+    }
+
+    /**
+     * Talk to a DPC package that is neither device owner nor profile owner.
+     */
+    private void checkCannotBind_nonManagingPackage() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent();
+            serviceIntent.setClassName(NON_MANAGING_PACKAGE, CrossUserService.class.getName());
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ex) {
+            MoreAsserts.assertContainsRegex("Invalid intent", ex.getMessage());
+        }
+    }
+
+    /**
+     * Talk to the same DPC in same user, that is talking to itself.
+     */
+    private void checkCannotBind_sameUser() throws Exception {
+        try {
+            final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+            bind(serviceIntent, EMPTY_SERVICE_CONNECTION, Process.myUserHandle());
+            fail("IllegalArgumentException should be thrown");
+        } catch (IllegalArgumentException ex) {
+            MoreAsserts.assertContainsRegex("target user id must be different", ex.getMessage());
+        }
+    }
+
+    /**
+     * Send a String to other side and expect the exact same string is echoed back.
+     */
+    private void checkCrossProfileCall_echo() throws Exception {
+        final String ANSWER = "42";
+        assertCrossProfileCall(ANSWER, service -> service.echo(ANSWER), mTargetUserHandle);
+    }
+
+    /**
+     * Make sure we are talking to the target user.
+     */
+    private void checkCrossProfileCall_getUserHandle() throws Exception {
+        assertCrossProfileCall(
+                mTargetUserHandle, service -> service.getUserHandle(), mTargetUserHandle);
+    }
+
+    /**
+     * Convenient method for you to execute a cross user call and assert the return value of it.
+     * @param expected The expected result of the cross user call.
+     * @param callable It is called when the service is bound, use this to make the service call.
+     * @param targetUserHandle Which user are we talking to.
+     * @param <T> The return type of the service call.
+     */
+    private <T> void assertCrossProfileCall(
+            T expected, CrossUserCallable<T> callable, UserHandle targetUserHandle)
+            throws Exception {
+        final LinkedBlockingQueue<ICrossUserService> queue
+                = new LinkedBlockingQueue<ICrossUserService>();
+        final ServiceConnection serviceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                Log.d(TAG, "onServiceConnected is called");
+                queue.add(ICrossUserService.Stub.asInterface(service));
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                Log.d(TAG, "onServiceDisconnected is called");
+            }
+        };
+        final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+        assertTrue(bind(serviceIntent, serviceConnection, targetUserHandle));
+        ICrossUserService service = queue.poll(5, TimeUnit.SECONDS);
+        assertNotNull("binding to the target service timed out", service);
+        try {
+            assertEquals(expected, callable.call(service));
+        } finally {
+            mContext.unbindService(serviceConnection);
+        }
+    }
+
+    private boolean bind(Intent serviceIntent, ServiceConnection serviceConnection,
+            UserHandle userHandle) {
+        return mDpm.bindDeviceAdminServiceAsUser(AdminReceiver.getComponentName(mContext),
+                serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE, userHandle);
+    }
+
+    interface CrossUserCallable<T> {
+        T call(ICrossUserService service) throws RemoteException;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
index 41bb626..91b710e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
@@ -61,6 +61,9 @@
     // IP address reserved for documentation by rfc5737
     public static final String TEST_ADDRESS = "192.0.2.4";
 
+    // HACK (TODO issue 31585407) to wait for the network to actually be usable
+    private static final int NETWORK_SETTLE_GRACE_MS = 200;
+
     private static final int SOCKET_TIMEOUT_MS = 5000;
     private static final int ICMP_ECHO_REQUEST = 0x08;
     private static final int ICMP_ECHO_REPLY = 0x00;
@@ -92,6 +95,7 @@
             if (!vpnLatch.await(NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
                 fail("Took too long waiting to establish a VPN-backed connection");
             }
+            Thread.sleep(NETWORK_SETTLE_GRACE_MS);
         } catch (InterruptedException | PackageManager.NameNotFoundException e) {
             fail("Failed to send ping: " + e);
         } finally {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
new file mode 100644
index 0000000..06873fe
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.deviceowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import java.lang.reflect.Method;
+
+public class AdminActionBookkeepingTest extends BaseDeviceOwnerTest {
+
+    /**
+     * Test: Retrieving security logs should update the corresponding timestamp.
+     */
+    public void testRetrieveSecurityLogs() throws Exception {
+        Thread.sleep(1);
+        final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+
+        long timeBefore = System.currentTimeMillis();
+        mDevicePolicyManager.retrieveSecurityLogs(getWho());
+        long timeAfter = System.currentTimeMillis();
+
+        final long firstTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+        assertTrue(firstTimestamp > previousTimestamp);
+        assertTrue(firstTimestamp >= timeBefore);
+        assertTrue(firstTimestamp <= timeAfter);
+
+        Thread.sleep(2);
+        timeBefore = System.currentTimeMillis();
+        final boolean preBootSecurityLogsRetrieved =
+                mDevicePolicyManager.retrievePreRebootSecurityLogs(getWho()) != null;
+        timeAfter = System.currentTimeMillis();
+
+        final long secondTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+        if (preBootSecurityLogsRetrieved) {
+            // If the device supports pre-boot security logs, verify that retrieving them updates
+            // the timestamp.
+            assertTrue(secondTimestamp > firstTimestamp);
+            assertTrue(secondTimestamp >= timeBefore);
+            assertTrue(secondTimestamp <= timeAfter);
+        } else {
+            // If the device does not support pre-boot security logs, verify that the attempt to
+            // retrieve them does not update the timestamp.
+            assertEquals(firstTimestamp, secondTimestamp);
+        }
+    }
+
+    /**
+     * Test: Requesting a bug report should update the corresponding timestamp.
+     */
+    public void testRequestBugreport() throws Exception {
+        Thread.sleep(1);
+        final long previousTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
+
+        final long timeBefore = System.currentTimeMillis();
+        mDevicePolicyManager.requestBugreport(getWho());
+        final long timeAfter = System.currentTimeMillis();
+
+        final long newTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
+        assertTrue(newTimestamp > previousTimestamp);
+        assertTrue(newTimestamp >= timeBefore);
+        assertTrue(newTimestamp <= timeAfter);
+    }
+
+    /**
+     * Test: Retrieving network logs should update the corresponding timestamp.
+     */
+    public void testGetLastNetworkLogRetrievalTime() throws Exception {
+        Thread.sleep(1);
+        final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+
+        // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+        // un-hiding happens.
+        final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+        setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), true);
+
+        long timeBefore = System.currentTimeMillis();
+        final Method retrieveNetworkLogsMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "retrieveNetworkLogs", ComponentName.class, long.class);
+        retrieveNetworkLogsMethod.invoke(mDevicePolicyManager, getWho(), 0 /* batchToken */);
+        long timeAfter = System.currentTimeMillis();
+
+        final long newTimestamp = mDevicePolicyManager.getLastNetworkLogRetrievalTime();
+        assertTrue(newTimestamp > previousTimestamp);
+        assertTrue(newTimestamp >= timeBefore);
+        assertTrue(newTimestamp <= timeAfter);
+
+        setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), false);
+    }
+
+    /**
+     * Helper that allows the host-side test harness to disable network logging after running the
+     * other tests in this file.
+     */
+    public void testDisablingNetworkLogging() throws Exception {
+        // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+        // un-hiding happens.
+        final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+                "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+        setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), false);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
index 195a18b..a5e8da1 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
@@ -68,7 +68,7 @@
             = new LinkedBlockingQueue();
 
     private TestCallback mCallback;
-    private Object mCallbackLock = new Object();
+    private final Object mCallbackLock = new Object();
     private final Messenger mMessenger = new Messenger(new CheckHandler());
     private final HandlerThread mCallbackThread = new HandlerThread("callback");
 
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java b/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
index 3d2c2ff..7a5dee3 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
+++ b/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.vpnfirewall;
 
+import android.R;
+import android.app.Notification;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -33,6 +35,7 @@
 public class ReflectorVpnService extends VpnService {
 
     private static String TAG = "ReflectorVpnService";
+    private static final int NOTIFICATION_ID = 1;
     private static int MTU = 1799;
 
     private ParcelFileDescriptor mFd = null;
@@ -45,8 +48,13 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
+        // Put ourself in the foreground to stop the system killing us while we wait for orders from
+        // the hostside test.
+        startForeground(NOTIFICATION_ID, new Notification.Builder(this)
+                .setSmallIcon(R.drawable.ic_dialog_alert)
+                .build());
         start();
-        return START_NOT_STICKY;
+        return START_REDELIVER_INTENT;
     }
 
     @Override
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 490afe7..e8bc728 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -136,9 +136,9 @@
     protected void installAppAsUser(String appFileName, boolean grantPermissions, int userId)
             throws FileNotFoundException, DeviceNotAvailableException {
         CLog.d("Installing app " + appFileName + " for user " + userId);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
         String result = getDevice().installPackageForUser(
-                MigrationHelper.getTestFile(mCtsBuild, appFileName), true, grantPermissions,
-                userId, "-t");
+                buildHelper.getTestFile(appFileName), true, grantPermissions, userId, "-t");
         assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
                 result);
     }
@@ -148,7 +148,7 @@
         executeShellCommand("am force-stop --user " + userId + " " + packageName);
     }
 
-    private void executeShellCommand(final String command) throws Exception {
+    protected void executeShellCommand(final String command) throws Exception {
         CLog.d("Starting command " + command);
         String commandOutput = getDevice().executeShellCommand(command);
         CLog.d("Output for command " + command + ": " + commandOutput);
@@ -566,17 +566,25 @@
         }
     }
 
-    protected void enableComponent(int userId, String componentName)
+    /**
+     * Runs pm enable command to enable a package or component. Returns the command result.
+     */
+    protected String enableComponentOrPackage(int userId, String packageOrComponent)
             throws DeviceNotAvailableException {
-        String command = "pm enable --user " + userId + " " + componentName;
-        CLog.d("Output for command " + command + ": "
-                + getDevice().executeShellCommand(command));
+        String command = "pm enable --user " + userId + " " + packageOrComponent;
+        String result = getDevice().executeShellCommand(command);
+        CLog.d("Output for command " + command + ": " + result);
+        return result;
     }
 
-    protected void disableComponent(int userId, String componentName)
+    /**
+     * Runs pm disable command to disable a package or component. Returns the command result.
+     */
+    protected String disableComponentOrPackage(int userId, String packageOrComponent)
             throws DeviceNotAvailableException {
-        String command = "pm disable --user " + userId + " " + componentName;
-        CLog.d("Output for command " + command + ": "
-                + getDevice().executeShellCommand(command));
+        String command = "pm disable --user " + userId + " " + packageOrComponent;
+        String result = getDevice().executeShellCommand(command);
+        CLog.d("Output for command " + command + ": " + result);
+        return result;
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 607795f..bb1811f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,8 +16,8 @@
 
 package com.android.cts.devicepolicy;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.cts.devicepolicy.BaseDevicePolicyTest.Settings;
-import com.android.cts.migration.MigrationHelper;
 
 import java.io.File;
 import java.lang.Exception;
@@ -135,7 +135,8 @@
         if (!mHasFeature) {
             return;
         }
-        final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final File apk = buildHelper.getTestFile(TEST_APP_APK);
         try {
             // Install the test and prepare the test apk.
             installAppAsUser(PACKAGE_INSTALLER_APK, mPrimaryUserId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index fad96ed..036bf40 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -18,12 +18,15 @@
 
 import android.platform.test.annotations.RequiresDevice;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Set of tests for use cases that apply to profile and device owner.
@@ -93,6 +96,9 @@
     private static final String CUSTOMIZATION_APP_PKG = "com.android.cts.customizationapp";
     private static final String CUSTOMIZATION_APP_APK = "CtsCustomizationApp.apk";
 
+    private static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES
+            = "enabled_notification_policy_access_packages";
+
     // ID of the user all tests are run as. For device owner this will be the primary user, for
     // profile owner it is the user id of the created profile.
     protected int mUserId;
@@ -497,7 +503,8 @@
         final String PACKAGE_VERIFIER_ENABLE_SETTING = "package_verifier_enable";
         final String SECURE_SETTING_CATEGORY = "secure";
         final String GLOBAL_SETTING_CATEGORY = "global";
-        final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final File apk = buildHelper.getTestFile(TEST_APP_APK);
         String unknownSourceSetting = null;
         String packageVerifierEnableSetting = null;
         String packageVerifierUserConsentSetting = null;
@@ -556,7 +563,13 @@
         if (!mHasFeature) {
             return;
         }
-        executeDeviceTestClass(".AudioRestrictionTest");
+        // This package may need to toggle zen mode for this test, so allow it to do so.
+        allowNotificationPolicyAccess(DEVICE_ADMIN_PKG, mUserId);
+        try {
+            executeDeviceTestClass(".AudioRestrictionTest");
+        } finally {
+            disallowNotificationPolicyAccess(DEVICE_ADMIN_PKG, mUserId);
+        }
     }
 
     public void testSuspendPackage() throws Exception {
@@ -585,7 +598,8 @@
     }
 
     public void testCannotRemoveUserIfRestrictionSet() throws Exception {
-        if (!mHasFeature || !canCreateAdditionalUsers(1)) {
+        // Outside of the primary user, setting DISALLOW_REMOVE_USER would not work.
+        if (!mHasFeature || !canCreateAdditionalUsers(1) || mUserId != getPrimaryUser()) {
             return;
         }
         final int userId = createUser();
@@ -600,6 +614,31 @@
         }
     }
 
+    public void testCannotEnableOrDisableDeviceOwnerOrProfileOwner() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        // Try to disable a component in device owner/ profile owner.
+        String result = disableComponentOrPackage(
+                mUserId, DEVICE_ADMIN_PKG + "/.SetPolicyActivity");
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+        // Try to disable the device owner/ profile owner package.
+        result = disableComponentOrPackage(mUserId, DEVICE_ADMIN_PKG);
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+        // Try to enable a component in device owner/ profile owner.
+        result = enableComponentOrPackage(
+                mUserId, DEVICE_ADMIN_PKG + "/.SetPolicyActivity");
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+        // Try to enable the device owner/ profile owner package.
+        result = enableComponentOrPackage(mUserId, DEVICE_ADMIN_PKG);
+        assertTrue("Should throw SecurityException",
+                result.contains("java.lang.SecurityException"));
+
+    }
+
     protected void executeDeviceTestClass(String className) throws Exception {
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId);
     }
@@ -695,4 +734,46 @@
                 : "testScreenCapturePossible";
         executeDeviceTestMethod(".ScreenCaptureDisabledTest", testMethodName);
     }
+
+    /**
+     * Allows packageName to manage notification policy configuration, which
+     * includes toggling zen mode.
+     */
+    private void allowNotificationPolicyAccess(String packageName, int userId)
+            throws DeviceNotAvailableException {
+        List<String> enabledPackages = getEnabledNotificationPolicyPackages(userId);
+        if (!enabledPackages.contains(packageName)) {
+            enabledPackages.add(packageName);
+            setEnabledNotificationPolicyPackages(enabledPackages, userId);
+        }
+    }
+
+    /**
+     * Disallows packageName to manage notification policy configuration, which
+     * includes toggling zen mode.
+     */
+    private void disallowNotificationPolicyAccess(String packageName, int userId)
+            throws DeviceNotAvailableException {
+        List<String> enabledPackages = getEnabledNotificationPolicyPackages(userId);
+        if (enabledPackages.contains(packageName)) {
+            enabledPackages.remove(packageName);
+            setEnabledNotificationPolicyPackages(enabledPackages, userId);
+        }
+    }
+
+    private void setEnabledNotificationPolicyPackages(List<String> packages, int userId)
+            throws DeviceNotAvailableException {
+        getDevice().setSetting(userId, "secure", ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+                String.join(":", packages));
+    }
+
+    private List<String> getEnabledNotificationPolicyPackages(int userId)
+            throws DeviceNotAvailableException {
+        String settingValue = getDevice().getSetting(userId, "secure",
+                ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+        if (settingValue == null) {
+            return new ArrayList<String>();
+        }
+        return new ArrayList<String>(Arrays.asList(settingValue.split(":|\n")));
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java
new file mode 100644
index 0000000..9c4018d
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.devicepolicy;
+
+/**
+ * Tests for having both device owner and profile owner. Device owner is setup for you in
+ * {@link #setUp()} and it is always the {@link #COMP_DPC_PKG}. You are required to call
+ * {@link #createManagedProfile(int)} yourself to create managed profile on each test case.
+ */
+public class DeviceOwnerPlusManagedProfileTest extends BaseDevicePolicyTest {
+    private static final String DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST =
+            "com.android.cts.comp.DeviceOwnerBindDeviceAdminServiceTest";
+    private static final String MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST =
+            "com.android.cts.comp.ManagedProfileBindDeviceAdminServiceTest";
+
+    private int mProfileUserId;
+
+    private static final String COMP_DPC_PKG = "com.android.cts.comp";
+    private static final String COMP_DPC_APK = "CtsCorpOwnedManagedProfile.apk";
+    private static final String COMP_DPC_ADMIN =
+            COMP_DPC_PKG + "/com.android.cts.comp.AdminReceiver";
+    private static final String COMP_DPC_PKG2 = "com.android.cts.comp2";
+    private static final String COMP_DPC_APK2 = "CtsCorpOwnedManagedProfile2.apk";
+    private static final String COMP_DPC_ADMIN2 =
+            COMP_DPC_PKG2 + "/com.android.cts.comp.AdminReceiver";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // We need managed user to be supported in order to create a profile of the user owner.
+        mHasFeature = mHasFeature && hasDeviceFeature("android.software.managed_users");
+        if (mHasFeature) {
+            // Set device owner.
+            installAppAsUser(COMP_DPC_APK, mPrimaryUserId);
+            if (!setDeviceOwner(COMP_DPC_ADMIN, mPrimaryUserId, /*expectFailure*/ false)) {
+                removeAdmin(COMP_DPC_ADMIN, mPrimaryUserId);
+                fail("Failed to set device owner");
+            }
+        }
+    }
+
+    /**
+     * Both device owner and profile are the same package ({@link #COMP_DPC_PKG}).
+     */
+    public void testBindDeviceAdminServiceAsUser_corpOwnedManagedProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        setupManagedProfile(COMP_DPC_APK, COMP_DPC_ADMIN);
+        // Installing a non managing app (neither device owner nor profile owner).
+        installAppAsUser(COMP_DPC_APK2, mPrimaryUserId);
+        installAppAsUser(COMP_DPC_APK2, mProfileUserId);
+
+        // Testing device owner -> profile owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_corpOwnedManagedProfile",
+                mPrimaryUserId);
+        // Testing profile owner -> device owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_corpOwnedManagedProfile",
+                mProfileUserId);
+    }
+
+    /**
+     * Device owner is {@link #COMP_DPC_PKG} while profile owner is {@link #COMP_DPC_PKG2}.
+     */
+    public void testBindDeviceAdminServiceAsUser_byodPlusDeviceOwner() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        setupManagedProfile(COMP_DPC_APK2, COMP_DPC_ADMIN2);
+        // Testing device owner -> profile owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG,
+                DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_byodPlusDeviceOwner",
+                mPrimaryUserId);
+        // Testing profile owner -> device owner.
+        runDeviceTestsAsUser(
+                COMP_DPC_PKG2,
+                MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST,
+                "testBindDeviceAdminServiceForUser_byodPlusDeviceOwner",
+                mProfileUserId);
+    }
+
+    protected void setupManagedProfile(String apkName, String adminReceiverClassName)
+            throws Exception {
+        mProfileUserId = createManagedProfile(mPrimaryUserId);
+        installAppAsUser(apkName, mProfileUserId);
+        setProfileOwnerOrFail(adminReceiverClassName, mProfileUserId);
+        startUser(mProfileUserId);
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 2a4c77f..3c31fd8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -324,6 +324,12 @@
         try {
             installAppAsUser(INTENT_RECEIVER_APK, mPrimaryUserId);
             executeDeviceOwnerTest("LockTaskTest");
+        } catch (AssertionError ex) {
+            // STOPSHIP(b/32771855), remove this once we fixed the bug.
+            executeShellCommand("dumpsys activity activities");
+            executeShellCommand("dumpsys window -a");
+            executeShellCommand("dumpsys activity service com.android.systemui");
+            throw ex;
         } finally {
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
         }
@@ -400,6 +406,19 @@
                 "testIsProvisioningAllowedTrueForManagedProfileAction");
     }
 
+    public void testAdminActionBookkeeping() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            executeDeviceOwnerTest("AdminActionBookkeepingTest");
+        } finally {
+            // Always attempt to disable network logging to bring the device to initial state.
+            executeDeviceTestMethod(".AdminActionBookkeepingTest", "testDisablingNetworkLogging");
+        }
+    }
+
     private void executeDeviceOwnerTest(String testClassName) throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index a05b2b3..d479868 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -260,20 +260,20 @@
         // allow_parent_profile_app_linking is not set, try different enabled state combinations.
         // We should not have app link handler in parent user no matter whether it is enabled.
 
-        disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testReceivedByBrowserActivityInManaged");
 
-        enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testReceivedByBrowserActivityInManaged");
 
-        disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testTwoReceivers");
 
-        enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testTwoReceivers");
 
         // We now set allow_parent_profile_app_linking, and hence we should have the app handler
@@ -281,20 +281,20 @@
         changeUserRestrictionForUser("allow_parent_profile_app_linking", ADD_RESTRICTION_COMMAND,
                 mProfileUserId);
 
-        disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testReceivedByBrowserActivityInManaged");
 
-        enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testTwoReceivers");
 
-        disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testTwoReceivers");
 
-        enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
-        enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+        enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
         assertAppLinkResult("testThreeReceivers");
     }
 
diff --git a/hostsidetests/dumpsys/Android.mk b/hostsidetests/dumpsys/Android.mk
index 9de0e9c..8a3470f 100644
--- a/hostsidetests/dumpsys/Android.mk
+++ b/hostsidetests/dumpsys/Android.mk
@@ -21,9 +21,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsDumpsysHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.dumpsys
 
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index fee107e..acfc72d 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -16,7 +16,7 @@
 
 package android.dumpsys.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -876,7 +876,8 @@
             getDevice().uninstallPackage(TEST_PKG);
 
             // install the test app
-            File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+            CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+            File testAppFile = buildHelper.getTestFile(TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
                     String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
index 338a7ae..3c8ead8 100644
--- a/hostsidetests/jdwpsecurity/Android.mk
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -23,9 +23,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsJdwpSecurityHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
index 186728c..a5570af 100644
--- a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -16,7 +16,7 @@
 
 package android.jdwpsecurity.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -85,7 +85,8 @@
         getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
 
         // Push jar file.
-        File jarFile = MigrationHelper.getTestFile(mBuildInfo, DEVICE_JAR_FILENAME);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        File jarFile = buildHelper.getTestFile(DEVICE_JAR_FILENAME);
         boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
         assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
     }
diff --git a/hostsidetests/monkey/Android.mk b/hostsidetests/monkey/Android.mk
index 14462d0..7c7ecb5 100644
--- a/hostsidetests/monkey/Android.mk
+++ b/hostsidetests/monkey/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_MODULE := CtsMonkeyTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 # prefix zzz intentional to run this last
 LOCAL_CTS_TEST_PACKAGE := zzz.android.monkey
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
index e601593..5f22b62 100755
--- a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
@@ -1,6 +1,6 @@
 package com.android.cts.monkey;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -41,9 +41,10 @@
         super.setUp();
         mDevice = getDevice();
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
         for (int i = 0; i < PKGS.length; i++) {
             mDevice.uninstallPackage(PKGS[i]);
-            File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+            File app = buildHelper.getTestFile(APKS[i]);
             mDevice.installPackage(app, false, options);
         }
         clearLogCat();
diff --git a/hostsidetests/multiuser/Android.mk b/hostsidetests/multiuser/Android.mk
index 1a324fb..ec18912 100644
--- a/hostsidetests/multiuser/Android.mk
+++ b/hostsidetests/multiuser/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.multiuser
 
@@ -34,4 +32,4 @@
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/net/Android.mk b/hostsidetests/net/Android.mk
index ad97ecd..1c3f053 100644
--- a/hostsidetests/net/Android.mk
+++ b/hostsidetests/net/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsHostsideNetworkTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork
 
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
index 6642512..f3d7dbd 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.net;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
@@ -80,7 +80,8 @@
 
     protected void installPackage(String apk) throws FileNotFoundException,
             DeviceNotAvailableException {
-        assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, apk), false));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false));
     }
 
     protected void uninstallPackage(String packageName, boolean shouldSucceed)
diff --git a/hostsidetests/numberblocking/Android.mk b/hostsidetests/numberblocking/Android.mk
index bf2d045..42c7169 100644
--- a/hostsidetests/numberblocking/Android.mk
+++ b/hostsidetests/numberblocking/Android.mk
@@ -25,9 +25,7 @@
 
 LOCAL_MODULE := CtsHostsideNumberBlockingTestCases
 
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
index 11455a0..5e1a0ec 100644
--- a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
+++ b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
@@ -16,7 +16,7 @@
 
 package com.android.cts.numberblocking.hostside;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.tradefed.build.IBuildInfo;
@@ -149,7 +149,8 @@
 
     private void installTestAppForUser(int userId) throws Exception {
         LogUtil.CLog.logAndDisplay(Log.LogLevel.INFO, "Installing test app for user: " + userId);
-        File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        File testAppFile = buildHelper.getTestFile(TEST_APK);
         String installResult = getDevice().installPackageForUser(
                 testAppFile, true /*reinstall*/, userId);
         assertNull(String.format(
diff --git a/hostsidetests/os/Android.mk b/hostsidetests/os/Android.mk
index bb5154f..e54703e 100644
--- a/hostsidetests/os/Android.mk
+++ b/hostsidetests/os/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.os
 
diff --git a/hostsidetests/os/src/android/os/cts/OsHostTests.java b/hostsidetests/os/src/android/os/cts/OsHostTests.java
index 52a375d..3b2e027 100644
--- a/hostsidetests/os/src/android/os/cts/OsHostTests.java
+++ b/hostsidetests/os/src/android/os/cts/OsHostTests.java
@@ -16,7 +16,7 @@
 
 package android.os.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.ITestDevice;
@@ -145,6 +145,7 @@
      * Helper: find a test apk
      */
     private File getTestAppFile(String fileName) throws FileNotFoundException {
-        return MigrationHelper.getTestFile(mCtsBuild, fileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        return buildHelper.getTestFile(fileName);
     }
 }
diff --git a/hostsidetests/retaildemo/Android.mk b/hostsidetests/retaildemo/Android.mk
index 52208ec..ba106cc 100644
--- a/hostsidetests/retaildemo/Android.mk
+++ b/hostsidetests/retaildemo/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_JAVA_LIBRARIES := \
     tools-common-prebuilt \
     cts-tradefed \
-    tradefed-prebuilt
+    tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.retaildemo
 
diff --git a/hostsidetests/sample/Android.mk b/hostsidetests/sample/Android.mk
index 8d8a076..bfdaeda 100644
--- a/hostsidetests/sample/Android.mk
+++ b/hostsidetests/sample/Android.mk
@@ -25,7 +25,7 @@
 
 LOCAL_MODULE := CtsSampleHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index 85492de..7943785 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -28,9 +28,7 @@
 
 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.security
 
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index a8c35d2..f304607 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.RestrictedBuildTest;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -111,7 +111,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        sepolicyAnalyze = buildHelper.getTestFile("sepolicy-analyze");
         sepolicyAnalyze.setExecutable(true);
 
         /* obtain sepolicy file from running device */
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
index 703895a..ff9e62b 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
 
 LOCAL_CTS_TEST_PACKAGE := android.server
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index e10e288..06fd7da 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -19,6 +19,9 @@
           xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
           package="android.server.cts">
 
+    <!-- virtual display test permissions -->
+    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
+
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
     <application>
@@ -163,6 +166,9 @@
         <activity android:name=".TurnScreenOnActivity"
                   android:exported="true"
         />
+        <activity android:name=".TurnScreenOnDismissKeyguardActivity"
+            android:exported="true"
+        />
         <activity android:name=".SingleTaskActivity"
             android:exported="true"
             android:launchMode="singleTask"
@@ -221,6 +227,9 @@
         <activity android:name=".DismissKeyguardActivity"
                   android:exported="true"
         />
+        <activity android:name=".DismissKeyguardMethodActivity"
+            android:exported="true"
+        />
         <activity android:name=".WallpaperActivity"
             android:exported="true"
             android:theme="@style/WallpaperTheme"
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index 71ed5f5..119f7bc 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -58,7 +58,8 @@
                 " size=" + buildCoordString(config.screenWidthDp, config.screenHeightDp) +
                 " displaySize=" + buildCoordString(point.x, point.y) +
                 " metricsSize=" + buildCoordString(metrics.widthPixels, metrics.heightPixels) +
-                " smallestScreenWidth=" + config.smallestScreenWidthDp;
+                " smallestScreenWidth=" + config.smallestScreenWidthDp +
+                " densityDpi=" + config.densityDpi;
 
         Log.i(getTag(), line);
     }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
index d77f8af..6dab9dd 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -64,6 +65,10 @@
             if (extras.getBoolean("dismissKeyguard")) {
                 getWindow().addFlags(FLAG_DISMISS_KEYGUARD);
             }
+            if (extras.getBoolean("dismissKeyguardMethod")) {
+                getSystemService(KeyguardManager.class).dismissKeyguard(
+                        BroadcastReceiverActivity.this, new KeyguardDismissLoggerCallback(), null);
+            }
         }
     }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java
new file mode 100644
index 0000000..18228e7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.cts;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.app.KeyguardManager.KeyguardDismissCallback;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+public class DismissKeyguardMethodActivity extends Activity {
+
+    private final String TAG = "DismissKeyguardMethodActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getSystemService(KeyguardManager.class).dismissKeyguard(this,
+                new KeyguardDismissLoggerCallback(), null);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java
new file mode 100644
index 0000000..efc0c79
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.cts;
+
+import android.app.KeyguardManager;
+import android.app.KeyguardManager.KeyguardDismissCallback;
+import android.util.Log;
+
+public class KeyguardDismissLoggerCallback extends KeyguardDismissCallback {
+
+    private final String TAG = "KeyguardDismissLoggerCallback";
+
+    @Override
+    public void onDismissError() {
+        Log.i(TAG, "onDismissError");
+    }
+
+    @Override
+    public void onDismissSucceeded() {
+        Log.i(TAG, "onDismissSucceeded");
+    }
+
+    @Override
+    public void onDismissCancelled() {
+        Log.i(TAG, "onDismissCancelled");
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
index bf77276..8d1d358 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
@@ -21,6 +21,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
 import android.app.Activity;
+import android.app.ActivityOptions;
 import android.content.Intent;
 import android.content.ComponentName;
 import android.net.Uri;
@@ -59,10 +60,16 @@
                         .build();
                 newIntent.setData(data);
             }
-        } else {
-            // We're all set, just launch.
         }
 
-        startActivity(newIntent);
+        ActivityOptions options = null;
+        final int displayId = extras.getInt("display_id", -1);
+        if (displayId != -1) {
+            options = ActivityOptions.makeBasic();
+            options.setLaunchDisplayId(displayId);
+            newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+        }
+
+        startActivity(newIntent, options != null ? options.toBundle() : null);
     }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java
new file mode 100644
index 0000000..9d262a7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.cts;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class TurnScreenOnDismissKeyguardActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+        getSystemService(KeyguardManager.class).dismissKeyguard(this,
+                new KeyguardDismissLoggerCallback(), null);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
index 05f7b91..38e0d61 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
@@ -37,7 +37,7 @@
     private static final String TAG = "VirtualDisplayActivity";
 
     private static final int DEFAULT_DENSITY_DPI = 160;
-    private static final String KEY_DENSITY_DPI = "densityDpi";
+    private static final String KEY_DENSITY_DPI = "density_dpi";
 
     private DisplayManager mDisplayManager;
     private VirtualDisplay mVirtualDisplay;
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
index 856bd58..9c909c2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -41,6 +41,11 @@
         executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
         mAmWmState.waitForHomeActivityVisible(mDevice);
 
+        /* TODO: Find a proper way to wait until launcher activity
+         * becomes fully visible. It appears that both VisibleBehindActivity
+         * and home activity are visible at some point before the former
+         * disappears.*/
+        Thread.sleep(3000);
         mAmWmState.computeState(mDevice, null);
         mAmWmState.assertContainsStack(
                 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
@@ -124,7 +129,9 @@
 
     public void testTranslucentActivityOverDockedStack() throws Exception {
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
         launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME, TEST_ACTIVITY_NAME});
         launchActivityInStack(TRANSLUCENT_ACTIVITY_NAME, DOCKED_STACK_ID);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME,
                 TRANSLUCENT_ACTIVITY_NAME}, false /* compareTaskAndStackBounds */);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
index 8b77ff4..2c733d1 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -25,6 +25,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
 import static android.server.cts.StateLogger.log;
 
 /**
@@ -34,75 +35,229 @@
 public class ActivityManagerDisplayTests extends ActivityManagerTestBase {
     private static final String DUMPSYS_ACTIVITY_PROCESSES = "dumpsys activity processes";
 
+    private static final String TEST_ACTIVITY_NAME = "TestActivity";
     private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
 
+    private static final int INVALID_DENSITY_DPI = -1;
     private static final int CUSTOM_DENSITY_DPI = 222;
 
     /** Temp storage used for parsing. */
     private final LinkedList<String> mDumpLines = new LinkedList<>();
 
+    private boolean mVirtualDisplayCreated;
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mVirtualDisplayCreated) {
+            executeShellCommand(getDestroyVirtualDisplayCommand());
+        }
+        super.tearDown();
+    }
+
     /**
      * Tests that the global configuration is equal to the default display's override configuration.
      */
     public void testDefaultDisplayOverrideConfiguration() throws Exception {
-        final DisplaysState ds = getDisplaysStates();
-        assertNotNull("Global configuration must not be empty.", ds.mGlobalConfig);
-        final String primaryDisplayOverrideConfig = ds.mDisplayConfigs.get(0);
+        final ReportedDisplays reportedDisplays = getDisplaysStates();
+        assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig);
+        final DisplayState primaryDisplay = reportedDisplays.getDisplayState(DEFAULT_DISPLAY_ID);
         assertEquals("Primary display's configuration should not be equal to global configuration.",
-                ds.mGlobalConfig, primaryDisplayOverrideConfig);
+                reportedDisplays.mGlobalConfig, primaryDisplay.mOverrideConfig);
     }
 
     /**
      * Tests that secondary display has override configuration set.
      */
     public void testCreateVirtualDisplayWithCustomConfig() throws Exception {
-        // Start an activity that is able to create virtual displays.
-        executeShellCommand(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
-        mAmWmState.computeState(mDevice, new String[] { VIRTUAL_DISPLAY_ACTIVITY },
-                false /* compareTaskAndStackBounds */);
-        final DisplaysState originalDS = getDisplaysStates();
-        final int originalDisplayCount = originalDS.mDisplayConfigs.size();
-
-        // Create virtual display with custom density dpi.
-        executeShellCommand(getCreateVirtualDisplayCommand(CUSTOM_DENSITY_DPI));
-
-        // Wait for the virtual display to be created and get configurations.
-        DisplaysState ds = getDisplaysStateAfterCreation(originalDisplayCount + 1);
-        assertEquals("New virtual display should be created",
-                originalDisplayCount + 1, ds.mDisplayConfigs.size());
-
-        // Find the id of newly added display.
-        int newDisplayId = -1;
-        for (Integer displayId : ds.mDisplayConfigs.keySet()) {
-            if (!originalDS.mDisplayConfigs.containsKey(displayId)) {
-                newDisplayId = displayId;
-                break;
-            }
-        }
-        assertFalse(-1 == newDisplayId);
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
 
         // Find the density of created display.
-        final String newDisplayConfig = ds.mDisplayConfigs.get(newDisplayId);
-        final String[] configParts = newDisplayConfig.split(" ");
-        int newDensityDpi = -1;
-        for (String part : configParts) {
-            if (part.endsWith("dpi")) {
-                final String densityDpiString = part.substring(0, part.length() - 3);
-                newDensityDpi = Integer.parseInt(densityDpiString);
-                break;
-            }
-        }
+        final int newDensityDpi = newDisplay.getDpi();
         assertEquals(CUSTOM_DENSITY_DPI, newDensityDpi);
 
         // Destroy the created display.
         executeShellCommand(getDestroyVirtualDisplayCommand());
     }
 
-    private DisplaysState getDisplaysStateAfterCreation(int expectedDisplayCount)
-            throws DeviceNotAvailableException {
-        DisplaysState ds = getDisplaysStates();
+    /**
+     * Tests launching an activity on virtual display.
+     */
+    public void testLaunchActivityOnSecondaryDisplay() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
 
-        while (ds.mDisplayConfigs.size() != expectedDisplayCount) {
+        // Launch activity on new secondary display.
+        executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME, newDisplay.mDisplayId));
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                TEST_ACTIVITY_NAME);
+
+        // Check that activity is on the right display.
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Activity launched on secondary display must be resumed",
+                getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+
+        // Check that activity config corresponds to display config.
+        final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME);
+        assertEquals("Activity launched on secondary display must have proper configuration",
+                CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
+    }
+
+    /**
+     * Tests launching an activity on virtual display and then launching another activity via shell
+     * command and without specifying the display id - it must appear on the same external display.
+     */
+    public void testConsequentLaunchActivity() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+        // Launch activity on new secondary display.
+        executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME, newDisplay.mDisplayId));
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                TEST_ACTIVITY_NAME);
+
+        // Launch second activity without specifying display.
+        executeShellCommand(getAmStartCmd(LAUNCHING_ACTIVITY));
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        // Check that activity is launched in focused stack on external display.
+        mAmWmState.assertFocusedActivity("Launched activity must be focused", LAUNCHING_ACTIVITY);
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be resumed in front stack",
+                getActivityComponentName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+    }
+
+    /**
+     * Tests launching an activity on virtual display and then launching another activity from the
+     * first one - it must appear on the secondary display, because it was launched from there.
+     */
+    public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception {
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+        // Launch activity on new secondary display.
+        executeShellCommand(getAmStartCmd(LAUNCHING_ACTIVITY, newDisplay.mDisplayId));
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be resumed",
+                LAUNCHING_ACTIVITY);
+
+        // Launch second activity from app on secondary display without specifying display id.
+        launchActivity(false /* toSide */, false /* randomData */, false /* multipleTask */,
+                TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+        // Check that activity is launched in focused stack on external display.
+        mAmWmState.assertFocusedActivity("Launched activity must be focused", TEST_ACTIVITY_NAME);
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be resumed in front stack",
+                getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+    }
+
+    /**
+     * Tests launching an activity to secondary display from activity on primary display.
+     */
+    public void testLaunchActivityFromAppToSecondaryDisplay() throws Exception {
+        // Start launching activity.
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        // Create new virtual display.
+        final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI,
+                true /* launchInSplitScreen */);
+
+        // Launch activity on secondary display from the app on primary display.
+        launchActivity(false /* toSide */, false /* randomData */, false /* multipleTask*/,
+                TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
+
+        // Check that activity is launched on external display.
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+                TEST_ACTIVITY_NAME);
+        final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+        final ActivityManagerState.ActivityStack frontStack
+                = mAmWmState.getAmState().getStackById(frontStackId);
+        assertEquals("Launched activity must be resumed in front stack",
+                getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+        assertEquals("Front stack must be on external display",
+                newDisplay.mDisplayId, frontStack.mDisplayId);
+    }
+
+    /** Find the display that was not originally reported in oldDisplays and added in newDisplays */
+    private DisplayState findNewDisplayId(ReportedDisplays oldDisplays,
+            ReportedDisplays newDisplays) {
+        for (Integer displayId : newDisplays.mDisplayStates.keySet()) {
+            if (!oldDisplays.mDisplayStates.containsKey(displayId)) {
+                return newDisplays.getDisplayState(displayId);
+            }
+        }
+
+        return null;
+    }
+
+    /** Create new virtual display with custom density. */
+    private DisplayState createVirtualDisplay(int densityDpi) throws Exception {
+        return createVirtualDisplay(densityDpi, false /* launchInSplitScreen */);
+    }
+
+    /**
+     * Create new virtual display.
+     * @param densityDpi provide custom density for the display.
+     * @param launchInSplitScreen start {@link VirtualDisplayActivity} to side from
+     *                            {@link LaunchingActivity} on primary display.
+     * @return {@link DisplayState} of newly created display.
+     * @throws Exception
+     */
+    private DisplayState createVirtualDisplay(int densityDpi,
+            boolean launchInSplitScreen) throws Exception {
+        // Start an activity that is able to create virtual displays.
+        if (launchInSplitScreen) {
+            launchActivityToSide(false /* randomData */, false /* multipleTaskFlag */,
+                    VIRTUAL_DISPLAY_ACTIVITY);
+        } else {
+            executeShellCommand(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+        }
+        mAmWmState.computeState(mDevice, new String[] {VIRTUAL_DISPLAY_ACTIVITY},
+                false /* compareTaskAndStackBounds */);
+        final ReportedDisplays originalDS = getDisplaysStates();
+        final int originalDisplayCount = originalDS.mDisplayStates.size();
+
+        // Create virtual display with custom density dpi.
+        executeShellCommand(getCreateVirtualDisplayCommand(densityDpi));
+        mVirtualDisplayCreated = true;
+
+        // Wait for the virtual display to be created and get configurations.
+        final ReportedDisplays ds = getDisplaysStateAfterCreation(originalDisplayCount + 1);
+        assertEquals("New virtual display must be created",
+                originalDisplayCount + 1, ds.mDisplayStates.size());
+
+        // Find the newly added display.
+        final DisplayState newDisplay = findNewDisplayId(originalDS, ds);
+        assertNotNull("New virtual display must be created", newDisplay);
+
+        return newDisplay;
+    }
+
+    /** Wait for provided number of displays and report their configurations. */
+    private ReportedDisplays getDisplaysStateAfterCreation(int expectedDisplayCount)
+            throws DeviceNotAvailableException {
+        ReportedDisplays ds = getDisplaysStates();
+
+        while (!ds.isValidState(expectedDisplayCount)) {
             log("***Waiting for the correct number of displays...");
             try {
                 Thread.sleep(1000);
@@ -115,7 +270,7 @@
         return ds;
     }
 
-    private DisplaysState getDisplaysStates() throws DeviceNotAvailableException {
+    private ReportedDisplays getDisplaysStates() throws DeviceNotAvailableException {
         final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(DUMPSYS_ACTIVITY_PROCESSES, outputReceiver);
         String dump = outputReceiver.getOutput();
@@ -123,11 +278,34 @@
 
         Collections.addAll(mDumpLines, dump.split("\\n"));
 
-        return DisplaysState.create(mDumpLines);
+        return ReportedDisplays.create(mDumpLines);
     }
 
     /** Contains the configurations applied to attached displays. */
-    private static final class DisplaysState {
+    private static final class DisplayState {
+        private int mDisplayId;
+        private String mOverrideConfig;
+
+        private DisplayState(int displayId, String overrideConfig) {
+            mDisplayId = displayId;
+            mOverrideConfig = overrideConfig;
+        }
+
+        private int getDpi() {
+            final String[] configParts = mOverrideConfig.split(" ");
+            for (String part : configParts) {
+                if (part.endsWith("dpi")) {
+                    final String densityDpiString = part.substring(0, part.length() - 3);
+                    return Integer.parseInt(densityDpiString);
+                }
+            }
+
+            return -1;
+        }
+    }
+
+    /** Contains the configurations applied to attached displays. */
+    private static final class ReportedDisplays {
         private static final Pattern sGlobalConfigurationPattern =
                 Pattern.compile("mGlobalConfiguration: (\\{.*\\})");
         private static final Pattern sDisplayOverrideConfigurationsPattern =
@@ -136,10 +314,10 @@
                 Pattern.compile("(\\d+): (\\{.*\\})");
 
         private String mGlobalConfig;
-        private Map<Integer, String> mDisplayConfigs = new HashMap<>();
+        private Map<Integer, DisplayState> mDisplayStates = new HashMap<>();
 
-        static DisplaysState create(LinkedList<String> dump) {
-            final DisplaysState result = new DisplaysState();
+        static ReportedDisplays create(LinkedList<String> dump) {
+            final ReportedDisplays result = new ReportedDisplays();
 
             while (!dump.isEmpty()) {
                 final String line = dump.pop().trim();
@@ -147,13 +325,14 @@
                 Matcher matcher = sDisplayOverrideConfigurationsPattern.matcher(line);
                 if (matcher.matches()) {
                     log(line);
-                    while (DisplaysState.shouldContinueExtracting(dump, sDisplayConfigPattern)) {
+                    while (ReportedDisplays.shouldContinueExtracting(dump, sDisplayConfigPattern)) {
                         final String displayOverrideConfigLine = dump.pop().trim();
                         log(displayOverrideConfigLine);
                         matcher = sDisplayConfigPattern.matcher(displayOverrideConfigLine);
                         matcher.matches();
                         final Integer displayId = Integer.valueOf(matcher.group(1));
-                        result.mDisplayConfigs.put(displayId, matcher.group(2));
+                        result.mDisplayStates.put(displayId,
+                                new DisplayState(displayId, matcher.group(2)));
                     }
                     continue;
                 }
@@ -177,14 +356,34 @@
             final String line = dump.peek().trim();
             return matchingPattern.matcher(line).matches();
         }
+
+        DisplayState getDisplayState(int displayId) {
+            return mDisplayStates.get(displayId);
+        }
+
+        /** Check if reported state is valid. */
+        boolean isValidState(int expectedDisplayCount) {
+            if (mDisplayStates.size() != expectedDisplayCount) {
+                return false;
+            }
+
+            for (Map.Entry<Integer, DisplayState> entry : mDisplayStates.entrySet()) {
+                final DisplayState ds = entry.getValue();
+                if (ds.mDisplayId != DEFAULT_DISPLAY_ID && ds.getDpi() == -1) {
+                    return false;
+                }
+            }
+            return true;
+        }
     }
 
     private static String getCreateVirtualDisplayCommand(int densityDpi) {
-        StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+        final StringBuilder commandBuilder
+                = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
         commandBuilder.append(" -f 0x20000000");
         commandBuilder.append(" --es command create_display");
-        if (densityDpi != -1) {
-            commandBuilder.append(" --ei densityDpi ").append(densityDpi);
+        if (densityDpi != INVALID_DENSITY_DPI) {
+            commandBuilder.append(" --ei density_dpi ").append(densityDpi);
         }
         return commandBuilder.toString();
     }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index c305bb1..0cc9ace 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -62,9 +62,9 @@
 
     public void testLaunchToSide() throws Exception {
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         launchActivityToSide();
-        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME});
-
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
         mAmWmState.assertContainsStack(
                 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
         mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
@@ -74,6 +74,7 @@
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME};
         final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME};
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
 
         // Launch activity to side.
         launchActivityToSide();
@@ -106,7 +107,9 @@
 
     public void testLaunchToSideMultiple() throws Exception {
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        final String[] waitForActivitiesVisible =
+            new String[] {TEST_ACTIVITY_NAME, LAUNCHING_ACTIVITY};
 
         // Launch activity to side.
         launchActivityToSide();
@@ -145,11 +148,16 @@
     private void launchTargetToSide(String targetActivityName,
                                     boolean taskCountMustIncrement) throws Exception {
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        final String[] waitForActivitiesVisible = new String[] {targetActivityName};
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+        final String[] waitForActivitiesVisible =
+            new String[] {targetActivityName, LAUNCHING_ACTIVITY};
 
         // Launch activity to side with data.
         launchActivityToSide(true, false, targetActivityName);
         mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        mAmWmState.assertContainsStack(
+                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
         int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
                 .getTasks().size();
         mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
@@ -195,7 +203,9 @@
 
     public void testLaunchToSideMultipleWithFlag() throws Exception {
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
-        final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+        final String[] waitForActivitiesVisible =
+            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
 
         // Launch activity to side.
         launchActivityToSide();
@@ -222,15 +232,17 @@
 
     public void testRotationWhenDocked() throws Exception {
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         launchActivityToSide();
-        final String[] waitForActivitiesVisible = new String[] {LAUNCHING_ACTIVITY};
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
         mAmWmState.assertContainsStack(
                 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
         mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
 
         // Rotate device single steps (90°) 0-1-2-3.
         // Each time we compute the state we implicitly assert valid bounds.
+        String[] waitForActivitiesVisible =
+            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
         setDeviceRotation(0);
         mAmWmState.computeState(mDevice, waitForActivitiesVisible);
         setDeviceRotation(1);
@@ -255,13 +267,16 @@
 
     public void testRotationWhenDockedWhileLocked() throws Exception {
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         launchActivityToSide();
-        final String[] waitForActivitiesVisible = new String[] {LAUNCHING_ACTIVITY};
-        mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.assertSanity();
         mAmWmState.assertContainsStack(
                 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
         mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
 
+        String[] waitForActivitiesVisible =
+            new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
         sleepDevice();
         setDeviceRotation(0);
         wakeUpAndUnlockDevice();
@@ -285,7 +300,9 @@
 
     public void testResizeDockedStack() throws Exception {
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
         launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
         resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
                 false /* compareTaskAndStackBounds */);
@@ -300,12 +317,14 @@
     }
 
     public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
+        final String[] waitTestActivityName = new String[] {TEST_ACTIVITY_NAME};
         executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
-        mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+        mAmWmState.computeState(mDevice, waitTestActivityName);
         final Rectangle fullScreenBounds =
                 mAmWmState.getWmState().getStack(FULLSCREEN_WORKSPACE_STACK_ID).getBounds();
 
         moveActivityToDockStack(TEST_ACTIVITY_NAME);
+        mAmWmState.computeState(mDevice, waitTestActivityName);
         launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
 
         mAmWmState.computeState(mDevice,
@@ -317,15 +336,15 @@
 
         Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
         resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
+        mAmWmState.computeState(mDevice,
+                new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
 
         // We resize twice to make sure we cross an orientation change threshold for both
         // activities.
         newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, false);
         resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
-
         mAmWmState.computeState(mDevice,
                 new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
-
         assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
         assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
     }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
index 28827f4..c74168d 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
@@ -82,4 +82,38 @@
         assertKeyguardGone();
         mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
     }
+
+    public void testDismissKeyguardActivity_method() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        executeShellCommand(getAmStartCmd("DismissKeyguardMethodActivity"));
+        enterAndConfirmLockCredential();
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
+        mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat();
+    }
+
+    public void testDismissKeyguardActivity_method_cancelled() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        executeShellCommand(getAmStartCmd("DismissKeyguardMethodActivity"));
+        pressBackButton();
+        assertOnDismissCancelledInLogcat();
+        mAmWmState.computeState(mDevice, new String[] {});
+        mAmWmState.assertVisibility("DismissKeyguardMethodActivity", false);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        unlockDeviceWithCredential();
+    }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
index 0ba77e0..ca86637 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
@@ -16,6 +16,11 @@
 
 package android.server.cts;
 
+import static android.server.cts.StateLogger.log;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 public class KeyguardTestBase extends ActivityManagerTestBase {
 
     protected void assertShowingAndOccluded() {
@@ -31,4 +36,36 @@
     protected void assertKeyguardGone() {
         assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
     }
+
+    protected void assertOnDismissSucceededInLogcat() throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded");
+    }
+
+    protected void assertOnDismissCancelledInLogcat() throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled");
+    }
+
+    protected void assertOnDismissErrorInLogcat() throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError");
+    }
+
+    private void assertInLogcat(String activityName, String entry) throws Exception {
+        final Pattern pattern = Pattern.compile("(.+)" + entry);
+        int tries = 0;
+        while (tries < 5) {
+            final String[] lines = getDeviceLogsForComponent(activityName);
+            log("Looking at logcat");
+            for (int i = lines.length - 1; i >= 0; i--) {
+                final String line = lines[i].trim();
+                log(line);
+                Matcher matcher = pattern.matcher(line);
+                if (matcher.matches()) {
+                    return;
+                }
+            }
+            tries++;
+            Thread.sleep(500);
+        }
+        fail("Not in logcat: " + entry);
+    }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
index b3de9fd..d323d97 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
@@ -170,6 +170,52 @@
         assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
     }
 
+    public void testDismissKeyguardActivity_method() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        executeShellCommand(getAmStartCmd("DismissKeyguardMethodActivity"));
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
+        mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat();
+    }
+
+    public void testDismissKeyguardActivity_method_notTop() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        gotoKeyguard();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        executeShellCommand(getAmStartCmd("BroadcastReceiverActivity"));
+        executeShellCommand(getAmStartCmd("TestActivity"));
+        executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguardMethod true");
+        assertOnDismissErrorInLogcat();
+    }
+
+    public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
+        clearLogcat();
+        sleepDevice();
+        mAmWmState.computeState(mDevice, null);
+        assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        executeShellCommand(getAmStartCmd("TurnScreenOnDismissKeyguardActivity"));
+        mAmWmState.waitForKeyguardGone(mDevice);
+        mAmWmState.computeState(mDevice, new String[] { "TurnScreenOnDismissKeyguardActivity"});
+        mAmWmState.assertVisibility("TurnScreenOnDismissKeyguardActivity", true);
+        assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+        assertOnDismissSucceededInLogcat();
+    }
+
     /**
      * Tests whether a FLAG_DISMISS_KEYGUARD activity repeatedly dismissed Keyguard, i.e. whenever
      * lockscreen would show it gets dismissed immediately.
diff --git a/hostsidetests/services/activityandwindowmanager/util/Android.mk b/hostsidetests/services/activityandwindowmanager/util/Android.mk
index ac91d35..993ba94 100644
--- a/hostsidetests/services/activityandwindowmanager/util/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/util/Android.mk
@@ -23,7 +23,7 @@
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_MODULE := cts-amwm-util
 
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
index dc42f71..19f9365 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -43,6 +43,7 @@
     // Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
     // (Needed in host-side tests to convert dp to px.)
     private static final int DISPLAY_DENSITY_DEFAULT = 160;
+    static final int DEFAULT_DISPLAY_ID = 0;
 
     // Default minimal size of resizable task, used if none is set explicitly.
     // Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
@@ -351,8 +352,8 @@
     }
 
     void assertFrontStack(String msg, int stackId) throws Exception {
-        assertEquals(msg, stackId, mAmState.getFrontStackId());
-        assertEquals(msg, stackId, mWmState.getFrontStackId());
+        assertEquals(msg, stackId, mAmState.getFrontStackId(DEFAULT_DISPLAY_ID));
+        assertEquals(msg, stackId, mWmState.getFrontStackId(DEFAULT_DISPLAY_ID));
     }
 
     void assertFocusedStack(String msg, int stackId) throws Exception {
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
index 9799bea..aff9eba 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
@@ -25,9 +25,11 @@
 import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 
+import java.util.Map;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
@@ -45,7 +47,7 @@
     private static final int HOME_ACTIVITY_TYPE = 1;
     private static final int RECENTS_ACTIVITY_TYPE = 2;
 
-    private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+)");
+    private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+).*");
     private final Pattern mStackIdPattern = Pattern.compile("Stack #(\\d+)\\:");
     private final Pattern mResumedActivityPattern =
             Pattern.compile("ResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
@@ -53,10 +55,12 @@
             Pattern.compile("mFocusedStack=ActivityStack\\{(.+) stackId=(\\d+), (.+)\\}(.+)");
 
     private final Pattern[] mExtractStackExitPatterns =
-            { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern};
+            { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern, mDisplayIdPattern };
 
-    // Stacks in z-order with the top most at the front of the list.
+    // Stacks in z-order with the top most at the front of the list, starting with primary display.
     private final List<ActivityStack> mStacks = new ArrayList();
+    // Stacks on all attached displays, in z-order with the top most at the front of the list.
+    private final Map<Integer, List<ActivityStack>> mDisplayStacks = new HashMap<>();
     private KeyguardControllerState mKeyguardControllerState;
     private int mFocusedStackId = -1;
     private String mResumedActivityRecord = null;
@@ -134,6 +138,7 @@
 
             if (stack != null) {
                 mStacks.add(stack);
+                mDisplayStacks.get(currentDisplayId).add(stack);
                 if (stack.mResumedActivity != null) {
                     mResumedActivities.add(stack.mResumedActivity);
                 }
@@ -169,9 +174,10 @@
             matcher = mDisplayIdPattern.matcher(line);
             if (matcher.matches()) {
                 log(line);
-                final String displayId = matcher.group(2);
+                final String displayId = matcher.group(1);
                 log(displayId);
                 currentDisplayId = Integer.parseInt(displayId);
+                mDisplayStacks.put(currentDisplayId, new ArrayList<>());
             }
         }
     }
@@ -185,8 +191,8 @@
         mKeyguardControllerState = null;
     }
 
-    int getFrontStackId() {
-        return mStacks.get(0).mStackId;
+    int getFrontStackId(int displayId) {
+        return mDisplayStacks.get(displayId).get(0).mStackId;
     }
 
     int getFocusedStackId() {
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 6b9c2f3..f5da421 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -71,16 +71,19 @@
     protected static final String AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND =
             "am stack move-top-activity-to-pinned-stack 1 0 0 500 500";
 
-    protected static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
+    static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
 
     private static final String AM_RESIZE_DOCKED_STACK = "am stack resize-docked-stack ";
 
     static final String AM_MOVE_TASK = "am stack move-task ";
 
     private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
+    private static final String INPUT_KEYEVENT_BACK = "input keyevent 4";
 
     private static final String LOCK_CREDENTIAL = "1234";
 
+    private static final int INVALID_DISPLAY_ID = -1;
+
     static String componentName = "android.server.cts";
 
     /** A reference to the device under test. */
@@ -108,6 +111,11 @@
         return base;
     }
 
+    protected static String getAmStartCmd(final String activityName, final int displayId) {
+        return "am start -n " + getActivityComponentName(activityName) + " -f 0x18000000"
+                + " --display " + displayId;
+	}
+
     protected static String getAmStartCmdOverHome(final String activityName) {
         return "am start --activity-task-on-home -n " + getActivityComponentName(activityName);
     }
@@ -205,6 +213,11 @@
         mDevice.executeShellCommand(command, outputReceiver);
     }
 
+    protected void launchActivity(boolean toSide, boolean randomData, boolean multipleTask,
+            String targetActivityName) throws Exception {
+        launchActivity(toSide, randomData, multipleTask, targetActivityName, INVALID_DISPLAY_ID);
+    }
+
     /**
      * Launch specific target activity. It uses existing instance of {@link #LAUNCHING_ACTIVITY}, so
      * that one should be started first.
@@ -214,10 +227,11 @@
      * @param targetActivityName Target activity to be launched. Only class name should be provided,
      *                           package name of {@link #LAUNCHING_ACTIVITY} will be added
      *                           automatically.
+     * @param displayId Display id where target activity should be launched.
      * @throws Exception
      */
     protected void launchActivity(boolean toSide, boolean randomData, boolean multipleTask,
-            String targetActivityName) throws Exception {
+            String targetActivityName, int displayId) throws Exception {
         StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(LAUNCHING_ACTIVITY));
         commandBuilder.append(" -f 0x20000000");
         if (toSide) {
@@ -232,6 +246,9 @@
         if (targetActivityName != null) {
             commandBuilder.append(" --es target_activity ").append(targetActivityName);
         }
+        if (displayId != INVALID_DISPLAY_ID) {
+            commandBuilder.append(" --ei display_id ").append(displayId);
+        }
         executeShellCommand(commandBuilder.toString());
     }
 
@@ -288,6 +305,10 @@
         executeShellCommand(INPUT_KEYEVENT_HOME);
     }
 
+    protected void pressBackButton() throws DeviceNotAvailableException {
+        executeShellCommand(INPUT_KEYEVENT_BACK);
+    }
+
     // Utility method for debugging, not used directly here, but useful, so kept around.
     protected void printStacksAndTasks() throws DeviceNotAvailableException {
         CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
@@ -568,7 +589,7 @@
     private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
     private static final Pattern sNewConfigPattern = Pattern.compile(
             "(.+): config size=\\((\\d+),(\\d+)\\) displaySize=\\((\\d+),(\\d+)\\)" +
-            " metricsSize=\\((\\d+),(\\d+)\\) smallestScreenWidth=(\\d+)");
+            " metricsSize=\\((\\d+),(\\d+)\\) smallestScreenWidth=(\\d+) densityDpi=(\\d+)");
     private static final Pattern sDisplayStatePattern =
             Pattern.compile("Display Power: state=(.+)");
 
@@ -580,13 +601,14 @@
         int metricsWidth;
         int metricsHeight;
         int smallestWidthDp;
+        int densityDpi;
 
         @Override
         public String toString() {
             return "ReportedSizes: {widthDp=" + widthDp + " heightDp=" + heightDp +
                     " displayWidth=" + displayWidth + " displayHeight=" + displayHeight +
                     " metricsWidth=" + metricsWidth + " metricsHeight=" + metricsHeight +
-                    " smallestWidthDp=" + smallestWidthDp + "}";
+                    " smallestWidthDp=" + smallestWidthDp + " densityDpi=" + densityDpi + "}";
         }
     }
 
@@ -605,6 +627,7 @@
                 details.metricsWidth = Integer.parseInt(matcher.group(6));
                 details.metricsHeight = Integer.parseInt(matcher.group(7));
                 details.smallestWidthDp = Integer.parseInt(matcher.group(8));
+                details.densityDpi = Integer.parseInt(matcher.group(9));
                 return details;
             }
         }
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index 3faf4f0..ba1148c 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -16,6 +16,7 @@
 
 package android.server.cts;
 
+import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
 import static android.server.cts.StateLogger.log;
 import static android.server.cts.StateLogger.logE;
 
@@ -26,8 +27,10 @@
 import java.awt.*;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -87,16 +90,23 @@
     private static final Pattern sInputMethodWindowPattern =
             Pattern.compile("mInputMethodWindow=Window\\{([0-9a-fA-F]+) u\\d+ .+\\}.*");
 
+    private static final Pattern sDisplayIdPattern =
+            Pattern.compile("Display: mDisplayId=(\\d+)");
+
     private static final Pattern[] sExtractStackExitPatterns = {
             sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern,
             sDebuggerWindowPattern, sFocusedWindowPattern, sAppErrorFocusedWindowPattern,
             sWaitingForDebuggerFocusedWindowPattern,
             sFocusedAppPattern, sLastAppTransitionPattern, sDefaultPinnedStackBoundsPattern,
-            sPinnedStackMovementBoundsPattern};
+            sPinnedStackMovementBoundsPattern, sDisplayIdPattern };
 
     // Windows in z-order with the top most at the front of the list.
     private List<WindowState> mWindowStates = new ArrayList();
-    private List<WindowStack> mStacks = new ArrayList();
+    // Stacks in z-order with the top most at the front of the list, starting with primary display.
+    private final List<WindowStack> mStacks = new ArrayList();
+    // Stacks on all attached displays, in z-order with the top most at the front of the list.
+    private final Map<Integer, List<WindowStack>> mDisplayStacks
+            = new HashMap<>();
     private List<Display> mDisplays = new ArrayList();
     private String mFocusedWindow = null;
     private String mFocusedApp = null;
@@ -158,12 +168,15 @@
 
         Collections.addAll(mSysDump, sysDump.split("\\n"));
 
+        int currentDisplayId = DEFAULT_DISPLAY_ID;
         while (!mSysDump.isEmpty()) {
             final Display display =
                     Display.create(mSysDump, sExtractStackExitPatterns);
             if (display != null) {
                 log(display.toString());
                 mDisplays.add(display);
+                currentDisplayId = display.mDisplayId;
+                mDisplayStacks.put(currentDisplayId, new ArrayList<>());
                 continue;
             }
 
@@ -172,6 +185,7 @@
 
             if (stack != null) {
                 mStacks.add(stack);
+                mDisplayStacks.get(currentDisplayId).add(stack);
                 continue;
             }
 
@@ -353,8 +367,8 @@
         return mLastTransition;
     }
 
-    int getFrontStackId() {
-        return mStacks.get(0).mStackId;
+    int getFrontStackId(int displayId) {
+        return mDisplayStacks.get(displayId).get(0).mStackId;
     }
 
     public int getRotation() {
@@ -677,8 +691,6 @@
     static class Display extends WindowContainer {
         private static final String TAG = "[Display] ";
 
-        private static final Pattern sDisplayIdPattern =
-                Pattern.compile("Display: mDisplayId=(\\d+)");
         private static final Pattern sDisplayInfoPattern =
                 Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)");
 
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
index e93607f..fd07930 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt CtsServicesHostTestCases
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed CtsServicesHostTestCases
 LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
 
 LOCAL_CTS_TEST_PACKAGE := android.server.cts
diff --git a/hostsidetests/shortcuts/hostside/Android.mk b/hostsidetests/shortcuts/hostside/Android.mk
index 56b2e60..830ec94 100644
--- a/hostsidetests/shortcuts/hostside/Android.mk
+++ b/hostsidetests/shortcuts/hostside/Android.mk
@@ -24,9 +24,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
 
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
index fbd344b..c703e7f 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
@@ -15,7 +15,7 @@
  */
 package android.content.pm.cts.shortcuthost;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -102,9 +102,9 @@
     protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
             DeviceNotAvailableException {
         CLog.i("Installing app " + appFileName + " for user " + userId);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
         String result = getDevice().installPackageForUser(
-                MigrationHelper.getTestFile(mCtsBuild, appFileName), true, true,
-                userId, "-t");
+                buildHelper.getTestFile(appFileName), true, true, userId, "-t");
         assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
                 result);
     }
diff --git a/hostsidetests/sustainedperf/Android.mk b/hostsidetests/sustainedperf/Android.mk
index 22c6d45..a9f06e4 100644
--- a/hostsidetests/sustainedperf/Android.mk
+++ b/hostsidetests/sustainedperf/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_COMPATIBILITY_SUITE := cts
 
 LOCAL_MODULE := CtsSustainedPerformanceHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/hostsidetests/systemui/Android.mk b/hostsidetests/systemui/Android.mk
index 1c0dd06..d4305f5 100644
--- a/hostsidetests/systemui/Android.mk
+++ b/hostsidetests/systemui/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_MODULE := CtsSystemUiHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.systemui
 
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index 00ca6ba..7875b4d 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -25,9 +25,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsThemeHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.host.theme
 
diff --git a/hostsidetests/theme/android_device.py b/hostsidetests/theme/android_device.py
index 6687494..68f7404 100644
--- a/hostsidetests/theme/android_device.py
+++ b/hostsidetests/theme/android_device.py
@@ -89,6 +89,11 @@
     def getOrientation(self):
         return int(self.runShellCommand("dumpsys | grep SurfaceOrientation")[0].split()[1])
 
+    def getHWType(self):
+        (output, err) = self.runShellCommand("dumpsys | grep android.hardware.type")
+        output = output.strip()
+        return output
+
 def runAdbDevices():
     devices = subprocess.check_output(["adb", "devices"])
     devices = devices.split('\n')[1:]
diff --git a/hostsidetests/theme/app/AndroidManifest.xml b/hostsidetests/theme/app/AndroidManifest.xml
index d9a89c6..2bfc2be 100755
--- a/hostsidetests/theme/app/AndroidManifest.xml
+++ b/hostsidetests/theme/app/AndroidManifest.xml
@@ -32,6 +32,8 @@
             </intent-filter>
         </activity>
         <activity android:name=".GenerateImagesActivity" android:screenOrientation="portrait"
+                  android:configChanges=
+                          "screenSize|smallestScreenSize|screenLayout|orientation"
                   android:exported="true" />
     </application>
 
diff --git a/hostsidetests/theme/assets/tvdpi.zip b/hostsidetests/theme/assets/tvdpi.zip
new file mode 100644
index 0000000..3071780
--- /dev/null
+++ b/hostsidetests/theme/assets/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/run_theme_capture_device.py b/hostsidetests/theme/run_theme_capture_device.py
index a516717..20aecf8 100755
--- a/hostsidetests/theme/run_theme_capture_device.py
+++ b/hostsidetests/theme/run_theme_capture_device.py
@@ -27,7 +27,6 @@
 CTS_THEME_dict = {
     120 : "ldpi",
     160 : "mdpi",
-    213 : "tvdpi",
     240 : "hdpi",
     320 : "xhdpi",
     480 : "xxhdpi",
@@ -98,10 +97,15 @@
     device = androidDevice(deviceSerial)
 
     density = device.getDensity()
-    if CTS_THEME_dict.has_key(density):
-        resName = CTS_THEME_dict[density]
+    # Reference images generated for tv should not be categorized by density
+    # rather by tv type. This is because TV uses leanback-specific material
+    # themes.
+    if device.getHWType() == "android.hardware.type.television":
+      resName = "tvdpi"
+    elif CTS_THEME_dict.has_key(density):
+      resName = CTS_THEME_dict[density]
     else:
-        resName = str(density) + "dpi"
+      resName = str(density) + "dpi"
 
     device.uninstallApk("android.theme.app")
 
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index 5a5c63b..c87ff63 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -16,7 +16,7 @@
 
 package android.theme.cts;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.Log;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
@@ -94,6 +94,9 @@
 
     private ExecutorCompletionService<File> mCompletionService;
 
+    /** the string identifying the hardware type. */
+    private String mHardwareType;
+
     @Override
     public void setAbi(IAbi abi) {
         mAbi = abi;
@@ -110,13 +113,15 @@
 
         mDevice = getDevice();
         mDevice.uninstallPackage(APP_PACKAGE_NAME);
+        mHardwareType = mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim();
 
         // Get the APK from the build.
-        final File app = MigrationHelper.getTestFile(mBuildInfo, String.format("%s.apk", APK_NAME));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        final File app = buildHelper.getTestFile(String.format("%s.apk", APK_NAME));
         final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
         mDevice.installPackage(app, true, true, options);
 
-        final String density = getDensityBucketForDevice(mDevice);
+        final String density = getDensityBucketForDevice(mDevice, mHardwareType);
         final String zipFile = String.format("/%s.zip", density);
         mReferences = extractReferenceImages(zipFile);
 
@@ -150,7 +155,7 @@
                 fail("Failed to unzip assets: " + zipFile);
             }
         } else {
-            if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+            if (checkHardwareTypeSkipTest(mHardwareType)) {
                 Log.logAndDisplay(LogLevel.WARN, LOG_TAG,
                         "Could not obtain resources for skipped themes test: " + zipFile);
             } else {
@@ -178,7 +183,7 @@
     }
 
     public void testThemes() throws Exception {
-        if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+        if (checkHardwareTypeSkipTest(mHardwareType)) {
             Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Skipped themes test for watch");
             return;
         }
@@ -301,14 +306,17 @@
         return receiver.getOutput().contains("OK ");
     }
 
-    private static String getDensityBucketForDevice(ITestDevice device) {
+    private static String getDensityBucketForDevice(ITestDevice device, String hardwareType) {
+        if (hardwareType.contains("android.hardware.type.television")) {
+            // references images for tv are under bucket "tvdpi".
+            return "tvdpi";
+        }
         final int density;
         try {
             density = getDensityForDevice(device);
         } catch (DeviceNotAvailableException e) {
             throw new RuntimeException("Failed to detect device density", e);
         }
-
         final String bucket;
         switch (density) {
             case 120:
@@ -317,9 +325,6 @@
             case 160:
                 bucket = "mdpi";
                 break;
-            case 213:
-                bucket = "tvdpi";
-                break;
             case 240:
                 bucket = "hdpi";
                 break;
@@ -360,7 +365,6 @@
     }
 
     private static boolean checkHardwareTypeSkipTest(String hardwareTypeString) {
-        return hardwareTypeString.contains("android.hardware.type.watch")
-                || hardwareTypeString.contains("android.hardware.type.television");
+        return hardwareTypeString.contains("android.hardware.type.watch");
     }
 }
diff --git a/hostsidetests/trustedvoice/Android.mk b/hostsidetests/trustedvoice/Android.mk
index 9d6237f..d80f725 100644
--- a/hostsidetests/trustedvoice/Android.mk
+++ b/hostsidetests/trustedvoice/Android.mk
@@ -23,7 +23,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsTrustedVoiceHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed ddmlib-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed ddmlib-prebuilt tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.trustedvoice
 
diff --git a/hostsidetests/tv/Android.mk b/hostsidetests/tv/Android.mk
index bb5795b..cb5e2bd 100644
--- a/hostsidetests/tv/Android.mk
+++ b/hostsidetests/tv/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsHostsideTvTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.tv.hostsidetv
 
diff --git a/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java b/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
index fe917ae..67cd752 100644
--- a/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
+++ b/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
@@ -16,9 +16,9 @@
 
 package com.android.cts.tv;
 
-import com.android.ddmlib.Log.LogLevel;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.VersionCodes;
-import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
@@ -51,8 +51,8 @@
 
     private void installPackage(String apk) throws FileNotFoundException,
             DeviceNotAvailableException {
-        assertNull(getDevice().installPackage(
-                MigrationHelper.getTestFile(mCtsBuildInfo, apk), true));
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuildInfo);
+        assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), true));
     }
 
     private void uninstallPackage(String packageName, boolean shouldSucceed)
diff --git a/hostsidetests/ui/Android.mk b/hostsidetests/ui/Android.mk
index 7060bdf..e2457c5 100644
--- a/hostsidetests/ui/Android.mk
+++ b/hostsidetests/ui/Android.mk
@@ -22,9 +22,7 @@
 
 LOCAL_MODULE := CtsUiHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
index 74e35fe..1b49eca 100644
--- a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
@@ -16,13 +16,13 @@
 
 package android.ui.cts;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.MeasureRun;
 import com.android.compatibility.common.util.MeasureTime;
 import com.android.compatibility.common.util.MetricsReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 import com.android.compatibility.common.util.Stat;
-import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.Log;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IBuildInfo;
@@ -78,7 +78,7 @@
                 String.format("%s#%s", getClass().getName(), "testInstallTime"), REPORT_LOG_NAME,
                 streamName);
         final int NUMBER_REPEAT = 10;
-        final IBuildInfo build = mBuild;
+        final CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
         final ITestDevice device = mDevice;
         double[] result = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
             @Override
@@ -87,7 +87,7 @@
             }
             @Override
             public void run(int i) throws Exception {
-                File app = MigrationHelper.getTestFile(build, APK);
+                File app = buildHelper.getTestFile(APK);
                 String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
                 device.installPackage(app, false, options);
             }
diff --git a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
index 04ee37e..9cfd957 100644
--- a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
@@ -16,9 +16,9 @@
 
 package android.ui.cts;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.util.MetricsStore;
 import com.android.compatibility.common.util.ReportLog;
-import com.android.cts.migration.MigrationHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestRunResult;
@@ -77,9 +77,10 @@
         super.setUp();
         mDevice = getDevice();
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
         for (int i = 0; i < PACKAGES.length; i++) {
             mDevice.uninstallPackage(PACKAGES[i]);
-            File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+            File app = buildHelper.getTestFile(APKS[i]);
             mDevice.installPackage(app, false, options);
         }
     }
diff --git a/hostsidetests/usage/Android.mk b/hostsidetests/usage/Android.mk
index 72b9473..482ba91 100644
--- a/hostsidetests/usage/Android.mk
+++ b/hostsidetests/usage/Android.mk
@@ -21,7 +21,7 @@
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsAppUsageHostTestCases
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.host.app.usage
 
diff --git a/hostsidetests/usb/Android.mk b/hostsidetests/usb/Android.mk
index a96c5d8..bc98445 100644
--- a/hostsidetests/usb/Android.mk
+++ b/hostsidetests/usb/Android.mk
@@ -21,9 +21,7 @@
 
 LOCAL_MODULE := CtsUsbTests
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_CTS_TEST_PACKAGE := android.usb
 
diff --git a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
index fe230a3..81cc265 100644
--- a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
+++ b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.cts.usb;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestRunResult;
 import com.android.tradefed.build.IBuildInfo;
@@ -62,7 +62,8 @@
         super.setUp();
         mDevice = getDevice();
         mDevice.uninstallPackage(PACKAGE_NAME);
-        File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        File app = buildHelper.getTestFile(APK_NAME);
         String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
         mDevice.installPackage(app, false, options);
     }
diff --git a/hostsidetests/webkit/Android.mk b/hostsidetests/webkit/Android.mk
index 535267c..6fe433c 100644
--- a/hostsidetests/webkit/Android.mk
+++ b/hostsidetests/webkit/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_MODULE := CtsHostsideWebViewTests
 
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := tradefed
 
 LOCAL_CTS_TEST_PACKAGE := android.webkit.hostside
 
diff --git a/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
index 4359bf4..b91efb7 100644
--- a/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
+++ b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
@@ -16,7 +16,8 @@
 
 package com.android.cts.webkit;
 
-
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.cts.util.NullWebViewUtils;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -25,6 +26,7 @@
 import android.webkit.CookieSyncManager;
 import android.webkit.cts.CtsTestServer;
 import android.webkit.cts.WebViewOnUiThread;
+import android.webkit.WebView;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -36,6 +38,8 @@
  * once - after that we will reuse the same webview provider).
  * This works because the instrumentation used to run device-tests from the host-side terminates the
  * testing process after each run.
+ * OBS! When adding a test here - remember to add a corresponding host-side test that will start the
+ * device-test added here! See com.android.cts.webkit.WebViewHostSideStartupTest.
  */
 public class WebViewDeviceSideStartupTest
         extends ActivityInstrumentationTestCase2<WebViewStartupCtsActivity> {
@@ -95,4 +99,49 @@
         assertTrue(m.matches());
         assertEquals("42", m.group(1)); // value got incremented
     }
+
+    @UiThreadTest
+    public void testGetCurrentWebViewPackageOnUiThread() throws Throwable {
+        runCurrentWebViewPackageTest(true /* alreadyOnMainThread */);
+    }
+
+    public void testGetCurrentWebViewPackage() throws Throwable {
+        runCurrentWebViewPackageTest(false /* alreadyOnMainThread */);
+    }
+
+    private void runCurrentWebViewPackageTest(boolean alreadyOnMainThread) throws Exception {
+        PackageManager pm = mActivity.getPackageManager();
+        if (pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+            PackageInfo webViewPackage = WebView.getCurrentWebViewPackage();
+            // Ensure that getCurrentWebViewPackage returns a package recognized by the package
+            // manager.
+            assertPackageEquals(pm.getPackageInfo(webViewPackage.packageName, 0), webViewPackage);
+
+            // Create WebView on the app's main thread
+            if (alreadyOnMainThread) {
+                mActivity.createAndAttachWebView();
+            } else {
+                getInstrumentation().runOnMainSync(new Runnable() {
+                    @Override
+                    public void run() {
+                        mActivity.createAndAttachWebView();
+                    }
+                });
+            }
+
+            // Ensure we are still using the same WebView package.
+            assertPackageEquals(webViewPackage, WebView.getCurrentWebViewPackage());
+        } else {
+            // if WebView isn't supported the API should return null.
+            assertNull(WebView.getCurrentWebViewPackage());
+        }
+    }
+
+    private void assertPackageEquals(PackageInfo expected, PackageInfo actual) {
+        if (expected == null) assertNull(actual);
+        assertEquals(expected.packageName, actual.packageName);
+        assertEquals(expected.versionCode, actual.versionCode);
+        assertEquals(expected.versionName, actual.versionName);
+        assertEquals(expected.lastUpdateTime, actual.lastUpdateTime);
+    }
 }
diff --git a/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java b/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
index ba37beb..90f24f7 100644
--- a/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
+++ b/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
@@ -39,6 +39,16 @@
                     "testCookieManagerBlockingUiThread"));
     }
 
+    public void testWebViewVersionApiOnUiThread() throws DeviceNotAvailableException {
+        assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+                    "testGetCurrentWebViewPackageOnUiThread"));
+    }
+
+    public void testWebViewVersionApi() throws DeviceNotAvailableException {
+        assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+                    "testGetCurrentWebViewPackage"));
+    }
+
     private boolean runDeviceTest(String packageName, String testClassName,
             String testMethodName) throws DeviceNotAvailableException {
         testClassName = packageName + "." + testClassName;
diff --git a/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java b/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
index f691150..decbd4c 100644
--- a/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
@@ -54,14 +54,15 @@
     public static String addPerformanceHeadersToLog(
             DeviceReportLog log, String message, int round, String codecName,
             MediaFormat configFormat, MediaFormat inputFormat, MediaFormat outputFormat) {
+        String mime = configFormat.getString(MediaFormat.KEY_MIME);
+        int width = configFormat.getInteger(MediaFormat.KEY_WIDTH);
+        int height = configFormat.getInteger(MediaFormat.KEY_HEIGHT);
+
         log.addValue("round", round, ResultType.NEUTRAL, ResultUnit.NONE);
         log.addValue("codec_name", codecName, ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("mime_type", configFormat.getString(MediaFormat.KEY_MIME),
-                ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("width", configFormat.getInteger(MediaFormat.KEY_WIDTH),
-                ResultType.NEUTRAL, ResultUnit.NONE);
-        log.addValue("height", configFormat.getInteger(MediaFormat.KEY_HEIGHT),
-                ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("mime_type", mime, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("width", width, ResultType.NEUTRAL, ResultUnit.NONE);
+        log.addValue("height", height, ResultType.NEUTRAL, ResultUnit.NONE);
         log.addValue("config_format", formatForReport(configFormat),
                 ResultType.NEUTRAL, ResultUnit.NONE);
         log.addValue("input_format", formatForReport(inputFormat),
@@ -71,6 +72,16 @@
 
         message += " codec=" + codecName + " round=" + round + " configFormat=" + configFormat
                 + " inputFormat=" + inputFormat + " outputFormat=" + outputFormat;
+
+        Range<Double> reported =
+            MediaUtils.getVideoCapabilities(codecName, mime)
+                    .getAchievableFrameRatesFor(width, height);
+        if (reported != null) {
+            log.addValue("reported_low", reported.getLower(), ResultType.NEUTRAL, ResultUnit.FPS);
+            log.addValue("reported_high", reported.getUpper(), ResultType.NEUTRAL, ResultUnit.FPS);
+            message += " reported=" + reported.getLower() + "-" + reported.getUpper();
+        }
+
         return message;
     }
 
diff --git a/libs/migration/Android.mk b/libs/migration/Android.mk
deleted file mode 100644
index 11173d6..0000000
--- a/libs/migration/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := cts-migration-lib
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/libs/migration/src/com/android/cts/migration/MigrationHelper.java b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
deleted file mode 100644
index 0595486..0000000
--- a/libs/migration/src/com/android/cts/migration/MigrationHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.android.cts.migration;
-
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * A temporary helper to enable tests to work with both cts v1 and v2.
- */
-public class MigrationHelper {
-
-    private static final String COMPATIBILITY_BUILD_HELPER =
-            "com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper";
-    private static final String CTS_BUILD_HELPER =
-            "com.android.cts.tradefed.build.CtsBuildHelper";
-
-    public static File getTestFile(IBuildInfo mBuild, String filename)
-            throws FileNotFoundException {
-        try {
-            Class<?> cls = Class.forName(COMPATIBILITY_BUILD_HELPER);
-            Constructor<?> cons = cls.getConstructor(IBuildInfo.class);
-            Object instance = cons.newInstance(mBuild);
-            Method method = cls.getMethod("getTestsDir");
-            File dir = (File) method.invoke(instance);
-            File file = new File(dir, filename);
-            CLog.i("Looking for test file %s in dir %s", filename, dir.getAbsolutePath());
-            if (file.exists()) {
-                CLog.i("File %s found", filename);
-                return file;
-            }
-        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
-                IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            // Ignore and fall back to CtsBuildHelper
-        }
-        try {
-            Class<?> cls = Class.forName(CTS_BUILD_HELPER);
-            Method builder = cls.getMethod("createBuildHelper", IBuildInfo.class);
-            Object helper = builder.invoke(null, mBuild);
-            Method method = cls.getMethod("getTestApp", String.class);
-            File file = (File) method.invoke(helper, filename);
-            CLog.i("Looking for test file %s as %s", filename, file.getAbsolutePath());
-            if (file.exists()) {
-                CLog.i("File %s found", filename);
-                return file;
-            }
-        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
-                IllegalArgumentException | InvocationTargetException e) {
-            // Ignore
-        }
-        throw new FileNotFoundException("Couldn't load file " + filename);
-    }
-
-}
diff --git a/test_defs.sh b/test_defs.sh
index 5d5090d..cc92685 100644
--- a/test_defs.sh
+++ b/test_defs.sh
@@ -22,7 +22,7 @@
 COMMON_JARS="
     ddmlib-prebuilt\
     hosttestlib\
-    tradefed-prebuilt"
+    tradefed"
 
 checkFile() {
     if [ ! -f "$1" ]; then
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1256546..4ce99ce 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -173,7 +173,7 @@
     }
 
     public void testInterrupt() throws Exception {
-        // The APIs are heavily tested in the android.accessibiliyservice package.
+        // The APIs are heavily tested in the android.accessibilityservice package.
         // This just makes sure the call does not throw an exception.
         waitForAccessibilityEnabled();
         mAccessibilityManager.interrupt();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index ce096fe..220ea5e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -30,6 +30,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ListView;
@@ -330,7 +331,7 @@
                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
         try {
             // create the notification to send
-            channel.setVibration(true);
+            channel.enableVibration(true);
             channel.setLights(true);
             channel.setBypassDnd(true);
             notificationManager.createNotificationChannel(channel);
@@ -390,6 +391,37 @@
         }
     }
 
+    @MediumTest
+    public void testInterrupt_notifiesService() {
+        getInstrumentation()
+                .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+        InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
+                this, InstrumentedAccessibilityService.class);
+        try {
+            assertFalse(service.wasOnInterruptCalled());
+
+            getActivity().runOnUiThread(() -> {
+                AccessibilityManager accessibilityManager = (AccessibilityManager) getActivity()
+                        .getSystemService(Service.ACCESSIBILITY_SERVICE);
+                accessibilityManager.interrupt();
+            });
+
+            Object waitObject = service.getInterruptWaitObject();
+            synchronized (waitObject) {
+                if (!service.wasOnInterruptCalled()) {
+                    try {
+                        waitObject.wait(TIMEOUT_ASYNC_PROCESSING);
+                    } catch (InterruptedException e) {
+                        // Do nothing
+                    }
+                }
+            }
+            assertTrue(service.wasOnInterruptCalled());
+        } finally {
+            service.disableSelfAndRemove();
+        }
+    }
+
     /**
      * Compares all properties of the <code>first</code> and the
      * <code>second</code>.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
index 127b6cc..486e4fa 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
@@ -107,8 +107,11 @@
         waitForIdle();
 
         // Clean up.
+        // The GLOBAL_ACTION_HOME is needed in the case where additional
+        // notifications showing up, we need to clear them as well for the upcoming
+        // new tests to work properly.
         getInstrumentation().getUiAutomation().performGlobalAction(
-                AccessibilityService.GLOBAL_ACTION_BACK);
+                AccessibilityService.GLOBAL_ACTION_HOME);
 
         // Sleep a bit so the UI is settled.
         waitForIdle();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
index 4a9ce08..31c78c5 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
@@ -30,6 +30,9 @@
             sInstances = new HashMap<>();
 
     private final Handler mHandler = new Handler();
+    final Object mInterruptWaitObject = new Object();
+    public boolean mOnInterruptCalled;
+
 
     @Override
     protected void onServiceConnected() {
@@ -53,7 +56,10 @@
 
     @Override
     public void onInterrupt() {
-        // Stub method.
+        synchronized (mInterruptWaitObject) {
+            mOnInterruptCalled = true;
+            mInterruptWaitObject.notifyAll();
+        }
     }
 
     public void disableSelfAndRemove() {
@@ -70,6 +76,16 @@
         assertTrue("Timed out waiting for runOnServiceSync()", sr.waitForComplete());
     }
 
+    public boolean wasOnInterruptCalled() {
+        synchronized (mInterruptWaitObject) {
+            return mOnInterruptCalled;
+        }
+    }
+
+    public Object getInterruptWaitObject() {
+        return mInterruptWaitObject;
+    }
+
     private static final class SyncRunnable implements Runnable {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final Runnable mTarget;
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 543a385..deb1854 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -671,11 +671,13 @@
     }
 
     /**
-     * Test that managed provisioning is pre-installed if and only if the device declares the
-     * device admin feature.
+     * Test that managed provisioning is pre-installed if the device declares the device admin
+     * feature.
      */
     public void testManagedProvisioningPreInstalled() throws Exception {
-        assertEquals(mDeviceAdmin, isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
+        if (mDeviceAdmin) {
+            assertTrue(isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
+        }
     }
 
     private void assertDeviceOwnerMessage(String message) {
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 943f0bf..cf96532 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -45,7 +45,7 @@
         assertEquals(false, channel.shouldShowLights());
         assertEquals(false, channel.shouldVibrate());
         assertEquals(NotificationManager.IMPORTANCE_DEFAULT, channel.getImportance());
-        assertEquals(null, channel.getRingtone());
+        assertEquals(null, channel.getSound());
     }
 
     public void testWriteToParcel() {
@@ -70,18 +70,27 @@
     public void testVibration() {
         NotificationChannel channel =
                 new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
-        channel.setVibration(true);
+        channel.enableVibration(true);
         assertTrue(channel.shouldVibrate());
-        channel.setVibration(false);
+        channel.enableVibration(false);
         assertFalse(channel.shouldVibrate());
     }
 
+    public void testVibrationPattern() {
+        final long[] pattern = new long[] {1, 7, 1, 7, 3};
+        NotificationChannel channel =
+                new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+        assertNull(channel.getVibrationPattern());
+        channel.setVibrationPattern(pattern);
+        assertEquals(pattern, channel.getVibrationPattern());
+    }
+
     public void testRingtone() {
         Uri expected = new Uri.Builder().scheme("fruit").appendQueryParameter("favorite", "bananas")
                 .build();
         NotificationChannel channel =
                 new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
-        channel.setRingtone(expected);
-        assertEquals(expected, channel.getRingtone());
+        channel.setSound(expected);
+        assertEquals(expected, channel.getSound());
     }
 }
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 672e5af..7cc5d6a 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -24,13 +24,14 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.provider.Telephony.Threads;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
 import android.app.stubs.R;
 
+import java.util.Arrays;
+
 public class NotificationManagerTest extends AndroidTestCase {
     final String TAG = NotificationManagerTest.class.getSimpleName();
     final boolean DEBUG = false;
@@ -55,8 +56,9 @@
     public void testCreateChannel() {
         NotificationChannel channel =
                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
-        channel.setVibration(true);
-        channel.setRingtone(new Uri.Builder().scheme("test").build());
+        channel.enableVibration(true);
+        channel.setVibrationPattern(new long[] {5, 8, 2, 1});
+        channel.setSound(new Uri.Builder().scheme("test").build());
         channel.setLights(true);
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
@@ -248,7 +250,8 @@
         assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
         assertEquals(expected.getImportance(), actual.getImportance());
         assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
-        assertEquals(expected.getRingtone(), actual.getRingtone());
+        assertEquals(expected.getSound(), actual.getSound());
         assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
+        assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
     }
 }
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index aca79fc..1a6bf4c 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -467,6 +467,10 @@
     }
 
     public void testUsbAccessory() {
+        // USB accessory mode is only a requirement for devices with USB ports supporting
+        // peripheral mode. As there is no public API to distinguish a device with only host
+        // mode support from having both peripheral and host support, the test may have
+        // false negatives.
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) &&
                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
diff --git a/tests/backup/src/android/backup/cts/BackupQuotaTest.java b/tests/backup/src/android/backup/cts/BackupQuotaTest.java
index 6e211f8..bec28c7 100644
--- a/tests/backup/src/android/backup/cts/BackupQuotaTest.java
+++ b/tests/backup/src/android/backup/cts/BackupQuotaTest.java
@@ -156,10 +156,6 @@
                 out.append(str);
             }
             return out.toString();
-        } finally {
-            if (br != null) {
-                closeQuietly(br);
-            }
         }
     }
 
@@ -167,7 +163,7 @@
                                                                String command) throws Exception {
         final ParcelFileDescriptor pfd =
                 instrumentation.getUiAutomation().executeShellCommand(command);
-        return new FileInputStream(pfd.getFileDescriptor());
+        return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
     }
 
     private static void closeQuietly(AutoCloseable closeable) {
diff --git a/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
index 2969753..bbc4c75 100644
--- a/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
@@ -494,6 +494,10 @@
                             });
 
                             stopCapture();
+                            if (VERBOSE) Log.v(TAG, "Cleanup Renderscript cache");
+                            scriptGraph.close();
+                            RenderScriptSingleton.clearContext();
+                            RenderScriptSingleton.setContext(getContext());
                         }
                     }
                 });
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index 67c08fe..11071fc 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -149,11 +149,13 @@
             assertNotNull("Can't get lens facing info", lensFacing);
             if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT) {
                 assertTrue("System doesn't have front camera feature",
-                        mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
-                        mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
+                        mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT));
             } else if (lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
                 assertTrue("System doesn't have back camera feature",
                         mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA));
+            } else if (lensFacing == CameraCharacteristics.LENS_FACING_EXTERNAL) {
+                assertTrue("System doesn't have external camera feature",
+                        mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
             } else {
                 fail("Unknown camera lens facing " + lensFacing.toString());
             }
@@ -166,10 +168,11 @@
         assertTrue("Missing system feature: FEATURE_CAMERA_ANY",
                ids.length == 0
             || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
-        assertTrue("Missing system feature: FEATURE_CAMERA or FEATURE_CAMERA_FRONT",
+        assertTrue("Missing system feature: FEATURE_CAMERA, FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL",
                ids.length == 0
             || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
-            || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT));
+            || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)
+            || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
     }
 
     // Test: that properties can be queried from each device, without exceptions.
diff --git a/tests/fragment/res/layout/nested_inflated_fragment_child.xml b/tests/fragment/res/layout/nested_inflated_fragment_child.xml
new file mode 100644
index 0000000..9a11bc4
--- /dev/null
+++ b/tests/fragment/res/layout/nested_inflated_fragment_child.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <TextView android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="Test" />
+</LinearLayout>
diff --git a/tests/fragment/res/layout/nested_inflated_fragment_parent.xml b/tests/fragment/res/layout/nested_inflated_fragment_parent.xml
new file mode 100644
index 0000000..026ba45
--- /dev/null
+++ b/tests/fragment/res/layout/nested_inflated_fragment_parent.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <fragment android:name="android.fragment.cts.NestedInflatedFragmentTest$InflatedChildFragment"
+              android:id="@+id/child_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index 89812c3..0d71a34 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -17,26 +17,39 @@
 
 package android.fragment.cts;
 
-import android.app.FragmentController;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotSame;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertSame;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentController;
 import android.app.FragmentHostCallback;
 import android.app.FragmentManager;
 import android.app.FragmentManager.FragmentLifecycleCallbacks;
+import android.app.FragmentManagerNonConfig;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.Debug;
+import android.os.Parcelable;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-
 import android.view.Window;
 import android.widget.TextView;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -44,12 +57,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.TestCase.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class FragmentLifecycleTest {
@@ -393,6 +400,47 @@
         });
     }
 
+    /**
+     * Test to ensure that when dispatch* is called that the fragment manager
+     * doesn't cause the contained fragment states to change even if no state changes.
+     */
+    @Test
+    public void noPrematureStateChange() throws Throwable {
+        final FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc, null);
+
+        mActivityRule.runOnUiThread(() -> {
+            fc.getFragmentManager().beginTransaction()
+                    .add(new StrictFragment(), "1")
+                    .commitNow();
+        });
+
+        Pair<Parcelable, FragmentManagerNonConfig> savedState =
+                FragmentTestUtil.destroy(mActivityRule, fc);
+
+        final FragmentController fragmentController = FragmentTestUtil.createController(mActivityRule);
+
+        mActivityRule.runOnUiThread(() -> {
+            fragmentController.attachHost(null);
+            fragmentController.dispatchCreate();
+            fragmentController.dispatchActivityCreated();
+            fragmentController.noteStateNotSaved();
+            fragmentController.execPendingActions();
+            fragmentController.dispatchStart();
+            fragmentController.reportLoaderStart();
+            fragmentController.dispatchResume();
+            fragmentController.restoreAllState(savedState.first, savedState.second);
+            fragmentController.dispatchResume();
+        });
+
+        FragmentManager fm = fragmentController.getFragmentManager();
+
+        StrictFragment fragment1 = (StrictFragment) fm.findFragmentByTag("1");
+
+        assertNotNull(fragment1);
+        assertFalse(fragment1.mCalledOnResume);
+    }
+
     private void executePendingTransactions(final FragmentManager fm) throws Throwable {
         mActivityRule.runOnUiThread(new Runnable() {
             @Override
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
index aec626f..5e66722 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
@@ -25,11 +25,13 @@
 
 import android.app.Fragment;
 import android.app.FragmentManager;
+import android.app.FragmentTransaction;
 import android.app.Instrumentation;
 import android.app.SharedElementCallback;
 import android.cts.util.transition.TargetTracking;
 import android.cts.util.transition.TrackingTransition;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
@@ -594,6 +596,109 @@
         verifyNoOtherTransitions(fragment2);
     }
 
+    // Ensure that shared element without matching transition name doesn't error out
+    @Test
+    public void sharedElementMismatch() throws Throwable {
+        final TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "fooSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .setAllowOptimization(mOptimize)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endBlue = findBlue();
+        final View endGreen = findGreen();
+
+        if (mOptimize) {
+            verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+        } else {
+            verifyAndClearTransition(fragment1.exitTransition, startBlueBounds, startGreen);
+            verifyAndClearTransition(fragment2.sharedElementEnter, startBlueBounds, startBlue);
+        }
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Ensure that using the same source or target shared element results in an exception.
+    @Test
+    public void sharedDuplicateTargetNames() throws Throwable {
+        setupInitialFragment();
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        FragmentTransaction ft = mFragmentManager.beginTransaction();
+        ft.addSharedElement(startBlue, "blueSquare");
+        try {
+            ft.addSharedElement(startGreen, "blueSquare");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            ft.addSharedElement(startBlue, "greenSquare");
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    // Test that invisible fragment views don't participate in transitions
+    @Test
+    public void invisibleNoTransitions() throws Throwable {
+        if (!mOptimize) {
+            return; // only optimized transitions can avoid interaction
+        }
+        // enter transition
+        TransitionFragment fragment = new InvisibleFragment();
+        fragment.setLayoutId(R.layout.scene1);
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+
+        // exit transition
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+
+        // reenter transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+
+        // return transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForNoTransition();
+        verifyNoOtherTransitions(fragment);
+    }
+
     private TransitionFragment setupInitialFragment() throws Throwable {
         TransitionFragment fragment1 = new TransitionFragment();
         fragment1.setLayoutId(R.layout.scene1);
@@ -856,6 +961,13 @@
             setSharedElementEnterTransition(sharedElementEnterTransition);
             setSharedElementReturnTransition(sharedElementReturnTransition);
         }
+    }
 
+    public static class InvisibleFragment extends TransitionFragment {
+        @Override
+        public void onViewCreated(View view, Bundle savedInstanceState) {
+            view.setVisibility(View.INVISIBLE);
+            super.onViewCreated(view, savedInstanceState);
+        }
     }
 }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
index 1599307..82890df 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -24,6 +24,7 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.Instrumentation;
+import android.os.Bundle;
 import android.os.Debug;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
@@ -870,6 +871,34 @@
         assertNotNull(findViewById(R.id.textC));
     }
 
+    // Test that adding a fragment with invisible or gone views does not end up with the view
+    // being visible
+    @Test
+    public void addInvisibleAndGoneFragments() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final StrictViewFragment fragment1 = new InvisibleFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container, fragment1);
+
+        assertEquals(View.INVISIBLE, fragment1.getView().getVisibility());
+
+        final InvisibleFragment fragment2 = new InvisibleFragment();
+        fragment2.visibility = View.GONE;
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(container, fragment2);
+
+        assertEquals(View.GONE, fragment2.getView().getVisibility());
+    }
+
     private View findViewById(int viewId) {
         return mActivityRule.getActivity().findViewById(viewId);
     }
@@ -883,4 +912,13 @@
                     fragments[i].getView());
         }
     }
-}
+
+    public static class InvisibleFragment extends StrictViewFragment {
+        public int visibility = View.INVISIBLE;
+
+        @Override
+        public void onViewCreated(View view, Bundle savedInstanceState) {
+            view.setVisibility(visibility);
+            super.onViewCreated(view, savedInstanceState);
+        }
+    }}
diff --git a/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java b/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java
new file mode 100644
index 0000000..e24eb39
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.fragment.cts;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NestedInflatedFragmentTest {
+    private static final String TAG = "NestedInflatedFragmentTest";
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<>(FragmentTestActivity.class);
+
+    @Test
+    public void inflatedChildFragment() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final FragmentTestActivity activity = mActivityRule.getActivity();
+                final FragmentManager fm = activity.getFragmentManager();
+
+                ParentFragment parentFragment = new ParentFragment();
+                fm.beginTransaction().add(android.R.id.content, parentFragment).commitNow();
+
+                fm.beginTransaction().replace(android.R.id.content, new SimpleFragment())
+                        .addToBackStack(null).commit();
+                fm.executePendingTransactions();
+
+                fm.popBackStackImmediate();
+            }
+        });
+    }
+
+    public static class ParentFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.nested_inflated_fragment_parent, container, false);
+        }
+    }
+
+    public static class InflatedChildFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.nested_inflated_fragment_child, container, false);
+        }
+    }
+
+    public static class SimpleFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            TextView textView = new TextView(inflater.getContext());
+            textView.setText("Simple fragment");
+            return textView;
+        }
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/TransitionFragment.java b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
index 3fede11..6513691 100644
--- a/tests/fragment/src/android/fragment/cts/TransitionFragment.java
+++ b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
@@ -53,9 +53,11 @@
         setSharedElementEnterTransition(sharedElementEnter);
         setSharedElementReturnTransition(sharedElementReturn);
         enterTransition.addListener(mListener);
+        sharedElementEnter.addListener(mListener);
         reenterTransition.addListener(mListener);
         exitTransition.addListener(mListener);
         returnTransition.addListener(mListener);
+        sharedElementReturn.addListener(mListener);
     }
 
     @Override
diff --git a/tests/jdwp/runner/host-side/Android.mk b/tests/jdwp/runner/host-side/Android.mk
index 426663d..7398f69 100644
--- a/tests/jdwp/runner/host-side/Android.mk
+++ b/tests/jdwp/runner/host-side/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE := cts-dalvik-host-test-runner
 
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
 
 LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
 
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
index 1879367..f722f5fe 100644
--- a/tests/libcore/luni/Android.mk
+++ b/tests/libcore/luni/Android.mk
@@ -24,6 +24,7 @@
     core-tests \
     cts-core-test-runner \
     mockito-target-minus-junit4 \
+    tzdata_update2-tests \
     tzdata_update-tests
 
 # Don't include this package in any target
diff --git a/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 2da6a3b..b096987 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -222,17 +222,17 @@
                         deviceWakeUpTimeMs = -1;
                     }
                     builder.append("\n");
-                    builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
-                    builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
-                        append("ms, ");
+                    builder.append("Timestamp=").append(event.timestamp/1000).append("us, ");
+                    builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000).
+                        append("us, ");
                     builder.append("Accuracy=").append(event.accuracy).append(", ");
                     builder.append("Values=").append(Arrays.toString(event.values));
                     ++i;
                 } else {
                     builder.append("\n");
                     builder.append("ReceivedTimestamp=")
-                    .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
-                    .append("ms Flush complete Event");
+                    .append(mTimeStampFlushCompleteEvents.get(j)/1000)
+                    .append("us Flush complete Event");
                     ++j;
                 }
             }
@@ -245,17 +245,17 @@
                     deviceWakeUpTimeMs = -1;
                 }
                 builder.append("\n");
-                builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
-                builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
-                    append("ms, ");
+                builder.append("Timestamp=").append(event.timestamp/1000).append("us, ");
+                builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000).
+                    append("us, ");
                 builder.append("Accuracy=").append(event.accuracy).append(", ");
                 builder.append("Values=").append(Arrays.toString(event.values));
             }
             for (;j < mTimeStampFlushCompleteEvents.size(); ++j) {
                 builder.append("\n");
                 builder.append("ReceivedTimestamp=")
-                    .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
-                    .append("ms Flush complete Event");
+                    .append(mTimeStampFlushCompleteEvents.get(j)/1000)
+                    .append("us Flush complete Event");
             }
         }
 
diff --git a/tests/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index 0cba3b4..35e97d0 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -31,6 +31,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -759,7 +760,12 @@
                             field.toReadableString(mAbsoluteClassName),
                             "Non-compatible field modifiers found when looking for " +
                             field.toSignatureString());
-                } else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
+                } else if (!checkFieldValueCompliance(field, f)) {
+                    mResultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
+                            field.toReadableString(mAbsoluteClassName),
+                            "Incorrect field value found when looking for " +
+                            field.toSignatureString());
+                }else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
                     // type name does not match, but this might be a generic
                     String genericTypeName = null;
                     Type type = f.getGenericType();
@@ -787,6 +793,194 @@
     }
 
     /**
+     * Checks whether the field values are compatible.
+     *
+     * @param apiField The field as defined by the platform API.
+     * @param deviceField The field as defined by the device under test.
+     */
+    private boolean checkFieldValueCompliance(JDiffField apiField, Field deviceField)
+            throws IllegalAccessException {
+        if ((apiField.mModifier & Modifier.FINAL) == 0 ||
+                (apiField.mModifier & Modifier.STATIC) == 0) {
+            // Only final static fields can have fixed values.
+            return true;
+        }
+        if (apiField.getValueString() == null) {
+            // If we don't define a constant value for it, then it can be anything.
+            return true;
+        }
+        // Some fields may be protected or package-private
+        deviceField.setAccessible(true);
+        switch(apiField.mFieldType) {
+            case "byte":
+                return Objects.equals(apiField.getValueString(),
+                        Byte.toString(deviceField.getByte(null)));
+            case "char":
+                return Objects.equals(apiField.getValueString(),
+                        Integer.toString(deviceField.getChar(null)));
+            case "short":
+                return Objects.equals(apiField.getValueString(),
+                        Short.toString(deviceField.getShort(null)));
+            case "int":
+                return Objects.equals(apiField.getValueString(),
+                        Integer.toString(deviceField.getInt(null)));
+            case "long":
+                return Objects.equals(apiField.getValueString(),
+                        Long.toString(deviceField.getLong(null)) + "L");
+            case "float":
+                return Objects.equals(apiField.getValueString(),
+                        canonicalizeFloatingPoint(
+                            Float.toString(deviceField.getFloat(null)), "f"));
+            case "double":
+                return Objects.equals(apiField.getValueString(),
+                        canonicalizeFloatingPoint(
+                            Double.toString(deviceField.getDouble(null)), ""));
+            case "boolean":
+                return Objects.equals(apiField.getValueString(),
+                        Boolean.toString(deviceField.getBoolean(null)));
+            case "java.lang.String":
+                String value = apiField.getValueString();
+                // Remove the quotes the value string is wrapped in
+                value = unescapeFieldStringValue(value.substring(1, value.length() - 1));
+                return Objects.equals(value, deviceField.get(null));
+            default:
+                return true;
+        }
+    }
+
+    /**
+     * Canonicalize the string representation of floating point numbers.
+     *
+     * This needs to be kept in sync with the doclava canonicalization.
+     */
+    private static final String canonicalizeFloatingPoint(String val, String suffix) {
+        if (val.equals("Infinity")) {
+            return "(1.0" + suffix + "/0.0" + suffix + ")";
+        } else if (val.equals("-Infinity")) {
+            return "(-1.0" + suffix + "/0.0" + suffix + ")";
+        } else if (val.equals("NaN")) {
+            return "(0.0" + suffix + "/0.0" + suffix + ")";
+        }
+
+        String str = val.toString();
+        if (str.indexOf('E') != -1) {
+            return str + suffix;
+        }
+
+        // 1.0 is the only case where a trailing "0" is allowed.
+        // 1.00 is canonicalized as 1.0.
+        int i = str.length() - 1;
+        int d = str.indexOf('.');
+        while (i >= d + 2 && str.charAt(i) == '0') {
+            str = str.substring(0, i--);
+        }
+        return str + suffix;
+    }
+
+
+    // This unescapes the string format used by doclava and so needs to be kept in sync with any
+    // changes made to that format.
+    private static String unescapeFieldStringValue(String str) {
+        final int N = str.length();
+
+        // If there's no special encoding strings in the string then just return it.
+        if (str.indexOf('\\') == -1) {
+            return str;
+        }
+
+        final StringBuilder buf = new StringBuilder(str.length());
+        char escaped = 0;
+        final int START = 0;
+        final int CHAR1 = 1;
+        final int CHAR2 = 2;
+        final int CHAR3 = 3;
+        final int CHAR4 = 4;
+        final int ESCAPE = 5;
+        int state = START;
+
+        for (int i=0; i<N; i++) {
+            final char c = str.charAt(i);
+            switch (state) {
+                case START:
+                    if (c == '\\') {
+                        state = ESCAPE;
+                    } else {
+                        buf.append(c);
+                    }
+                    break;
+                case ESCAPE:
+                    switch (c) {
+                        case '\\':
+                            buf.append('\\');
+                            state = START;
+                            break;
+                        case 't':
+                            buf.append('\t');
+                            state = START;
+                            break;
+                        case 'b':
+                            buf.append('\b');
+                            state = START;
+                            break;
+                        case 'r':
+                            buf.append('\r');
+                            state = START;
+                            break;
+                        case 'n':
+                            buf.append('\n');
+                            state = START;
+                            break;
+                        case 'f':
+                            buf.append('\f');
+                            state = START;
+                            break;
+                        case '\'':
+                            buf.append('\'');
+                            state = START;
+                            break;
+                        case '\"':
+                            buf.append('\"');
+                            state = START;
+                            break;
+                        case 'u':
+                            state = CHAR1;
+                            escaped = 0;
+                            break;
+                    }
+                    break;
+                case CHAR1:
+                case CHAR2:
+                case CHAR3:
+                case CHAR4:
+                    escaped <<= 4;
+                    if (c >= '0' && c <= '9') {
+                        escaped |= c - '0';
+                    } else if (c >= 'a' && c <= 'f') {
+                        escaped |= 10 + (c - 'a');
+                    } else if (c >= 'A' && c <= 'F') {
+                        escaped |= 10 + (c - 'A');
+                    } else {
+                        throw new RuntimeException(
+                                "bad escape sequence: '" + c + "' at pos " + i + " in: \""
+                                + str + "\"");
+                    }
+                    if (state == CHAR4) {
+                        buf.append(escaped);
+                        state = START;
+                    } else {
+                        state++;
+                    }
+                    break;
+            }
+        }
+        if (state != START) {
+            throw new RuntimeException("unfinished escape sequence: " + str);
+        }
+        return buf.toString();
+    }
+
+
+    /**
      * Finds the reflected field specified by the field description.
      *
      * @param field the field description to find
diff --git a/tests/signature/tests/Android.mk b/tests/signature/tests/Android.mk
index f17ee47..0c9c24c 100644
--- a/tests/signature/tests/Android.mk
+++ b/tests/signature/tests/Android.mk
@@ -21,6 +21,6 @@
 
 LOCAL_MODULE := signature-tests
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed signature-hostside
+LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed signature-hostside
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/signature/tests/run_unit_tests.sh b/tests/signature/tests/run_unit_tests.sh
index 19ce8d2..02f914c 100755
--- a/tests/signature/tests/run_unit_tests.sh
+++ b/tests/signature/tests/run_unit_tests.sh
@@ -36,7 +36,7 @@
 fi;
 
 JAR_DIR=${ANDROID_BUILD_TOP}/out/host/$OS/framework
-JARS="tradefed-prebuilt.jar hosttestlib.jar signature-hostside.jar signature-tests.jar"
+JARS="tradefed.jar hosttestlib.jar signature-hostside.jar signature-tests.jar"
 
 for JAR in $JARS; do
     checkFile ${JAR_DIR}/${JAR}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
index 9cd84c7..6e477ae 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
@@ -252,7 +252,7 @@
                 "public transient java.lang.String TRANSIENT_FIELD");
     }
 
-    public void testPacakgeField() {
+    public void testPackageField() {
         JDiffClassDescription clz = createNormalClass();
         JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
                 "PACAKGE_FIELD", "java.lang.String", 0, VALUE);
@@ -279,6 +279,30 @@
         assertEquals(field.toSignatureString(), "protected java.lang.String PROTECTED_FIELD");
     }
 
+    public void testFieldValue() {
+        JDiffClassDescription clz = createNormalClass();
+        JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+                "VALUE_FIELD", "java.lang.String",
+                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"\\u2708\"");
+        clz.addField(field);
+        clz.checkSignatureCompliance();
+        assertEquals(field.toSignatureString(),
+                "public static final java.lang.String VALUE_FIELD");
+    }
+
+    public void testFieldValueChanged() {
+        ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD);
+        JDiffClassDescription clz = createNormalClass(observer);
+        JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+                "VALUE_FIELD", "java.lang.String",
+                Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"&#9992;\"");
+        clz.addField(field);
+        clz.checkSignatureCompliance();
+        assertEquals(field.toSignatureString(),
+                "public static final java.lang.String VALUE_FIELD");
+        observer.validate();
+    }
+
     public void testInnerClass() {
         JDiffClassDescription clz = new JDiffClassDescription(
                 "android.signature.cts.tests.data", "NormalClass.InnerClass", new NoFailures());
@@ -311,7 +335,8 @@
         clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
         clz.setModifier(Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT);
         clz.addMethod(
-                new JDiffClassDescription.JDiffMethod("doSomething", Modifier.PUBLIC, "void"));
+                new JDiffClassDescription.JDiffMethod("doSomething",
+                    Modifier.PUBLIC | Modifier.ABSTRACT, "void"));
         clz.checkSignatureCompliance();
         assertEquals(clz.toSignatureString(), "public interface NormalClass.InnerInterface");
     }
@@ -322,7 +347,8 @@
         clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
         clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
         clz.addMethod(
-                new JDiffClassDescription.JDiffMethod("doSomething", Modifier.PUBLIC, "void"));
+                new JDiffClassDescription.JDiffMethod("doSomething",
+                    Modifier.ABSTRACT| Modifier.PUBLIC, "void"));
         clz.checkSignatureCompliance();
         assertEquals(clz.toSignatureString(), "public interface NormalInterface");
     }
diff --git a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
index 5acd696..db47967 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
@@ -47,6 +47,7 @@
     public static String STATIC_FIELD;
     public volatile String VOLATILE_FIELD;
     public transient String TRANSIENT_FIELD;
+    public final static String VALUE_FIELD = "\u2708";
     String PACAKGE_FIELD;
     private String PRIVATE_FIELD;
     protected String PROTECTED_FIELD;
diff --git a/tests/tests/bionic/Android.build.copy.libs.mk b/tests/tests/bionic/Android.build.copy.libs.mk
index dd7d4e0..6c2d546 100644
--- a/tests/tests/bionic/Android.build.copy.libs.mk
+++ b/tests/tests/bionic/Android.build.copy.libs.mk
@@ -49,6 +49,7 @@
   libtest_check_order_reloc_siblings_e.so \
   libtest_check_order_reloc_siblings_f.so \
   libtest_check_order_reloc_siblings.so \
+  libtest_check_rtld_next_from_library.so \
   libtest_dlopen_from_ctor_main.so \
   libtest_dlopen_from_ctor.so \
   libtest_dlopen_weak_undefined_func.so \
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderTest.java b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
index e7d8a05..dc4a031 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
@@ -226,6 +226,11 @@
         // cannot trigger this callback reliably
     }
 
+    public void testRefresh_DefaultImplReturnsFalse() {
+        MockContentProvider provider = new MockContentProvider();
+        assertFalse(provider.refresh(null, null, null));
+    }
+
     public void testGetIContentProvider() {
         MockContentProvider mockContentProvider = new MockContentProvider();
 
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index ea1227c..fa9a2a7 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -910,6 +910,44 @@
         }
     }
 
+    public void testRefresh_DefaultImplReturnsFalse() {
+        boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
+        assertFalse(refreshed);
+        MockContentProvider.assertRefreshed(TABLE1_URI);
+    }
+
+    public void testRefresh_ReturnsProviderValue() {
+        try {
+            MockContentProvider.setRefreshReturnValue(true);
+            boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
+            assertTrue(refreshed);
+            MockContentProvider.assertRefreshed(TABLE1_URI);
+        } finally {
+            MockContentProvider.setRefreshReturnValue(false);
+        }
+    }
+
+    public void testRefresh_NullUriThrowsImmediately() {
+        try {
+            mContentResolver.refresh(null, null, null);
+            fail("did not throw NullPointerException when uri is null.");
+        } catch (NullPointerException e) {
+            //expected.
+        }
+    }
+
+    public void testRefresh_CancellableThrowsImmediately() {
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        cancellationSignal.cancel();
+
+        try {
+            mContentResolver.refresh(TABLE1_URI, null, cancellationSignal);
+            fail("Expected OperationCanceledException");
+        } catch (OperationCanceledException ex) {
+            // expected
+        }
+    }
+
     public void testRegisterContentObserver() {
         final MockContentObserver mco = new MockContentObserver();
 
diff --git a/tests/tests/content/src/android/content/cts/MockContentProvider.java b/tests/tests/content/src/android/content/cts/MockContentProvider.java
index bddc82d..e422c34 100644
--- a/tests/tests/content/src/android/content/cts/MockContentProvider.java
+++ b/tests/tests/content/src/android/content/cts/MockContentProvider.java
@@ -16,22 +16,15 @@
 
 package android.content.cts;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
+import static junit.framework.Assert.assertEquals;
 
+import android.annotation.Nullable;
 import android.content.ContentProvider;
+import android.content.ContentProvider.PipeDataWriter;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.UriMatcher;
-import android.content.ContentProvider.PipeDataWriter;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.SQLException;
@@ -45,6 +38,15 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+
 public class MockContentProvider extends ContentProvider
         implements PipeDataWriter<String> {
 
@@ -62,6 +64,9 @@
     private static final int SELF_ID = 6;
     private static final int CRASH_ID = 6;
 
+    private static @Nullable Uri sRefreshedUri;
+    private static boolean sRefreshReturnValue;
+
     private final String mAuthority;
     private final String mDbName;
     private final UriMatcher URL_MATCHER;
@@ -385,6 +390,13 @@
         }
     }
 
+    @Override
+    public boolean refresh(Uri uri, @Nullable Bundle args,
+            @Nullable CancellationSignal cancellationSignal) {
+        sRefreshedUri = uri;
+        return sRefreshReturnValue;
+    }
+
     private void crashOnLaunchIfNeeded() {
         if (getCrashOnLaunch(getContext())) {
             // The test case wants us to crash our process on first launch.
@@ -413,6 +425,14 @@
         }
     }
 
+    public static void setRefreshReturnValue(boolean value) {
+        sRefreshReturnValue = value;
+    }
+
+    public static void assertRefreshed(Uri expectedUri) {
+        assertEquals(sRefreshedUri, expectedUri);
+    }
+
     private static File getCrashOnLaunchFile(Context context) {
         return context.getFileStreamPath("MockContentProvider.crashonlaunch");
     }
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 48da789..4e24981 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -61,6 +61,7 @@
             (float)(SECONDARY_DISPLAY_DPI + 1) / DisplayMetrics.DENSITY_DEFAULT;
     // Matches com.android.internal.R.string.display_manager_overlay_display_name.
     private static final String OVERLAY_DISPLAY_NAME_PREFIX = "Overlay #";
+    private static final String OVERLAY_DISPLAY_TYPE = "type OVERLAY";
 
     private DisplayManager mDisplayManager;
     private WindowManager mWindowManager;
@@ -115,15 +116,15 @@
         }
     }
 
-    private boolean isSecondarySize(Display display) {
-        final Point p = new Point();
-        display.getSize(p);
-        return p.x == SECONDARY_DISPLAY_WIDTH && p.y == SECONDARY_DISPLAY_HEIGHT;
+    /** Check if the display is an overlay display, created by this test. */
+    private boolean isSecondaryDisplay(Display display) {
+        return display.toString().contains(OVERLAY_DISPLAY_TYPE);
     }
 
+    /** Get the overlay display, created by this test. */
     private Display getSecondaryDisplay(Display[] displays) {
         for (Display display : displays) {
-            if (isSecondarySize(display)) {
+            if (isSecondaryDisplay(display)) {
                 return display;
             }
         }
@@ -143,7 +144,7 @@
             if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
                 hasDefaultDisplay = true;
             }
-            if (isSecondarySize(display)) {
+            if (isSecondaryDisplay(display)) {
                 hasSecondaryDisplay = true;
             }
         }
@@ -234,22 +235,6 @@
     }
 
     /**
-     * Test that the getCurrentSizeRange method returns correct values.
-     */
-    public void testGetCurrentSizeRange() {
-        Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
-
-        Point smallest = new Point();
-        Point largest = new Point();
-        display.getCurrentSizeRange(smallest, largest);
-
-        assertEquals(SECONDARY_DISPLAY_WIDTH, smallest.x);
-        assertEquals(SECONDARY_DISPLAY_HEIGHT, smallest.y);
-        assertEquals(SECONDARY_DISPLAY_WIDTH, largest.x);
-        assertEquals(SECONDARY_DISPLAY_HEIGHT, largest.y);
-    }
-
-    /**
      * Test that the getFlags method returns no flag bits set for the overlay display.
      */
     public void testFlags() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
new file mode 100644
index 0000000..41dc97d
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics.cts;
+
+import android.graphics.ColorSpace;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.function.DoubleUnaryOperator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorSpaceTest {
+    // Column-major RGB->XYZ transform matrix for the sRGB color space
+    private static final float[] SRGB_TO_XYZ = {
+            0.412391f, 0.212639f, 0.019331f,
+            0.357584f, 0.715169f, 0.119195f,
+            0.180481f, 0.072192f, 0.950532f
+    };
+    // Column-major XYZ->RGB transform matrix for the sRGB color space
+    private static final float[] XYZ_TO_SRGB = {
+            3.240970f, -0.969244f,  0.055630f,
+           -1.537383f,  1.875968f, -0.203977f,
+           -0.498611f,  0.041555f,  1.056971f
+    };
+
+    private static final float[] SRGB_PRIMARIES_xyY =
+            { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
+    private static final float[] SRGB_WHITE_POINT_xyY = { 0.3127f, 0.3290f };
+
+    private static final float[] SRGB_PRIMARIES_XYZ = {
+            1.939394f, 1.000000f, 0.090909f,
+            0.500000f, 1.000000f, 0.166667f,
+            2.500000f, 1.000000f, 13.166667f
+    };
+    private static final float[] SRGB_WHITE_POINT_XYZ = { 0.950456f, 1.000f, 1.089058f };
+
+    private static final DoubleUnaryOperator sIdentity = DoubleUnaryOperator.identity();
+
+    @Test
+    public void testNamedColorSpaces() {
+        for (ColorSpace.Named named : ColorSpace.Named.values()) {
+            ColorSpace colorSpace = ColorSpace.get(named);
+            assertNotNull(colorSpace.getName());
+            assertNotNull(colorSpace);
+            assertEquals(named.ordinal(), colorSpace.getId());
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullName() {
+        new ColorSpace.Rgb(null, new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testEmptyName() {
+        new ColorSpace.Rgb("", new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test
+    public void testName() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+                sIdentity, sIdentity, 0.0f, 1.0f);
+        assertEquals("Test", cs.getName());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPrimariesLength() {
+        new ColorSpace.Rgb("Test", new float[7], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testWhitePointLength() {
+        new ColorSpace.Rgb("Test", new float[6], new float[1], sIdentity, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullOETF() {
+        new ColorSpace.Rgb("Test", new float[6], new float[2], null, sIdentity, 0.0f, 1.0f);
+    }
+
+    @Test
+    public void testOETF() {
+        DoubleUnaryOperator op = Math::sqrt;
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+                op, sIdentity, 0.0f, 1.0f);
+        assertEquals(op, cs.getOetf());
+        assertEquals(0.5, cs.getOetf().applyAsDouble(0.25), 1e-5);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testNullEOTF() {
+        new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, null, 0.0f, 1.0f);
+    }
+
+    @Test
+    public void testEOTF() {
+        DoubleUnaryOperator op = x -> x * x;
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+                sIdentity, op, 0.0f, 1.0f);
+        assertEquals(op, cs.getEotf());
+        assertEquals(0.0625, cs.getEotf().applyAsDouble(0.25), 1e-5);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidRange() {
+        new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, sIdentity, 2.0f, 1.0f);
+    }
+
+    @Test
+    public void testRanges() {
+        ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float m1 = cs.getMinValue(0);
+        float m2 = cs.getMinValue(1);
+        float m3 = cs.getMinValue(2);
+
+        assertEquals(0.0f, m1, 1e-9f);
+        assertEquals(0.0f, m2, 1e-9f);
+        assertEquals(0.0f, m3, 1e-9f);
+
+        m1 = cs.getMaxValue(0);
+        m2 = cs.getMaxValue(1);
+        m3 = cs.getMaxValue(2);
+
+        assertEquals(1.0f, m1, 1e-9f);
+        assertEquals(1.0f, m2, 1e-9f);
+        assertEquals(1.0f, m3, 1e-9f);
+
+        cs = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+
+        m1 = cs.getMinValue(0);
+        m2 = cs.getMinValue(1);
+        m3 = cs.getMinValue(2);
+
+        assertEquals(0.0f, m1, 1e-9f);
+        assertEquals(-128.0f, m2, 1e-9f);
+        assertEquals(-128.0f, m3, 1e-9f);
+
+        m1 = cs.getMaxValue(0);
+        m2 = cs.getMaxValue(1);
+        m3 = cs.getMaxValue(2);
+
+        assertEquals(100.0f, m1, 1e-9f);
+        assertEquals(128.0f, m2, 1e-9f);
+        assertEquals(128.0f, m3, 1e-9f);
+
+        cs = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
+
+        m1 = cs.getMinValue(0);
+        m2 = cs.getMinValue(1);
+        m3 = cs.getMinValue(2);
+
+        assertEquals(0.0f, m1, 1e-9f);
+        assertEquals(0.0f, m2, 1e-9f);
+        assertEquals(0.0f, m3, 1e-9f);
+
+        m1 = cs.getMaxValue(0);
+        m2 = cs.getMaxValue(1);
+        m3 = cs.getMaxValue(2);
+
+        assertEquals(2.0f, m1, 1e-9f);
+        assertEquals(2.0f, m2, 1e-9f);
+        assertEquals(2.0f, m3, 1e-9f);
+    }
+
+    @Test
+    public void testMat3x3() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] rgbToXYZ = cs.getTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testMat3x3Inverse() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] xyzToRGB = cs.getInverseTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testMat3x3Primaries() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] primaries = cs.getPrimaries();
+
+        assertNotNull(primaries);
+        assertEquals(6, primaries.length);
+
+        assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-5f);
+        assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-5f);
+    }
+
+    @Test
+    public void testMat3x3WhitePoint() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+        float[] whitePoint = cs.getWhitePoint();
+
+        assertNotNull(whitePoint);
+        assertEquals(2, whitePoint.length);
+
+        assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-5f);
+        assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-5f);
+    }
+
+    @Test
+    public void testXYZFromPrimaries_xyY() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_xyY, SRGB_WHITE_POINT_xyY,
+                sIdentity, sIdentity, 0.0f, 1.0f);
+
+        float[] rgbToXYZ = cs.getTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+        }
+
+        float[] xyzToRGB = cs.getInverseTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testXYZFromPrimaries_XYZ() {
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_XYZ, SRGB_WHITE_POINT_XYZ,
+                sIdentity, sIdentity, 0.0f, 1.0f);
+
+        float[] primaries = cs.getPrimaries();
+
+        assertNotNull(primaries);
+        assertEquals(6, primaries.length);
+
+        // SRGB_PRIMARIES_xyY only has 1e-3 of precision, match it
+        assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-3f);
+        assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-3f);
+
+        float[] whitePoint = cs.getWhitePoint();
+
+        assertNotNull(whitePoint);
+        assertEquals(2, whitePoint.length);
+
+        // SRGB_WHITE_POINT_xyY only has 1e-3 of precision, match it
+        assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-3f);
+        assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-3f);
+
+        float[] rgbToXYZ = cs.getTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+        }
+
+        float[] xyzToRGB = cs.getInverseTransform();
+        for (int i = 0; i < 9; i++) {
+            assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+        }
+    }
+
+    @Test
+    public void testIsSRGB() {
+        assertTrue(ColorSpace.get(ColorSpace.Named.SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.DISPLAY_P3).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.CIE_LAB).isSrgb());
+        assertFalse(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isSrgb());
+
+        ColorSpace.Rgb cs = new ColorSpace.Rgb("My sRGB", SRGB_TO_XYZ,
+                x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f));
+        assertTrue(cs.isSrgb());
+    }
+
+    @Test
+    public void testIsWideGamut() {
+        assertFalse(ColorSpace.get(ColorSpace.Named.SRGB).isWideGamut());
+        assertFalse(ColorSpace.get(ColorSpace.Named.BT709).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.DCI_P3).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.BT2020).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.ACES).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.CIE_LAB).isWideGamut());
+        assertTrue(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isWideGamut());
+    }
+
+    @Test
+    public void testWhitePoint() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] whitePoint = cs.getWhitePoint();
+
+        assertNotNull(whitePoint);
+        assertEquals(2, whitePoint.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(whitePoint, Float.NaN);
+        assertArrayNotEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
+        assertSame(whitePoint, cs.getWhitePoint(whitePoint));
+        assertArrayEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
+    }
+
+    @Test
+    public void testPrimaries() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] primaries = cs.getPrimaries();
+
+        assertNotNull(primaries);
+        assertEquals(6, primaries.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(primaries, Float.NaN);
+        assertArrayNotEquals(primaries, cs.getPrimaries(), 1e-5f);
+        assertSame(primaries, cs.getPrimaries(primaries));
+        assertArrayEquals(primaries, cs.getPrimaries(), 1e-5f);
+    }
+
+    @Test
+    public void testRGBtoXYZMatrix() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] rgbToXYZ = cs.getTransform();
+
+        assertNotNull(rgbToXYZ);
+        assertEquals(9, rgbToXYZ.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(rgbToXYZ, Float.NaN);
+        assertArrayNotEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
+        assertSame(rgbToXYZ, cs.getTransform(rgbToXYZ));
+        assertArrayEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
+    }
+
+    @Test
+    public void testXYZtoRGBMatrix() {
+        ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] xyzToRGB = cs.getInverseTransform();
+
+        assertNotNull(xyzToRGB);
+        assertEquals(9, xyzToRGB.length);
+
+        // Make sure a copy is returned
+        Arrays.fill(xyzToRGB, Float.NaN);
+        assertArrayNotEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
+        assertSame(xyzToRGB, cs.getInverseTransform(xyzToRGB));
+        assertArrayEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
+    }
+
+    @Test
+    public void testRGBtoXYZ() {
+        ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.75f, 0.5f, 0.25f };
+        float[] expected = { 0.3012f, 0.2679f, 0.0840f };
+
+        float[] r1 = cs.toXyz(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, cs.toXyz(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testXYZtoRGB() {
+        ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.3012f, 0.2679f, 0.0840f };
+        float[] expected = { 0.75f, 0.5f, 0.25f };
+
+        float[] r1 = cs.fromXyz(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, cs.fromXyz(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testConnect() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getSource());
+        assertSame(ColorSpace.get(ColorSpace.Named.DCI_P3), connector.getDestination());
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        assertSame(connector.getDestination(), connector.getSource());
+
+        connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3));
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getDestination());
+
+        connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.SRGB));
+        assertSame(connector.getSource(), connector.getDestination());
+    }
+
+    @Test
+    public void testConnector() {
+        // Connect color spaces with same white points
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+
+        float[] source = { 1.0f, 0.5f, 0.0f };
+        float[] expected = { 0.8912f, 0.4962f, 0.1164f };
+
+        float[] r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, connector.transform(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.ADOBE_RGB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        float[] tmp = source;
+        source = expected;
+        expected = tmp;
+
+        r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayNotEquals(source, r1, 1e-5f);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        r3 = new float[] { source[0], source[1], source[2] };
+        assertSame(r3, connector.transform(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testAdaptedConnector() {
+        // Connect color spaces with different white points
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB));
+
+        float[] source = new float[] { 1.0f, 0.0f, 0.0f };
+        float[] expected = new float[] { 0.70226f, 0.2757f, 0.1036f };
+
+        float[] r = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r);
+        assertEquals(3, r.length);
+        assertArrayNotEquals(source, r, 1e-5f);
+        assertArrayEquals(expected, r, 1e-4f);
+    }
+
+    @Test
+    public void testAdaptedConnectorWithRenderIntent() {
+        // Connect a wider color space to a narrow color space
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.RenderIntent.RELATIVE);
+
+        float[] source = { 0.9f, 0.9f, 0.9f };
+
+        float[] relative = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(relative);
+        assertEquals(3, relative.length);
+        assertArrayNotEquals(source, relative, 1e-5f);
+        assertArrayEquals(new float[] { 0.8862f, 0.8862f, 0.8862f }, relative, 1e-4f);
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.RenderIntent.ABSOLUTE);
+
+        float[] absolute = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(absolute);
+        assertEquals(3, absolute.length);
+        assertArrayNotEquals(source, absolute, 1e-5f);
+        assertArrayNotEquals(relative, absolute, 1e-5f);
+        assertArrayEquals(new float[] { 0.8475f, 0.9217f, 0.8203f }, absolute, 1e-4f);
+    }
+
+    @Test
+    public void testIdentityConnector() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        assertSame(connector.getSource(), connector.getDestination());
+
+        float[] source = new float[] { 0.11112f, 0.22227f, 0.444448f };
+
+        float[] r = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r);
+        assertEquals(3, r.length);
+        assertArrayEquals(source, r, 1e-5f);
+    }
+
+    @Test
+    public void testConnectorTransformIdentity() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+        float[] source = { 1.0f, 0.0f, 0.0f };
+        float[] expected = { 1.0f, 0.0f, 0.0f };
+
+        float[] r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r3 = { source[0], source[1], source[2] };
+        assertSame(r3, connector.transform(r3));
+        assertEquals(3, r3.length);
+        assertArrayEquals(r1, r3, 1e-5f);
+    }
+
+    @Test
+    public void testAdaptation() {
+        ColorSpace adapted = ColorSpace.adapt(
+                ColorSpace.get(ColorSpace.Named.SRGB),
+                ColorSpace.ILLUMINANT_D50);
+
+        float[] sRGBD50 = {
+                0.43602175f, 0.22247513f, 0.01392813f,
+                0.38510883f, 0.71690667f, 0.09710153f,
+                0.14308129f, 0.06061824f, 0.71415880f
+        };
+
+        assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f);
+    }
+
+    @Test
+    public void testImplicitSRGBConnector() {
+        ColorSpace.Connector connector1 = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector1.getDestination());
+
+        ColorSpace.Connector connector2 = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.DCI_P3),
+                ColorSpace.get(ColorSpace.Named.SRGB));
+
+        float[] source = { 0.6f, 0.9f, 0.7f };
+        assertArrayEquals(
+                connector1.transform(source[0], source[1], source[2]),
+                connector2.transform(source[0], source[1], source[2]), 1e-7f);
+    }
+
+    @Test
+    public void testLab() {
+        ColorSpace.Connector connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.CIE_LAB));
+
+        float[] source = { 100.0f, 0.0f, 0.0f };
+        float[] expected = { 1.0f, 1.0f, 1.0f };
+
+        float[] r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        source = new float[] { 100.0f, 0.0f, 54.0f };
+        expected = new float[] { 1.0f, 0.9925f, 0.5762f };
+
+        float[] r2 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r2);
+        assertEquals(3, r2.length);
+        assertArrayEquals(expected, r2, 1e-3f);
+
+        connector = ColorSpace.connect(
+                ColorSpace.get(ColorSpace.Named.CIE_LAB), ColorSpace.RenderIntent.ABSOLUTE);
+
+        source = new float[] { 100.0f, 0.0f, 0.0f };
+        expected = new float[] { 1.0f, 0.9910f, 0.8651f };
+
+        r1 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        source = new float[] { 100.0f, 0.0f, 54.0f };
+        expected = new float[] { 1.0f, 0.9853f, 0.4652f };
+
+        r2 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r2);
+        assertEquals(3, r2.length);
+        assertArrayEquals(expected, r2, 1e-3f);
+    }
+
+    @Test
+    public void testXYZ() {
+        ColorSpace xyz = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
+
+        float[] source = { 0.32f, 0.43f, 0.54f };
+
+        float[] r1 = xyz.toXyz(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(source, r1, 1e-7f);
+
+        float[] r2 = xyz.fromXyz(source[0], source[1], source[2]);
+        assertNotNull(r2);
+        assertEquals(3, r2.length);
+        assertArrayEquals(source, r2, 1e-7f);
+
+        ColorSpace.Connector connector =
+                ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_XYZ));
+
+        float[] expected = { 0.2280f, 0.7541f, 0.8453f };
+
+        float[] r3 = connector.transform(source[0], source[1], source[2]);
+        assertNotNull(r3);
+        assertEquals(3, r3.length);
+        assertArrayEquals(expected, r3, 1e-3f);
+    }
+
+    @Test
+    public void testIDs() {
+        // These cannot change
+        assertEquals(0, ColorSpace.get(ColorSpace.Named.SRGB).getId());
+        assertEquals(-1, ColorSpace.MIN_ID);
+        assertEquals(64, ColorSpace.MAX_ID);
+    }
+
+    @Test
+    public void testFromLinear() {
+        ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.0f, 0.5f, 1.0f };
+        float[] expected = { 0.0f, 0.7354f, 1.0f };
+
+        float[] r1 = colorSpace.fromLinear(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r2 = { source[0], source[1], source[2] };
+        assertSame(r2, colorSpace.fromLinear(r2));
+        assertEquals(3, r2.length);
+        assertArrayEquals(r1, r2, 1e-5f);
+    }
+
+    @Test
+    public void testToLinear() {
+        ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+        float[] source = { 0.0f, 0.5f, 1.0f };
+        float[] expected = new float[] { 0.0f, 0.2140f, 1.0f };
+
+        float[] r1 = colorSpace.toLinear(source[0], source[1], source[2]);
+        assertNotNull(r1);
+        assertEquals(3, r1.length);
+        assertArrayEquals(expected, r1, 1e-3f);
+
+        float[] r2 = new float[] { source[0], source[1], source[2] };
+        assertSame(r2, colorSpace.toLinear(r2));
+        assertEquals(3, r2.length);
+        assertArrayEquals(r1, r2, 1e-5f);
+    }
+
+    @Test
+    public void testIdempotentTransferFunctions() {
+        Arrays.stream(ColorSpace.Named.values())
+                .map(ColorSpace::get)
+                .filter(cs -> cs.getModel() == ColorSpace.Model.RGB)
+                .map(cs -> (ColorSpace.Rgb) cs)
+                .forEach(cs -> {
+                        float[] source = { 0.0f, 0.5f, 1.0f };
+                        float[] r = cs.fromLinear(cs.toLinear(source[0], source[1], source[2]));
+                        assertArrayEquals(source, r, 1e-3f);
+                });
+    }
+
+    @SuppressWarnings("SameParameterValue")
+    private static void assertArrayNotEquals(float[] a, float[] b, float eps) {
+        for (int i = 0; i < a.length; i++) {
+            if (Float.compare(a[i], b[i]) == 0 || Math.abs(a[i] - b[i]) < eps) {
+                fail("Expected " + a[i] + ", received " + b[i]);
+            }
+        }
+    }
+
+    private static void assertArrayEquals(float[] a, float[] b, float eps) {
+        for (int i = 0; i < a.length; i++) {
+            if (Float.compare(a[i], b[i]) != 0 && Math.abs(a[i] - b[i]) > eps) {
+                fail("Expected " + a[i] + ", received " + b[i]);
+            }
+        }
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
index 2a4dc48..7df4360 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
@@ -31,7 +31,6 @@
     public void testAlpha() {
         assertEquals(0xff, Color.alpha(Color.RED));
         assertEquals(0xff, Color.alpha(Color.YELLOW));
-        new Color();
     }
 
     @Test
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 5fe6026..35185dd 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -262,7 +262,7 @@
 
     // Since Mockito can't mock or spy on protected methods, we have a custom extension
     // of StateListDrawable to track calls to protected inflateTag method.
-    private class MockShapeDrawable extends ShapeDrawable {
+    public class MockShapeDrawable extends ShapeDrawable {
         public boolean inflateTagCalled;
         public boolean extendedAttrsSet;
 
diff --git a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
index cbacd26..402b204 100644
--- a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
+++ b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
@@ -55,13 +55,7 @@
         Assert.assertTrue(mTextureView.isOpaque());
         mWidth = width;
         mHeight = height;
-        PackageManager packageManager = getPackageManager();
-        boolean hasRearCamera = packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA);
-        boolean hasFrontCamera =
-                packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
-        if (hasRearCamera) {
-            mCamera = Camera.open();
-        } else if (hasFrontCamera) {
+        if (Camera.getNumberOfCameras() > 0) {
             mCamera = Camera.open(0);
         } else {
             // no camera, and no frame update, so just complete here.
@@ -84,8 +78,10 @@
     }
 
     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-        mCamera.stopPreview();
-        mCamera.release();
+        if (mCamera != null) {
+            mCamera.stopPreview();
+            mCamera.release();
+        }
         return true;
     }
 
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 0c7afaf..4867268 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -56,7 +56,7 @@
 	descGen \
 	jsr305lib
 
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := tradefed
 
 LOCAL_MODULE := cts-icu-tools
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
index caa6336..77cde44 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
@@ -61,26 +61,6 @@
         }
     }
 
-    public void testGetPrivateKeyOnMainThreadFails() throws InterruptedException {
-        final CountDownLatch waiter = new CountDownLatch(1);
-        new Handler(getContext().getMainLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    KeyChain.getPrivateKey(getContext(), "");
-                    fail("IllegalStateException was expected for calling "
-                            + "KeyChain.getPrivateKey(Context, String) on main thread");
-                } catch (IllegalStateException expected) {
-                } catch (Exception invalid) {
-                    fail("Expected IllegalStateException, received " + invalid);
-                } finally {
-                    waiter.countDown();
-                }
-            }
-        });
-        waiter.await();
-    }
-
     /**
      * Tests whether the required algorithms are backed by a Keymaster HAL that
      * binds the key material to the specific device it was created or imported
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
index 6deaed4..aed0d42 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
@@ -271,7 +271,7 @@
                             continue;
                         }
                     }
-                    if ((i > 0) && ((i % 8 ) == 0)) {
+                    if ((i >= 64) && ((i % 8 ) == 0)) {
                         keyGenerator.init(spec, rng);
                         SecretKey key = keyGenerator.generateKey();
                         assertEquals(i, TestUtils.getKeyInfo(key).getKeySize());
diff --git a/tests/tests/location/src/android/location/cts/GeocoderTest.java b/tests/tests/location/src/android/location/cts/GeocoderTest.java
index d96b73f..62d9d25 100644
--- a/tests/tests/location/src/android/location/cts/GeocoderTest.java
+++ b/tests/tests/location/src/android/location/cts/GeocoderTest.java
@@ -17,6 +17,9 @@
 package android.location.cts;
 
 
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.location.Geocoder;
 import android.test.AndroidTestCase;
 
@@ -43,7 +46,21 @@
 
     public void testIsPresent() {
         Geocoder geocoder = new Geocoder(getContext());
-        assertTrue(geocoder.isPresent());
+        if (isServiceMissing()) {
+            assertFalse(geocoder.isPresent());
+        } else {
+            assertTrue(geocoder.isPresent());
+        }
+    }
+
+    private boolean isServiceMissing() {
+        Context context = getContext();
+        PackageManager pm = context.getPackageManager();
+
+        final Intent intent = new Intent("com.android.location.service.GeocodeProvider");
+        final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+               | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+        return pm.queryIntentServices(intent, flags).isEmpty();
     }
 
     public void testGetFromLocation() throws IOException, InterruptedException {
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index 509be67..662a1fd 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -55,6 +55,8 @@
             " listener has failed, this indicates a platform bug. Please report the issue with" +
             " a full bugreport.";
 
+    private static final int YEAR_2016 = 2016;
+
     // The valid Gnss navigation message type as listed in
     // android/hardware/libhardware/include/hardware/gps.h
     public static final Set<Integer> GNSS_NAVIGATION_MESSAGE_TYPE =
@@ -70,8 +72,6 @@
             GnssNavigationMessage.TYPE_GAL_F
         ));
 
-    private static final int YEAR_2016 = 2016;
-
     /**
      * Check if test can be run on the current device.
      *
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 23fa502..4b5b1d7 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -1092,7 +1092,9 @@
             boolean sawOutputEos = false;
             int deadDecoderCounter = 0;
             ArrayList<String> frames = new ArrayList<String>();
-            while ((waitForEos && !sawOutputEos) || frameIx < frameEndIx) {
+            String buf = null;
+            // After all input buffers are queued, dequeue as many output buffers as possible.
+            while ((waitForEos && !sawOutputEos) || frameIx < frameEndIx || buf != null) {
                 if (frameIx < frameEndIx) {
                     if (queueInputBuffer(
                             media,
@@ -1103,7 +1105,7 @@
                     }
                 }
 
-                String buf = dequeueAndReleaseOutputBuffer(info);
+                buf = dequeueAndReleaseOutputBuffer(info);
                 if (buf != null) {
                     // Some decoders output a 0-sized buffer at the end. Disregard those.
                     if (info.size > 0) {
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerStub.java b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
index 947acec..50fb2fd 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerStub.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
@@ -32,6 +32,11 @@
     private MediaPlayer mMediaPlayer;
     private AudioManager mAudioManager;
     private static CTSResult mCTSResult;
+    private static final int[] STREAM_TYPES = {
+            AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM,
+            AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM,
+            AudioManager.STREAM_NOTIFICATION, AudioManager.STREAM_DTMF,
+            AudioManager.STREAM_ACCESSIBILITY };
 
     public static void setCTSResult(CTSResult cr) {
         mCTSResult = cr;
@@ -51,7 +56,7 @@
     protected void onPause() {
         super.onPause();
         try {
-            for (int i = 0; i < AudioSystem.getNumStreamTypes(); i++) {
+            for (int i : STREAM_TYPES) {
                 mAudioManager.setStreamMute(i, false);
                 mAudioManager.setStreamSolo(i, false);
             }
@@ -65,7 +70,7 @@
     protected void onResume() {
         super.onResume();
         try {
-            for (int i = 0; i < AudioSystem.getNumStreamTypes(); i++) {
+            for (int i : STREAM_TYPES) {
                 mAudioManager.setStreamMute(i, true);
                 mAudioManager.setStreamSolo(i, true);
             }
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index c32be5c..a1754d1 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -468,7 +468,8 @@
             int[] streams = {AudioManager.STREAM_ALARM,
                     AudioManager.STREAM_MUSIC,
                     AudioManager.STREAM_VOICE_CALL,
-                    AudioManager.STREAM_RING};
+                    AudioManager.STREAM_RING,
+                    AudioManager.STREAM_ACCESSIBILITY};
 
             mAudioManager.adjustVolume(ADJUST_RAISE, 0);
             mAudioManager.adjustSuggestedStreamVolume(
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
index 7b74ba7..9b1dc81 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -19,11 +19,22 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.cts.util.MediaUtils;
 import android.graphics.Bitmap;
+import android.media.MediaFormat;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.view.View;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.Timeout;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
 @TargetApi(24)
+@RunWith(AndroidJUnit4.class)
 public class DecodeAccuracyTest extends DecodeAccuracyTestBase {
 
     private static final String TAG = DecodeAccuracyTest.class.getSimpleName();
@@ -32,12 +43,17 @@
     private static final String H264_CROPPED_VIDEO_FILE_NAME = "520x360h264decodertest.mp4";
     private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90;
     private static final int OFFSET = 10;
+    private static final int PER_TEST_TIMEOUT_S = 30;
 
     private View videoView;
     private VideoViewFactory videoViewFactory;
 
+    @Rule
+    public Timeout globalTimeout = Timeout.seconds(PER_TEST_TIMEOUT_S);
+
+    @After
     @Override
-    protected void tearDown() throws Exception {
+    public void tearDown() throws Exception {
         if (videoView != null) {
             getHelper().cleanUpView(videoView);
         }
@@ -48,36 +64,42 @@
     }
 
     /* <------------- Tests Using H264 -------------> */
+    @Test
     public void testH264GLViewVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
                 new GLSurfaceViewFactory(),
                 new VideoFormat(H264_VIDEO_FILE_NAME));
     }
 
+    @Test
     public void testH264GLViewLargerHeightVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
                 new GLSurfaceViewFactory(),
                 getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
     }
 
+    @Test
     public void testH264GLViewLargerWidthVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
                 new GLSurfaceViewFactory(),
                 getLargerWidthVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
     }
 
+    @Test
     public void testH264SurfaceViewVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
                 new SurfaceViewFactory(),
                 new VideoFormat(H264_VIDEO_FILE_NAME));
     }
 
+    @Test
     public void testH264SurfaceViewLargerHeightVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
                 new SurfaceViewFactory(),
                 getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
     }
 
+    @Test
     public void testH264SurfaceViewLargerWidthVideoDecode() throws Exception {
         runH264DecodeAccuracyTest(
                 new SurfaceViewFactory(),
@@ -85,36 +107,42 @@
     }
 
     /* <------------- Tests Using VP9 -------------> */
+    @Test
     public void testVP9GLViewVideoDecode() throws Exception {
         runVP9DecodeAccuracyTest(
                 new GLSurfaceViewFactory(),
                 new VideoFormat(VP9_VIDEO_FILE_NAME));
     }
 
+    @Test
     public void testVP9GLViewLargerHeightVideoDecode() throws Exception {
         runVP9DecodeAccuracyTest(
                 new GLSurfaceViewFactory(),
                 getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
     }
 
+    @Test
     public void testVP9GLViewLargerWidthVideoDecode() throws Exception {
         runVP9DecodeAccuracyTest(
                 new GLSurfaceViewFactory(),
                 getLargerWidthVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
     }
 
+    @Test
     public void testVP9SurfaceViewVideoDecode() throws Exception {
         runVP9DecodeAccuracyTest(
                 new SurfaceViewFactory(),
                 new VideoFormat(VP9_VIDEO_FILE_NAME));
     }
 
+    @Test
     public void testVP9SurfaceViewLargerHeightVideoDecode() throws Exception {
         runVP9DecodeAccuracyTest(
                 new SurfaceViewFactory(),
                 getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
     }
 
+    @Test
     public void testVP9SurfaceViewLargerWidthVideoDecode() throws Exception {
         runVP9DecodeAccuracyTest(
                 new SurfaceViewFactory(),
@@ -122,12 +150,14 @@
     }
 
     /* <------------- Tests H264 with cropping -------------> */
+    @Test
     public void testH264GLViewCroppedVideoDecode() throws Exception {
         runH264DecodeCroppedTest(
                 new GLSurfaceViewFactory(),
                 new VideoFormat(H264_CROPPED_VIDEO_FILE_NAME));
     }
 
+    @Test
     public void testH264SurfaceViewCroppedVideoDecode() throws Exception {
         runH264DecodeCroppedTest(
                 new SurfaceViewFactory(),
@@ -136,17 +166,23 @@
 
     private void runH264DecodeAccuracyTest(
             VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
-        runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertestgolden);
+        if (MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+            runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertestgolden);
+        }
     }
 
     private void runVP9DecodeAccuracyTest(
             VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
-        runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.vp9decodertestgolden);
+        if (MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+            runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.vp9decodertestgolden);
+        }
     }
 
     private void runH264DecodeCroppedTest(
             VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
-        runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertest520x360golden);
+        if (MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+            runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertest520x360golden);
+        }
     }
 
     private void runDecodeAccuracyTest(
@@ -191,7 +227,8 @@
 
     private void validateResult(
             VideoFormat videoFormat, VideoViewSnapshot videoViewSnapshot, int goldenResId) {
-        final Bitmap result = getHelper().generateBitmapFromVideoViewSnapshot(videoViewSnapshot);
+        final Bitmap result = checkNotNull("The expected bitmap from snapshot is null",
+                getHelper().generateBitmapFromVideoViewSnapshot(videoViewSnapshot));
         final Bitmap golden = getHelper().generateBitmapFromImageResourceId(goldenResId);
         final BitmapCompare.Difference difference = BitmapCompare.computeMinimumDifference(
                 result, golden, videoFormat.getOriginalWidth(), videoFormat.getOriginalHeight());
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index fae1bb4..1ce732d 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -44,6 +44,8 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 import android.util.Pair;
@@ -73,7 +75,12 @@
 import javax.microedition.khronos.egl.EGLDisplay;
 import javax.microedition.khronos.egl.EGLSurface;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
 @TargetApi(16)
+@RunWith(AndroidJUnit4.class)
 public class DecodeAccuracyTestBase
     extends ActivityInstrumentationTestCase2<DecodeAccuracyTestActivity> {
 
@@ -86,9 +93,12 @@
         super(DecodeAccuracyTestActivity.class);
     }
 
+    @Before
     @Override
-    protected void setUp() throws Exception {
+    public void setUp() throws Exception {
         super.setUp();
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+        setActivityInitialTouchMode(false);
         mActivity = getActivity();
         getInstrumentation().waitForIdleSync();
         mContext = getInstrumentation().getTargetContext();
@@ -96,8 +106,9 @@
         testHelper = new TestHelper(mContext, mActivity);
     }
 
+    @After
     @Override
-    protected void tearDown() throws Exception {
+    public void tearDown() throws Exception {
         mActivity = null;
         super.tearDown();
     }
@@ -117,6 +128,11 @@
         return reference;
     }
 
+    public static <T> T checkNotNull(String msg, T reference) {
+        assertNotNull(msg, reference);
+        return reference;
+    }
+
     public static class SimplePlayer {
 
         public static final long DECODE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1) / 2;
@@ -419,6 +435,8 @@
     /* Utility class for collecting common test case functionality. */
     class TestHelper {
 
+        private final String TAG =  TestHelper.class.getSimpleName();
+
         private final Context context;
         private final Handler handler;
         private final Activity activity;
@@ -473,13 +491,21 @@
         }
 
         public synchronized Bitmap generateBitmapFromVideoViewSnapshot(VideoViewSnapshot snapshot) {
+            final long timeOutMs = TimeUnit.SECONDS.toMillis(10);
+            final long start = SystemClock.elapsedRealtime();
             handler.post(snapshot);
             try {
-                while (!snapshot.isBitmapReady()) {
+                while (!snapshot.isBitmapReady()
+                        && (SystemClock.elapsedRealtime() - start < timeOutMs)) {
                     Thread.sleep(100);
                 }
             } catch (InterruptedException e) {
                 e.printStackTrace();
+                return null;
+            }
+            if (!snapshot.isBitmapReady()) {
+                Log.e(TAG, "Time out in generateBitmapFromVideoViewSnapshot().");
+                return null;
             }
             return snapshot.getBitmap();
         }
@@ -1165,8 +1191,7 @@
 class SurfaceViewSnapshot extends VideoViewSnapshot  {
 
     private static final String TAG = SurfaceViewSnapshot.class.getSimpleName();
-    private static final int PIXELCOPY_REQUEST_SLEEP_MS = 30;
-    private static final int PIXELCOPY_REQUEST_MAX_ATTEMPTS = 20;
+    private static final int PIXELCOPY_REQUEST_SLEEP_MS = 100;
     private static final int PIXELCOPY_TIMEOUT_MS = 1000;
 
     private final Thread copyThread;
@@ -1182,15 +1207,13 @@
                 bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
                 try {
                     // Wait for SurfaceView to be available.
-                    for (int i = 0; i < PIXELCOPY_REQUEST_MAX_ATTEMPTS; i++) {
-                        copyResult = copyHelper.request(surfaceView, bitmap);
-                        if (copyResult == PixelCopy.SUCCESS) {
-                            break;
-                        }
+                    while (copyResult != PixelCopy.SUCCESS) {
                         Thread.sleep(PIXELCOPY_REQUEST_SLEEP_MS);
+                        copyResult = copyHelper.request(surfaceView, bitmap);
                     }
                 } catch (InterruptedException e) {
-                    Log.w(TAG, "Pixel Copy is stopped/interrupted before it finishes.", e);
+                    Log.e(TAG, "Pixel Copy is stopped/interrupted before it finishes.", e);
+                    bitmap = null;
                 }
                 copyHelper.release();
             }
@@ -1294,10 +1317,10 @@
         try {
             waitForByteBuffer();
         } catch (InterruptedException e) {
-            Log.w(TAG, e.getMessage());
-            Log.w(TAG, "ByteBuffer may contain incorrect pixels.");
+            Log.e(TAG, e.getMessage());
+            bitmap = null;
+            return;
         }
-        // Get ByteBuffer anyway. Let the test fail if ByteBuffer contains incorrect pixels.
         ByteBuffer byteBuffer = glSurfaceViewFactory.getByteBuffer();
         bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
         byteBuffer.rewind();
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 13ebeff..3025306 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -501,9 +501,9 @@
 
     private void testTrackSelection(int resid) throws Exception {
         AssetFileDescriptor fd1 = null;
+        MediaExtractor ex1 = new MediaExtractor();
         try {
             fd1 = mResources.openRawResourceFd(resid);
-            MediaExtractor ex1 = new MediaExtractor();
             ex1.setDataSource(fd1.getFileDescriptor(), fd1.getStartOffset(), fd1.getLength());
 
             ByteBuffer buf1 = ByteBuffer.allocate(1024*1024);
@@ -664,6 +664,9 @@
             }
 
         } finally {
+            if (ex1 != null) {
+                ex1.release();
+            }
             if (fd1 != null) {
                 fd1.close();
             }
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index b3f7a35..9dbcd5e 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -423,52 +423,55 @@
                 Log.i(TAG, "start encoding");
             }
             EncodingHelper encodingHelper = new EncodingHelper();
-            mEncodingSurface = encodingHelper.startEncoding(maxSize.getWidth(), maxSize.getHeight(),
-                    mEncoderEventListener);
-            GlCompositor compositor = new GlCompositor();
-            if (DBG) {
-                Log.i(TAG, "start composition");
-            }
-            compositor.startComposition(mEncodingSurface, maxSize.getWidth(), maxSize.getHeight(),
-                    numDisplays);
-            for (int j = 0; j < NUM_DISPLAY_CREATION; j++) {
+            try {
+                mEncodingSurface = encodingHelper.startEncoding(
+                        maxSize.getWidth(), maxSize.getHeight(), mEncoderEventListener);
+                GlCompositor compositor = new GlCompositor();
                 if (DBG) {
-                    Log.i(TAG, "create display");
+                    Log.i(TAG, "start composition");
                 }
-                for (int k = 0; k < numDisplays; k++) {
-                    virtualDisplays[k] =
-                        new VirtualDisplayPresentation(getContext(),
-                                compositor.getWindowSurface(k),
-                                maxSize.getWidth()/numDisplays, maxSize.getHeight());
-                    virtualDisplays[k].createVirtualDisplay();
-                    virtualDisplays[k].createPresentation();
-                }
-                if (DBG) {
-                    Log.i(TAG, "start rendering");
-                }
-                for (int k = 0; k < NUM_RENDERING; k++) {
-                    for (int l = 0; l < numDisplays; l++) {
-                        virtualDisplays[l].doRendering(COLOR_RED);
+                compositor.startComposition(mEncodingSurface,
+                        maxSize.getWidth(), maxSize.getHeight(), numDisplays);
+                for (int j = 0; j < NUM_DISPLAY_CREATION; j++) {
+                    if (DBG) {
+                        Log.i(TAG, "create display");
                     }
-                    // do not care how many frames are actually rendered.
-                    Thread.sleep(1);
+                    for (int k = 0; k < numDisplays; k++) {
+                        virtualDisplays[k] =
+                            new VirtualDisplayPresentation(getContext(),
+                                    compositor.getWindowSurface(k),
+                                    maxSize.getWidth()/numDisplays, maxSize.getHeight());
+                        virtualDisplays[k].createVirtualDisplay();
+                        virtualDisplays[k].createPresentation();
+                    }
+                    if (DBG) {
+                        Log.i(TAG, "start rendering");
+                    }
+                    for (int k = 0; k < NUM_RENDERING; k++) {
+                        for (int l = 0; l < numDisplays; l++) {
+                            virtualDisplays[l].doRendering(COLOR_RED);
+                        }
+                        // do not care how many frames are actually rendered.
+                        Thread.sleep(1);
+                    }
+                    for (int k = 0; k < numDisplays; k++) {
+                        virtualDisplays[k].dismissPresentation();
+                        virtualDisplays[k].destroyVirtualDisplay();
+                    }
+                    compositor.recreateWindows();
                 }
-                for (int k = 0; k < numDisplays; k++) {
-                    virtualDisplays[k].dismissPresentation();
-                    virtualDisplays[k].destroyVirtualDisplay();
+                if (DBG) {
+                    Log.i(TAG, "stop composition");
                 }
-                compositor.recreateWindows();
+                compositor.stopComposition();
+            } finally {
+                if (DBG) {
+                    Log.i(TAG, "stop encoding");
+                }
+                encodingHelper.stopEncoding();
+                assertTrue(mCodecConfigReceived);
+                assertTrue(mCodecBufferReceived);
             }
-            if (DBG) {
-                Log.i(TAG, "stop composition");
-            }
-            compositor.stopComposition();
-            if (DBG) {
-                Log.i(TAG, "stop encoding");
-            }
-            encodingHelper.stopEncoding();
-            assertTrue(mCodecConfigReceived);
-            assertTrue(mCodecBufferReceived);
         }
     }
 
@@ -553,15 +556,15 @@
                 throw new RuntimeException("encoder "+ MIME_TYPE + " not support : " + format.toString());
             }
 
-            mEncoder = MediaCodec.createByCodecName(codecName);
-            mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
-            mEncodingSurface = mEncoder.createInputSurface();
-            mEncoder.start();
-            mInitCompleted.release();
-            if (DBG) {
-                Log.i(TAG, "starting encoder");
-            }
             try {
+                mEncoder = MediaCodec.createByCodecName(codecName);
+                mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+                mEncodingSurface = mEncoder.createInputSurface();
+                mEncoder.start();
+                mInitCompleted.release();
+                if (DBG) {
+                    Log.i(TAG, "starting encoder");
+                }
                 ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
                 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                 while (!mStopEncoding) {
@@ -596,11 +599,15 @@
                 e.printStackTrace();
                 throw e;
             } finally {
-                mEncoder.stop();
-                mEncoder.release();
-                mEncoder = null;
-                mEncodingSurface.release();
-                mEncodingSurface = null;
+                if (mEncoder != null) {
+                    mEncoder.stop();
+                    mEncoder.release();
+                    mEncoder = null;
+                }
+                if (mEncodingSurface != null) {
+                    mEncodingSurface.release();
+                    mEncodingSurface = null;
+                }
             }
         }
     }
diff --git a/tests/tests/media/src/android/media/cts/EncoderTest.java b/tests/tests/media/src/android/media/cts/EncoderTest.java
index adb2351..e086347 100644
--- a/tests/tests/media/src/android/media/cts/EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/EncoderTest.java
@@ -161,7 +161,7 @@
         try {
             pool.shutdown();
             assertTrue("timed out waiting for encoder threads",
-                    pool.awaitTermination(5, TimeUnit.MINUTES));
+                    pool.awaitTermination(10, TimeUnit.MINUTES));
         } catch (InterruptedException e) {
             fail("interrupted while waiting for encoder threads");
         }
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index 7258303..2ba10df 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -976,13 +976,14 @@
         boolean success = false;
         Surface surface = null;
         int noOfFailure = 0;
-        final float frameRate = getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H264);
 
         if (!hasH264()) {
             MediaUtils.skipTest("no codecs");
             return true;
         }
 
+        final float frameRate = getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H264);
+
         try {
             if (persistent) {
                 surface = MediaCodec.createPersistentInputSurface();
diff --git a/tests/tests/mediastress/preconditions/Android.mk b/tests/tests/mediastress/preconditions/Android.mk
index 139bf23..573f083 100644
--- a/tests/tests/mediastress/preconditions/Android.mk
+++ b/tests/tests/mediastress/preconditions/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/tests/tests/mediastress/preconditions/tests/Android.mk b/tests/tests/mediastress/preconditions/tests/Android.mk
index 28549f5..e2dae48 100644
--- a/tests/tests/mediastress/preconditions/tests/Android.mk
+++ b/tests/tests/mediastress/preconditions/tests/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := easymock
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt compatibility-host-media-preconditions
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed compatibility-host-media-preconditions
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 6697f7e..0c564a7 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -51,3 +51,34 @@
 include $(BUILD_CTS_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
+
+# platform version check (b/32056228)
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-platform-version-check
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+cts_platform_version_path := cts/tests/tests/os/assets/platform_versions.txt
+cts_platform_version_string := $(shell cat $(cts_platform_version_path))
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE) : $(cts_platform_version_path) build/core/version_defaults.mk
+	$(hide) if [ -z "$(findstring $(PLATFORM_VERSION),$(cts_platform_version_string))" ]; then \
+		echo "============================================================" 1>&2; \
+		echo "Could not find version \"$(PLATFORM_VERSION)\" in CTS platform version file:" 1>&2; \
+		echo "" 1>&2; \
+		echo "	$(cts_platform_version_path)" 1>&2; \
+		echo "" 1>&2; \
+		echo "Most likely PLATFORM_VERSION in build/core/version_defaults.mk" 1>&2; \
+		echo "has changed and a new version must be added to this CTS file." 1>&2; \
+		echo "============================================================" 1>&2; \
+		exit 1; \
+	fi
+	@mkdir -p $(dir $@)
+	echo $(cts_platform_version_string) > $@
diff --git a/tests/tests/os/assets/minijail/isolated-arm.policy b/tests/tests/os/assets/minijail/isolated-arm.policy
index e5e5e6f..2e47d92 100644
--- a/tests/tests/os/assets/minijail/isolated-arm.policy
+++ b/tests/tests/os/assets/minijail/isolated-arm.policy
@@ -41,8 +41,8 @@
 mkdir: return EPERM
 mknod: return EPERM
 
-# mmap2: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap2: 1
+# mmap2: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap2: arg3 in 0x24833
 
 _newselect: 1
 open: 1
diff --git a/tests/tests/os/assets/minijail/isolated-arm64.policy b/tests/tests/os/assets/minijail/isolated-arm64.policy
index e092751..66be1f7 100644
--- a/tests/tests/os/assets/minijail/isolated-arm64.policy
+++ b/tests/tests/os/assets/minijail/isolated-arm64.policy
@@ -3,7 +3,7 @@
 getdents64: 1
 getrlimit: 1
 
-# mmap: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap: 1
+# mmap: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap: arg3 in 0x24833
 
 newfstatat: 1
diff --git a/tests/tests/os/assets/minijail/isolated-common.policy b/tests/tests/os/assets/minijail/isolated-common.policy
index f44486e..48cfd49 100644
--- a/tests/tests/os/assets/minijail/isolated-common.policy
+++ b/tests/tests/os/assets/minijail/isolated-common.policy
@@ -77,9 +77,8 @@
 mknodat: return EPERM
 mlock: 1
 
-# mprotect: TODO(rsesek): Restrict arg2 (prot) to ~(PROT_READ | PROT_WRITE | PROT_EXEC)
-#                         after http://b/31997910 is fixed.
-mprotect: 1
+# mprotect: prot in {PROT_READ|PROT_WRITE|PROT_EXEC}
+mprotect: arg2 in 0x7
 
 mremap: 1
 msync: 1
diff --git a/tests/tests/os/assets/minijail/isolated-i386.policy b/tests/tests/os/assets/minijail/isolated-i386.policy
index 43ece54..a5798d0 100644
--- a/tests/tests/os/assets/minijail/isolated-i386.policy
+++ b/tests/tests/os/assets/minijail/isolated-i386.policy
@@ -39,10 +39,9 @@
 mkdir: return EPERM
 mknod: return EPERM
 
-# mmap2: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap2: 1
-# mmap: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap: 1
+# mmap2: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap2: arg3 in 0x24833
+mmap: arg3 in 0x24833
 
 _newselect: 1
 oldlstat: return EPERM
diff --git a/tests/tests/os/assets/minijail/isolated-x86-64.policy b/tests/tests/os/assets/minijail/isolated-x86-64.policy
index bbbbb90..45ea743 100644
--- a/tests/tests/os/assets/minijail/isolated-x86-64.policy
+++ b/tests/tests/os/assets/minijail/isolated-x86-64.policy
@@ -24,8 +24,8 @@
 mkdir: return EPERM
 mknod: return EPERM
 
-# mmap: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap: 1
+# mmap: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap: arg3 in 0x24833
 
 newfstatat: 1
 open: 1
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
new file mode 100644
index 0000000..2638c45
--- /dev/null
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -0,0 +1 @@
+O
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index e39249b..d06171b 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -16,10 +16,16 @@
 
 package android.os.cts;
 
+import android.content.res.AssetManager;
 import android.os.Build;
 import android.platform.test.annotations.RestrictedBuildTest;
+import android.support.test.InstrumentationRegistry;
 import android.util.Log;
 
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
@@ -29,17 +35,16 @@
 public class BuildVersionTest extends TestCase {
 
     private static final String LOG_TAG = "BuildVersionTest";
-    private static final Set<String> EXPECTED_RELEASES =
-            new HashSet<String>(Arrays.asList("7.1","7.1.1","7.1.2"));
     private static final int EXPECTED_SDK = 25;
     private static final String EXPECTED_BUILD_VARIANT = "user";
     private static final String EXPECTED_TAG = "release-keys";
+    private static final String PLATFORM_VERSIONS_FILE = "platform_versions.txt";
 
     @SuppressWarnings("deprecation")
     @RestrictedBuildTest
     public void testReleaseVersion() {
         // Applications may rely on the exact release version
-        assertAnyOf("BUILD.VERSION.RELEASE", Build.VERSION.RELEASE, EXPECTED_RELEASES);
+        assertAnyOf("BUILD.VERSION.RELEASE", Build.VERSION.RELEASE, getExpectedReleases());
         assertEquals("Build.VERSION.SDK", "" + EXPECTED_SDK, Build.VERSION.SDK);
         assertEquals("Build.VERSION.SDK_INT", EXPECTED_SDK, Build.VERSION.SDK_INT);
     }
@@ -94,4 +99,20 @@
                      ", should be one of: " + permittedValues);
         }
     }
+
+    private Set<String> getExpectedReleases() {
+        Set<String> expectedReleases = new HashSet<String>();
+        final AssetManager assets =
+                InstrumentationRegistry.getInstrumentation().getTargetContext().getAssets();
+        String line;
+        try (BufferedReader br =
+                new BufferedReader(new InputStreamReader(assets.open(PLATFORM_VERSIONS_FILE)))) {
+            while ((line = br.readLine()) != null) {
+                expectedReleases.add(line);
+            }
+        } catch (IOException e) {
+            fail("Could not open file " + PLATFORM_VERSIONS_FILE + " to run test");
+        }
+        return expectedReleases;
+    }
 }
diff --git a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
index f93aacf..2a4b6da 100644
--- a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
@@ -16,31 +16,40 @@
 
 package android.permission.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.media.AudioManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test the non-location-related functionality of TelephonyManager.
  */
-public class TelephonyManagerPermissionTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class TelephonyManagerPermissionTest {
 
     private boolean mHasTelephony;
     TelephonyManager mTelephonyManager = null;
     private AudioManager mAudioManager;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mHasTelephony = getContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_TELEPHONY);
-        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        mTelephonyManager =
+                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
         assertNotNull(mTelephonyManager);
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
         assertNotNull(mAudioManager);
     }
 
@@ -50,7 +59,7 @@
      * Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE}.
      */
-    @SmallTest
+    @Test
     public void testGetDeviceId() {
         if (!mHasTelephony) {
             return;
@@ -76,7 +85,7 @@
      * Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE}.
      */
-    @SmallTest
+    @Test
     public void testGetLine1Number() {
         if (!mHasTelephony) {
             return;
@@ -96,7 +105,7 @@
      * Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE}.
      */
-    @SmallTest
+    @Test
     public void testGetSimSerialNumber() {
         if (!mHasTelephony) {
             return;
@@ -116,7 +125,7 @@
      * Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE}.
      */
-    @SmallTest
+    @Test
     public void testGetSubscriberId() {
         if (!mHasTelephony) {
             return;
@@ -136,7 +145,7 @@
      * Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE}.
      */
-    @SmallTest
+    @Test
     public void testVoiceMailNumber() {
         if (!mHasTelephony) {
             return;
@@ -157,7 +166,7 @@
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE} for
      * {@link AudioManager#MODE_IN_CALL}.
      */
-    @SmallTest
+    @Test
     public void testSetMode() {
         if (!mHasTelephony) {
             return;
@@ -168,9 +177,28 @@
     }
 
     /**
+     * Verify that TelephonyManager.setDataEnabled requires Permission.
+     * <p>
+     * Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
+     */
+    @Test
+    public void testSetDataEnabled() {
+        if (!mHasTelephony) {
+            return;
+        }
+        try {
+            mTelephonyManager.setDataEnabled(false);
+            fail("Able to set data enabled");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
      * Verify that Telephony related broadcasts are protected.
      */
-    @SmallTest
+    @Test
     public void testProtectedBroadcasts() {
         if (!mHasTelephony) {
             return;
@@ -215,4 +243,8 @@
         } catch (SecurityException e) {}
 
     }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
 }
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index ee51fea..eb0406e 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctsdeviceutil ctstestrunner
+    ctsdeviceutil ctstestrunner ub-uiautomator
 
 LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 1c34dfa..8c1c3cc 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -51,6 +51,8 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.provider.cts.GetResultActivity" />
+
         <service android:name="android.provider.cts.contacts.account.MockAccountService"
                  process="android.provider.cts"
                  android:exported="true">
diff --git a/tests/tests/provider/src/android/provider/cts/GetResultActivity.java b/tests/tests/provider/src/android/provider/cts/GetResultActivity.java
new file mode 100644
index 0000000..382ca6f
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/GetResultActivity.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+
+public class GetResultActivity extends Activity {
+    private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+
+    public static class Result {
+        public final int requestCode;
+        public final int resultCode;
+        public final Intent data;
+
+        public Result(int requestCode, int resultCode, Intent data) {
+            this.requestCode = requestCode;
+            this.resultCode = resultCode;
+            this.data = data;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        try {
+            mResult.offer(new Result(requestCode, resultCode, data), 5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Result getResult() {
+        final Result result;
+        try {
+            result = mResult.poll(30, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+        if (result == null) {
+            throw new IllegalStateException("Activity didn't receive a Result in 30 seconds");
+        }
+        return result;
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
new file mode 100644
index 0000000..3ede99c
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.cts;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.UriPermission;
+import android.content.pm.PackageManager;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.cts.GetResultActivity.Result;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.text.format.DateUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class MediaStoreUiTest extends InstrumentationTestCase {
+
+    private static final int REQUEST_CODE = 42;
+    private static final String CONTENT = "Test";
+
+    private UiDevice mDevice;
+    private GetResultActivity mActivity;
+
+    private File mFile;
+    private Uri mMediaStoreUri;
+
+    @Override
+    public void setUp() throws Exception {
+        mDevice = UiDevice.getInstance(getInstrumentation());
+
+        final Context context = getInstrumentation().getContext();
+        mActivity = launchActivity(context.getPackageName(), GetResultActivity.class, null);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (mFile != null) {
+            mFile.delete();
+        }
+
+        final ContentResolver resolver = mActivity.getContentResolver();
+        for (UriPermission permission : resolver.getPersistedUriPermissions()) {
+            mActivity.revokeUriPermission(
+                    permission.getUri(),
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION
+                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        }
+
+        mActivity.finish();
+    }
+
+    public void testGetDocumentUri() throws Exception {
+        if (!supportsHardware()) return;
+
+        prepareFile();
+
+        final Uri treeUri = acquireAccess(mFile, Environment.DIRECTORY_DOCUMENTS);
+        assertNotNull(treeUri);
+
+        final Uri docUri = MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
+        assertNotNull(docUri);
+
+        final ContentResolver resolver = mActivity.getContentResolver();
+        try (ParcelFileDescriptor fd = resolver.openFileDescriptor(docUri, "rw")) {
+            // Test reading
+            try (final BufferedReader reader =
+                         new BufferedReader(new FileReader(fd.getFileDescriptor()))) {
+                assertEquals(CONTENT, reader.readLine());
+            }
+
+            // Test writing
+            try (final OutputStream out = new FileOutputStream(fd.getFileDescriptor())) {
+                out.write(CONTENT.getBytes());
+            }
+        }
+    }
+
+    public void testGetDocumentUri_ThrowsWithoutPermission() throws Exception {
+        if (!supportsHardware()) return;
+
+        prepareFile();
+
+        try {
+            MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
+            fail("Expecting SecurityException.");
+        } catch (SecurityException e) {
+            // Expected
+        }
+    }
+
+    private boolean supportsHardware() {
+        final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+        return !pm.hasSystemFeature("android.hardware.type.television")
+                && !pm.hasSystemFeature("android.hardware.type.watch");
+    }
+
+    private void prepareFile() throws Exception {
+        assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+
+        final File documents =
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
+        documents.mkdirs();
+        assertTrue(documents.isDirectory());
+
+        mFile = new File(documents, "test.txt");
+        try (OutputStream os = new FileOutputStream(mFile)) {
+            os.write(CONTENT.getBytes());
+        }
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        MediaScannerConnection.scanFile(
+                mActivity,
+                new String[]{ mFile.getAbsolutePath() },
+                new String[]{ "plain/text" },
+                (String path, Uri uri) -> onScanCompleted(uri, latch)
+        );
+        assertTrue(
+                "MediaScanner didn't finish scanning in 30s.", latch.await(30, TimeUnit.SECONDS));
+    }
+
+    private void onScanCompleted(Uri uri, CountDownLatch latch) {
+        mMediaStoreUri = uri;
+        latch.countDown();
+    }
+
+    private Uri acquireAccess(File file, String directoryName) {
+        StorageManager storageManager =
+                (StorageManager) mActivity.getSystemService(Context.STORAGE_SERVICE);
+
+        // Request access from DocumentsUI
+        final StorageVolume volume = storageManager.getStorageVolume(file);
+        final Intent intent = volume.createAccessIntent(directoryName);
+        mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+        // Granting the access
+        BySelector buttonPanelSelector = By.pkg("com.android.documentsui")
+                .res("android:id/buttonPanel");
+        mDevice.wait(Until.hasObject(buttonPanelSelector), 30 * DateUtils.SECOND_IN_MILLIS);
+        final UiObject2 buttonPanel = mDevice.findObject(buttonPanelSelector);
+        final UiObject2 allowButton = buttonPanel.findObject(By.res("android:id/button1"));
+        allowButton.click();
+
+        mDevice.waitForIdle();
+
+        // Check granting result and take persistent permission
+        final Result result = mActivity.getResult();
+        assertEquals(Activity.RESULT_OK, result.resultCode);
+
+        final Intent resultIntent = result.data;
+        final Uri resultUri = resultIntent.getData();
+        final int flags = resultIntent.getFlags()
+                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        mActivity.getContentResolver().takePersistableUriPermission(resultUri, flags);
+        return resultUri;
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index 5ec765c..485b39c 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -228,6 +228,9 @@
 
     private Uri insertVideo(Context context) throws IOException {
         File file = new File(Environment.getExternalStorageDirectory(), "testVideo.3gp");
+        // clean up any potential left over entries from a previous aborted run
+        cleanExternalMediaFile(file.getAbsolutePath());
+
         new FileCopyHelper(context).copyToExternalStorage(R.raw.testvideo, file);
 
         ContentValues values = new ContentValues();
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 4668107..c739fa5 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -26,35 +26,13 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
 
 LOCAL_JNI_SHARED_LIBRARIES := libctssecurity_jni libcts_jni libnativehelper_compat_libc++ \
-		libnativehelper \
-		libbinder \
-		libutils \
-		libmedia \
-		libselinux \
-		libcutils \
-		libcrypto \
-		libc++ \
-		libbacktrace \
-		libui \
-		libsonivox \
-		libexpat \
-		libcamera_client \
-		libgui \
-		libaudioutils \
-		libaudiohal \
-		libnbaio \
-		libpcre2 \
-		libpackagelistparser \
-		libpowermanager \
-		libbase \
-		libunwind \
-		libhardware \
-		libsync \
-		libcamera_metadata \
-		libspeexresampler \
-		liblzma \
-		libstagefright_foundation \
-		libeffects
+                      libnativehelper \
+                      libcutils \
+                      libcrypto \
+                      libselinux \
+                      libc++ \
+                      libpcre2 \
+                      libpackagelistparser
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)\
                    src/android/security/cts/activity/ISecureRandomService.aidl\
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 2a94aff..5b8b49e 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,39 +31,16 @@
 		android_security_cts_MMapExecutableTest.cpp \
 		android_security_cts_EncryptionTest.cpp \
 
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
-										$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := libnativehelper \
+LOCAL_SHARED_LIBRARIES := \
+		libnativehelper \
 		liblog \
-		libutils \
-		libmedia \
-		libselinux \
-		libdl \
 		libcutils \
 		libcrypto \
+		libselinux \
 		libc++ \
-		libbacktrace \
-		libui \
-		libsonivox \
-		libexpat \
-		libcamera_client \
-		libgui \
-		libaudioutils \
-		libaudiohal \
-		libnbaio \
 		libpcre2 \
 		libpackagelistparser \
-		libpowermanager \
-		libbase \
-		libunwind \
-		libhardware \
-		libsync \
-		libcamera_metadata \
-		libspeexresampler \
-		liblzma \
-		libstagefright_foundation \
-		libeffects
+
 
 LOCAL_C_INCLUDES += ndk/sources/cpufeatures
 LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/res/raw/bug_31647370.ogg b/tests/tests/security/res/raw/bug_31647370.ogg
new file mode 100644
index 0000000..31f602a
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_31647370.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/onekhzsine_90sec.mp3 b/tests/tests/security/res/raw/onekhzsine_90sec.mp3
new file mode 100644
index 0000000..3049011
--- /dev/null
+++ b/tests/tests/security/res/raw/onekhzsine_90sec.mp3
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BrowserTest.java b/tests/tests/security/src/android/security/cts/BrowserTest.java
index 0948713..f468d66 100644
--- a/tests/tests/security/src/android/security/cts/BrowserTest.java
+++ b/tests/tests/security/src/android/security/cts/BrowserTest.java
@@ -172,7 +172,13 @@
 
             // do a file request
             intent.setData(Uri.fromFile(htmlFile));
-            mContext.startActivity(intent);
+
+            try {
+                mContext.startActivity(intent);
+            } catch (SecurityException e) {
+                // If browser activity cannot be started, skip the test.
+                continue;
+            }
 
             /*
              * Wait 5 seconds for the browser to contact the server, but
diff --git a/tests/tests/security/src/android/security/cts/EffectBundleTest.java b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
index 6361a54..2fa4218 100644
--- a/tests/tests/security/src/android/security/cts/EffectBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
@@ -22,50 +22,135 @@
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
 public class EffectBundleTest extends InstrumentationTestCase {
     private static final String TAG = "EffectBundleTest";
-    private static final int[] BAND_ARRAY = {Integer.MIN_VALUE, -10000, -100, -2, -1};
+    private static final int[] INVALID_BAND_ARRAY = {Integer.MIN_VALUE, -10000, -100, -2, -1};
     private static final int mValue0 = 9999; //unlikely values. Should not change
     private static final int mValue1 = 13877;
+    private static final int PRESET_CUSTOM = -1; //keep in sync AudioEqualizer.h
+
+    private static final int MEDIA_SHORT = 0;
+    private static final int MEDIA_LONG = 1;
 
     //Testing security bug: 32436341
     public void testEqualizer_getParamCenterFreq() throws Exception {
-        testGetParam(Equalizer.PARAM_CENTER_FREQ, BAND_ARRAY, mValue0, mValue1);
+        testGetParam(MEDIA_SHORT, Equalizer.PARAM_CENTER_FREQ, INVALID_BAND_ARRAY, mValue0,
+                mValue1);
+    }
+
+    //Testing security bug: 32588352
+    public void testEqualizer_getParamCenterFreq_long() throws Exception {
+        testGetParam(MEDIA_LONG, Equalizer.PARAM_CENTER_FREQ, INVALID_BAND_ARRAY, mValue0, mValue1);
     }
 
     //Testing security bug: 32438598
     public void testEqualizer_getParamBandLevel() throws Exception {
-        testGetParam(Equalizer.PARAM_BAND_LEVEL, BAND_ARRAY, mValue0, mValue1);
+        testGetParam(MEDIA_SHORT, Equalizer.PARAM_BAND_LEVEL, INVALID_BAND_ARRAY, mValue0, mValue1);
+    }
+
+    //Testing security bug: 32584034
+    public void testEqualizer_getParamBandLevel_long() throws Exception {
+        testGetParam(MEDIA_LONG, Equalizer.PARAM_BAND_LEVEL, INVALID_BAND_ARRAY, mValue0, mValue1);
     }
 
     //Testing security bug: 32247948
     public void testEqualizer_getParamFreqRange() throws Exception {
-        testGetParam(Equalizer.PARAM_BAND_FREQ_RANGE, BAND_ARRAY, mValue0, mValue1);
+        testGetParam(MEDIA_SHORT, Equalizer.PARAM_BAND_FREQ_RANGE, INVALID_BAND_ARRAY, mValue0,
+                mValue1);
     }
 
-    private void testGetParam(int command, int[] bandArray, int value0, int value1) {
+    //Testing security bug: 32588756
+    public void testEqualizer_getParamFreqRange_long() throws Exception {
+        testGetParam(MEDIA_LONG, Equalizer.PARAM_BAND_FREQ_RANGE, INVALID_BAND_ARRAY, mValue0,
+                mValue1);
+    }
+
+    //Testing security bug: 32448258
+    public void testEqualizer_getParamPresetName() throws Exception {
+        testParamPresetName(MEDIA_SHORT);
+    }
+
+    //Testing security bug: 32588016
+    public void testEqualizer_getParamPresetName_long() throws Exception {
+        testParamPresetName(MEDIA_LONG);
+    }
+
+    private void testParamPresetName(int media) {
+        final int command = Equalizer.PARAM_GET_PRESET_NAME;
+        for (int invalidBand : INVALID_BAND_ARRAY)
+        {
+            final byte testValue = 7;
+            byte reply[] = new byte[Equalizer.PARAM_STRING_SIZE_MAX];
+            Arrays.fill(reply, testValue);
+            if (!eqGetParam(media, command, invalidBand, reply)) {
+                fail("getParam PARAM_GET_PRESET_NAME did not complete successfully");
+            }
+            //Compare
+            if (invalidBand == PRESET_CUSTOM) {
+                final String expectedName = "Custom";
+                int length = 0;
+                while (reply[length] != 0) length++;
+                try {
+                    final String presetName =  new String(reply, 0, length,
+                            StandardCharsets.ISO_8859_1.name());
+                    assertEquals("getPresetName custom preset name failed", expectedName,
+                            presetName);
+                } catch (Exception e) {
+                    Log.w(TAG,"Problem creating reply string.");
+                }
+            } else {
+                for (int i = 0; i< reply.length; i++) {
+                    assertEquals(String.format("getParam should not change reply at byte %d", i),
+                            testValue, reply[i]);
+                }
+            }
+        }
+    }
+
+    //testing security bug: 32095626
+    public void testEqualizer_setParamBandLevel() throws Exception {
+        final int command = Equalizer.PARAM_BAND_LEVEL;
+        short[] value = { 1000 };
+        for (int invalidBand : INVALID_BAND_ARRAY)
+        {
+            if (!eqSetParam(MEDIA_SHORT, command, invalidBand, value)) {
+                fail("setParam PARAM_BAND_LEVEL did not complete successfully");
+            }
+        }
+    }
+
+    //testing security bug: 32585400
+    public void testEqualizer_setParamBandLevel_long() throws Exception {
+        final int command = Equalizer.PARAM_BAND_LEVEL;
+        short[] value = { 1000 };
+        for (int invalidBand : INVALID_BAND_ARRAY)
+        {
+            if (!eqSetParam(MEDIA_LONG, command, invalidBand, value)) {
+                fail("setParam PARAM_BAND_LEVEL did not complete successfully");
+            }
+        }
+    }
+
+    private boolean eqGetParam(int media, int command, int band, byte[] reply) {
         MediaPlayer mp = null;
         Equalizer eq = null;
+        boolean status = false;
         try {
-            mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good);
+            mp = MediaPlayer.create(getInstrumentation().getContext(), getMediaId(media));
             eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
 
-            for (int band : bandArray)
-            {
-                AudioEffect af = eq;
-                int cmd[] = {command, band};
-                int reply[] = {value0, value1};
+            AudioEffect af = eq;
+            int cmd[] = {command, band};
 
-                AudioEffect.class.getDeclaredMethod("getParameter", int[].class,
-                        int[].class).invoke(af, cmd, reply);
-
-                //values should remain the same
-                assertEquals("getParam should not change value0", value0, reply[0]);
-                assertEquals("getParam should not change value1", value1, reply[1]);
-            }
-
+            AudioEffect.class.getDeclaredMethod("getParameter", int[].class,
+                    byte[].class).invoke(af, cmd, reply);
+            status = true;
         } catch (Exception e) {
             Log.w(TAG,"Problem testing equalizer");
+            status = false;
         } finally {
             if (eq != null) {
                 eq.release();
@@ -74,5 +159,85 @@
                 mp.release();
             }
         }
+        return status;
+    }
+
+    private boolean eqGetParam(int media, int command, int band, int[] reply) {
+        MediaPlayer mp = null;
+        Equalizer eq = null;
+        boolean status = false;
+        try {
+            mp = MediaPlayer.create(getInstrumentation().getContext(), getMediaId(media));
+            eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
+
+            AudioEffect af = eq;
+            int cmd[] = {command, band};
+
+            AudioEffect.class.getDeclaredMethod("getParameter", int[].class,
+                    int[].class).invoke(af, cmd, reply);
+            status = true;
+        } catch (Exception e) {
+            Log.w(TAG,"Problem getting parameter from equalizer");
+            status = false;
+        } finally {
+            if (eq != null) {
+                eq.release();
+            }
+            if (mp != null) {
+                mp.release();
+            }
+        }
+        return status;
+    }
+
+    private void testGetParam(int media, int command, int[] bandArray, int value0, int value1) {
+        int reply[] = {value0, value1};
+        for (int invalidBand : INVALID_BAND_ARRAY)
+        {
+            if (!eqGetParam(media, command, invalidBand, reply)) {
+                fail(String.format("getParam for command %d did not complete successfully",
+                        command));
+            }
+            assertEquals("getParam should not change value0", value0, reply[0]);
+            assertEquals("getParam should not change value1", value1, reply[1]);
+        }
+    }
+
+    private boolean eqSetParam(int media, int command, int band, short[] value) {
+        MediaPlayer mp = null;
+        Equalizer eq = null;
+        boolean status = false;
+        try {
+            mp = MediaPlayer.create(getInstrumentation().getContext(),  getMediaId(media));
+            eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
+
+            AudioEffect af = eq;
+            int cmd[] = {command, band};
+
+            AudioEffect.class.getDeclaredMethod("setParameter", int[].class,
+                    short[].class).invoke(af, cmd, value);
+            status = true;
+        } catch (Exception e) {
+            Log.w(TAG,"Problem setting parameter in equalizer");
+            status = false;
+        } finally {
+            if (eq != null) {
+                eq.release();
+            }
+            if (mp != null) {
+                mp.release();
+            }
+        }
+        return status;
+    }
+
+    private int getMediaId(int media) {
+        switch (media) {
+            default:
+            case MEDIA_SHORT:
+                return R.raw.good;
+            case MEDIA_LONG:
+                return R.raw.onekhzsine_90sec;
+        }
     }
 }
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 78ce7e7..c501423 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -62,6 +62,10 @@
     public StagefrightTest() {
     }
 
+    public void testStagefright_bug_31647370() throws Exception {
+        doStagefrightTest(R.raw.bug_31647370);
+    }
+
     public void testStagefright_bug_32577290() throws Exception {
         doStagefrightTest(R.raw.bug_32577290);
     }
diff --git a/tests/tests/simpleperf/Android.mk b/tests/tests/simpleperf/Android.mk
index 0cfa49b..342752e 100644
--- a/tests/tests/simpleperf/Android.mk
+++ b/tests/tests/simpleperf/Android.mk
@@ -25,6 +25,7 @@
   libbase \
   libcutils \
   liblog \
+  libprocinfo \
   libutils \
   liblzma \
   libLLVMObject \
diff --git a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
index e7130ba..f4eee35 100644
--- a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
@@ -69,7 +69,7 @@
         assertConnectionState(connection, Connection.STATE_DISCONNECTED);
     }
 
-    public void testInCallShortPress_togglesMute() throws Exception {
+    public void testInCallLongPress_togglesMute() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
@@ -83,15 +83,15 @@
         // Before the audio state is changed for the first time, the connection might not
         // know about its audio state yet.
         assertMuteState(incallService, false);
-        sendMediaButtonShortPress();
+        sendMediaButtonLongPress();
         assertMuteState(connection, true);
         assertMuteState(incallService, true);
-        sendMediaButtonShortPress();
+        sendMediaButtonLongPress();
         assertMuteState(connection, false);
         assertMuteState(incallService, false);
     }
 
-    public void testInCallLongPress_hangupCall() throws Exception {
+    public void testInCallShortPress_hangupCall() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
@@ -105,7 +105,7 @@
         connection.setActive();
         assertCallState(call, Call.STATE_ACTIVE);
 
-        sendMediaButtonLongPress();
+        sendMediaButtonShortPress();
         assertCallState(call, Call.STATE_DISCONNECTED);
         assertConnectionState(connection, Connection.STATE_DISCONNECTED);
     }
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index abacd68..50820b2 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -16,6 +16,13 @@
 
 package android.telephony.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
 import android.content.Context;
@@ -26,20 +33,28 @@
 import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.CellLocation;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
 import android.util.Log;
+
 import com.android.internal.telephony.PhoneConstants;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.regex.Pattern;
 
-public class TelephonyManagerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class TelephonyManagerTest {
     private TelephonyManager mTelephonyManager;
     private boolean mOnCellLocationChangedCalled = false;
     private ServiceState mServiceState;
@@ -47,25 +62,24 @@
     private static final int TOLERANCE = 1000;
     private PhoneStateListener mListener;
     private static ConnectivityManager mCm;
-    private static final String TAG = "android.telephony.cts.TelephonyManagerTest";
+    private static final String TAG = "TelephonyManagerTest";
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mTelephonyManager =
                 (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
         mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         if (mListener != null) {
             // unregister the listener
             mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
         }
-        super.tearDown();
     }
 
+    @Test
     public void testListen() throws Throwable {
         if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
             Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
@@ -131,6 +145,7 @@
      * it's no need to get details of these information, just make sure they are in right
      * condition(>0 or not null).
      */
+    @Test
     public void testTelephonyManager() {
         assertTrue(mTelephonyManager.getNetworkType() >= TelephonyManager.NETWORK_TYPE_UNKNOWN);
         assertTrue(mTelephonyManager.getPhoneType() >= TelephonyManager.PHONE_TYPE_NONE);
@@ -145,8 +160,8 @@
             assertFalse(mTelephonyManager.getMmsUAProfUrl().isEmpty());
         }
 
-        // The following methods may return null. Simply call them to make sure they do not
-        // throw any exceptions.
+        // The following methods may return any value depending on the state of the device. Simply
+        // call them to make sure they do not throw any exceptions.
         mTelephonyManager.getVoiceMailNumber();
         mTelephonyManager.getSimOperatorName();
         mTelephonyManager.getNetworkCountryIso();
@@ -165,6 +180,7 @@
         mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
         mTelephonyManager.getDeviceSoftwareVersion();
         mTelephonyManager.getPhoneCount();
+        mTelephonyManager.getDataEnabled();
 
         TelecomManager telecomManager = (TelecomManager) getContext()
             .getSystemService(Context.TELECOM_SERVICE);
@@ -174,6 +190,7 @@
         mTelephonyManager.isVoicemailVibrationEnabled(defaultAccount);
     }
 
+    @Test
     public void testCreateForPhoneAccountHandle(){
         TelecomManager telecomManager = getContext().getSystemService(TelecomManager.class);
         PhoneAccountHandle handle =
@@ -182,6 +199,7 @@
         assertEquals(mTelephonyManager.getSubscriberId(), telephonyManager.getSubscriberId());
     }
 
+    @Test
     public void testCreateForPhoneAccountHandle_InvalidHandle(){
         PhoneAccountHandle handle =
                 new PhoneAccountHandle(new ComponentName("com.example.foo", "bar"), "baz");
@@ -191,6 +209,7 @@
     /**
      * Tests that the phone count returned is valid.
      */
+    @Test
     public void testGetPhoneCount() {
         int phoneCount = mTelephonyManager.getPhoneCount();
         int phoneType = mTelephonyManager.getPhoneType();
@@ -212,6 +231,7 @@
      * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
      * only a WiFi device.
      */
+    @Test
     public void testGetDeviceId() {
         String deviceId = mTelephonyManager.getDeviceId();
         verifyDeviceId(deviceId);
@@ -222,6 +242,7 @@
      * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
      * only a WiFi device.
      */
+    @Test
     public void testGetDeviceIdForSlotId() {
         String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
         verifyDeviceId(deviceId);
@@ -391,6 +412,7 @@
 
     private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
 
+    @Test
     public void testGetNetworkCountryIso() {
         PackageManager packageManager = getContext().getPackageManager();
         String countryCode = mTelephonyManager.getNetworkCountryIso();
@@ -403,6 +425,7 @@
         }
     }
 
+    @Test
     public void testGetSimCountryIso() {
         PackageManager packageManager = getContext().getPackageManager();
         String countryCode = mTelephonyManager.getSimCountryIso();
@@ -415,6 +438,7 @@
         }
     }
 
+    @Test
     public void testGetServiceState() throws InterruptedException {
         if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
             Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
@@ -445,4 +469,8 @@
 
         assertEquals(mServiceState, mTelephonyManager.getServiceState());
     }
+
+    private static Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
 }
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 1844800..4d181e8 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -266,6 +266,14 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity android:name="android.view.cts.TooltipActivity"
+                  android:label="TooltipActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/view/res/layout/tooltip_layout.xml b/tests/tests/view/res/layout/tooltip_layout.xml
new file mode 100644
index 0000000..8291b31
--- /dev/null
+++ b/tests/tests/view/res/layout/tooltip_layout.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/tooltip_layout"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <LinearLayout
+            android:id="@+id/tooltip_group"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+        <TextView
+                android:id="@+id/no_tooltip"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:text="View with no tooltip"/>
+
+        <TextView
+                android:id="@+id/has_tooltip"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dp"
+                android:text="View with tooltip"
+                android:tooltip="tooltip text"/>
+
+    </LinearLayout>
+
+    <TextView
+            android:id="@+id/no_tooltip2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="10dp"
+            android:text="Another view with no tooltip"/>
+
+    <LinearLayout
+            android:id="@+id/empty_group"
+            android:layout_width="100dp"
+            android:layout_height="30dp"
+            android:layout_margin="10dp"
+            android:background="#ddd"/>
+
+</LinearLayout>
diff --git a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
index 3b61da5..2f874fc 100644
--- a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
+++ b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
@@ -191,5 +191,3 @@
                 (firstDrawFrameMetric == 0) || (firstDrawFrameMetric == 1));
     }
 }
-
-
diff --git a/tests/tests/view/src/android/view/cts/TooltipActivity.java b/tests/tests/view/src/android/view/cts/TooltipActivity.java
new file mode 100644
index 0000000..6cb9967
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/TooltipActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.View;
+
+public class TooltipActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.tooltip_layout);
+    }
+
+    public void onCreateContextMenu(
+            ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+        menu.add("context menu");
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/TooltipTest.java b/tests/tests/view/src/android/view/cts/TooltipTest.java
new file mode 100644
index 0000000..b4c94b0
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/TooltipTest.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
+import android.cts.util.PollingCheck;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link View}.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TooltipTest {
+    private static final String LOG_TAG = "TooltipTest";
+
+    private static final long TIMEOUT_DELTA = 10000;
+    private static final long WAIT_MARGIN = 100;
+
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+    private ViewGroup mTopmostView;
+    private ViewGroup mGroupView;
+    private View mNoTooltipView;
+    private View mTooltipView;
+    private View mNoTooltipView2;
+    private View mEmptyGroup;
+
+    @Rule
+    public ActivityTestRule<TooltipActivity> mActivityRule =
+            new ActivityTestRule<>(TooltipActivity.class);
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mCtsActivityRule =
+            new ActivityTestRule<>(CtsActivity.class, false, false);
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mActivity = mActivityRule.getActivity();
+        mTopmostView = (ViewGroup) mActivity.findViewById(R.id.tooltip_layout);
+        mGroupView = (ViewGroup) mActivity.findViewById(R.id.tooltip_group);
+        mNoTooltipView = mActivity.findViewById(R.id.no_tooltip);
+        mTooltipView = mActivity.findViewById(R.id.has_tooltip);
+        mNoTooltipView2 = mActivity.findViewById(R.id.no_tooltip2);
+        mEmptyGroup = mActivity.findViewById(R.id.empty_group);
+
+        PollingCheck.waitFor(TIMEOUT_DELTA, mActivity::hasWindowFocus);
+    }
+
+    private void waitOut(long msDelay) {
+        try {
+            Thread.sleep(msDelay + WAIT_MARGIN);
+        } catch (InterruptedException e) {
+            Log.e(LOG_TAG, "Wait interrupted. Test may fail!", e);
+        }
+    }
+
+    private void setTooltip(View view, CharSequence tooltip) throws Throwable {
+        mActivityRule.runOnUiThread(() -> view.setTooltip(tooltip));
+    }
+
+    private boolean hasTooltip(View view) {
+        final View tooltipView = view.getTooltipView();
+        return tooltipView != null && tooltipView.getParent() != null;
+    }
+
+
+    private void addView(ViewGroup parent, View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> parent.addView(view));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void removeView(View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> ((ViewGroup) (view.getParent())).removeView(view));
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void callPerformLongClick(View view) throws Throwable {
+        mActivityRule.runOnUiThread(() -> view.performLongClick(0, 0));
+    }
+
+    private void requestLowProfileSystemUi() throws Throwable {
+        final int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        mActivityRule.runOnUiThread(() -> mTooltipView.setSystemUiVisibility(flag));
+        PollingCheck.waitFor(TIMEOUT_DELTA,
+                () -> (mTooltipView.getWindowSystemUiVisibility() & flag) == flag);
+    }
+
+    private void injectKeyPress(View target, int keyCode, int duration) throws Throwable {
+        if (target != null) {
+            mActivityRule.runOnUiThread(() -> {
+                target.setFocusableInTouchMode(true);
+                target.requestFocus();
+            });
+            mInstrumentation.waitForIdleSync();
+            assertTrue(target.isFocused());
+        }
+        mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+        waitOut(duration);
+        mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
+    }
+
+    private void injectArbitraryShortKeyPress() throws Throwable {
+        injectKeyPress(null, KeyEvent.KEYCODE_0, 0);
+    }
+
+    private void injectLongKeyPress(View target, int keyCode) throws Throwable {
+        injectKeyPress(target, keyCode, ViewConfiguration.getLongPressTimeout());
+    }
+
+    private void injectLongEnter(View target) throws Throwable {
+        injectLongKeyPress(target, KeyEvent.KEYCODE_ENTER);
+    }
+
+    private void injectShortClick(View target) {
+        CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, target);
+    }
+
+    private void injectLongClick(View target) {
+        CtsTouchUtils.emulateLongPressOnView(mInstrumentation, target,
+                target.getWidth() / 2, target.getHeight() / 2);
+    }
+
+    private void injectMotionEvent(MotionEvent event) {
+        mInstrumentation.sendPointerSync(event);
+    }
+
+    private void injectHoverMove(View target, int offsetX, int offsetY) {
+        injectMotionEvent(obtainMouseEvent(
+                target, MotionEvent.ACTION_HOVER_MOVE, offsetX,  offsetY));
+    }
+
+    private void injectHoverMove(View target) {
+        injectHoverMove(target, 0, 0);
+    }
+
+    private void injectLongHoverMove(View target) {
+        injectHoverMove(target);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+    }
+
+    private static MotionEvent obtainMouseEvent(View target, int action, int offsetX, int offsetY) {
+        final long eventTime = SystemClock.uptimeMillis();
+        final int[] xy = new int[2];
+        target.getLocationOnScreen(xy);
+        MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action,
+                xy[0] + target.getWidth() / 2 + offsetX, xy[1] + target.getHeight() / 2 + offsetY,
+                0);
+        event.setSource(InputDevice.SOURCE_MOUSE);
+        return event;
+    }
+
+    @Test
+    public void testGetSetTooltip() throws Throwable {
+        // No tooltip set in resource
+        assertEquals(null, mNoTooltipView.getTooltip());
+
+        // Set the tooltip, read it back
+        final String tooltipString1 = "new tooltip";
+        setTooltip(mNoTooltipView, tooltipString1);
+        assertEquals(tooltipString1, mNoTooltipView.getTooltip());
+
+        // Clear the tooltip.
+        setTooltip(mNoTooltipView, null);
+        assertEquals(null, mNoTooltipView.getTooltip());
+
+        // Check the tooltip set in resource
+        assertEquals("tooltip text", mTooltipView.getTooltip());
+
+        // Clear the tooltip set in resource
+        setTooltip(mTooltipView, null);
+        assertEquals(null, mTooltipView.getTooltip());
+
+        // Set the tooltip again, read it back
+        final String tooltipString2 = "new tooltip 2";
+        setTooltip(mTooltipView, tooltipString2);
+        assertEquals(tooltipString2, mTooltipView.getTooltip());
+    }
+
+    @Test
+    public void testNoTooltipWhenNotSet() throws Throwable {
+        callPerformLongClick(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+
+        injectLongClick(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+
+        injectLongEnter(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+    }
+
+    @Test
+    public void testNoTooltipOnDisabledView() throws Throwable {
+        mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
+
+        injectLongClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectLongEnter(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectLongHoverMove(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testUpdateOpenTooltip() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        setTooltip(mTooltipView, "updated tooltip");
+        assertTrue(hasTooltip(mTooltipView));
+
+        setTooltip(mTooltipView, null);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testTooltipHidesOnActivityFocusChange() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        CtsActivity activity = mCtsActivityRule.launchActivity(null);
+        PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mActivity.hasWindowFocus());
+        assertFalse(hasTooltip(mTooltipView));
+        activity.finish();
+    }
+
+    @Test
+    public void testTooltipHidesOnWindowFocusChange() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Show a context menu on another widget.
+        mActivity.registerForContextMenu(mNoTooltipView);
+        mActivityRule.runOnUiThread(() -> mNoTooltipView.showContextMenu(0, 0));
+
+        PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mTooltipView.hasWindowFocus());
+        mInstrumentation.waitForIdleSync();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    // Tests for tooltips triggered by long click.
+
+    @Test
+    public void testShortClickDoesNotShowTooltip() throws Throwable {
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testPerformLongClickShowsTooltipImmediately() throws Throwable {
+        callPerformLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipBlockedByLongClickListener() throws Throwable {
+        mTooltipView.setOnLongClickListener(v -> true);
+        injectLongClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipBlockedByContextMenu() throws Throwable {
+        mActivity.registerForContextMenu(mTooltipView);
+        injectLongClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnNonClickableView() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnClickableView() throws Throwable {
+        mTooltipView.setClickable(true);
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnLongClickableView() throws Throwable {
+        mTooltipView.setLongClickable(true);
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipOnContextClickableView() throws Throwable {
+        mTooltipView.setContextClickable(true);
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipStaysOnMouseMove() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip stays while the mouse moves over the widget.
+        injectHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-click-triggered tooltip stays while the mouse to another widget.
+        injectHoverMove(mNoTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesAfterUp() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-click-triggered tooltip hides after ACTION_UP (with a delay).
+        waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesOnClick() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesOnClickElsewhere() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongClickTooltipHidesOnKey() throws Throwable {
+        injectLongClick(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectArbitraryShortKeyPress();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    // Tests for tooltips triggered by long key press.
+
+    @Test
+    public void testShortKeyPressDoesNotShowTooltip() throws Throwable {
+        injectKeyPress(null, KeyEvent.KEYCODE_ENTER, 0);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectKeyPress(mTooltipView, KeyEvent.KEYCODE_ENTER, 0);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongArbitraryKeyPressDoesNotShowTooltip() throws Throwable {
+        injectLongKeyPress(mTooltipView, KeyEvent.KEYCODE_0);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressWithoutFocusDoesNotShowTooltip() throws Throwable {
+        injectLongEnter(null);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressOnAnotherViewDoesNotShowTooltip() throws Throwable {
+        injectLongEnter(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnNonClickableView() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnClickableView() throws Throwable {
+        mTooltipView.setClickable(true);
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnLongClickableView() throws Throwable {
+        mTooltipView.setLongClickable(true);
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipOnContextClickableView() throws Throwable {
+        mTooltipView.setContextClickable(true);
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipStaysOnMouseMove() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip stays while the mouse moves over the widget.
+        injectHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-keypress-triggered tooltip stays while the mouse to another widget.
+        injectHoverMove(mNoTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesAfterUp() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Long-keypress-triggered tooltip hides after ACTION_UP (with a delay).
+        waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesOnClick() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesOnClickElsewhere() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testLongKeyPressTooltipHidesOnKey() throws Throwable {
+        injectLongEnter(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectArbitraryShortKeyPress();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    // Tests for tooltips triggered by mouse hover.
+
+    @Test
+    public void testMouseClickDoesNotShowTooltip() throws Throwable {
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_DOWN, 0, 0));
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_PRESS, 0, 0));
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_RELEASE, 0, 0));
+        injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_UP, 0, 0));
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverDoesNotShowTooltipImmediately() throws Throwable {
+        injectHoverMove(mTooltipView, 0, 0);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectHoverMove(mTooltipView, 1, 1);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectHoverMove(mTooltipView, 2, 2);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverExitCancelsPendingTooltip() throws Throwable {
+        injectHoverMove(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipOnClickableView() throws Throwable {
+        mTooltipView.setClickable(true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipOnLongClickableView() throws Throwable {
+        mTooltipView.setLongClickable(true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipOnContextClickableView() throws Throwable {
+        mTooltipView.setContextClickable(true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipStaysOnMouseMove() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip stays while the mouse moves over the widget.
+        injectHoverMove(mTooltipView, 1, 1);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectHoverMove(mTooltipView, 2, 2);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnExit() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        // Tooltip hides once the mouse moves out of the widget.
+        injectHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnClick() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnClickOnElsewhere() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectShortClick(mNoTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnKey() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        injectArbitraryShortKeyPress();
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnTimeout() throws Throwable {
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        waitOut(ViewConfiguration.getHoverTooltipHideTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipHidesOnShortTimeout() throws Throwable {
+        requestLowProfileSystemUi();
+
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+
+        waitOut(ViewConfiguration.getHoverTooltipHideShortTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipWithHoverListener() throws Throwable {
+        mTooltipView.setOnHoverListener((v, event) -> true);
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipUnsetWhileHovering() throws Throwable {
+        injectHoverMove(mTooltipView);
+        setTooltip(mTooltipView, null);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipDisableWhileHovering() throws Throwable {
+        injectHoverMove(mTooltipView);
+        mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipFromParent() throws Throwable {
+        // Hover listeners should not interfere with tooltip dispatch.
+        mNoTooltipView.setOnHoverListener((v, event) -> true);
+        mTooltipView.setOnHoverListener((v, event) -> true);
+
+        setTooltip(mTopmostView, "tooltip");
+
+        // Hover over a child with a tooltip works normally.
+        injectLongHoverMove(mTooltipView);
+        assertFalse(hasTooltip(mTopmostView));
+        assertTrue(hasTooltip(mTooltipView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        // Hover over a child with no tooltip triggers a tooltip on its parent.
+        injectLongHoverMove(mNoTooltipView2);
+        assertFalse(hasTooltip(mNoTooltipView2));
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+
+        // Same but the child is and empty view group.
+        injectLongHoverMove(mEmptyGroup);
+        assertFalse(hasTooltip(mEmptyGroup));
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+
+        // Hover over a grandchild with no tooltip triggers a tooltip on its grandparent.
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+        assertTrue(hasTooltip(mTopmostView));
+        // Move to another child one level up, the tooltip stays.
+        injectHoverMove(mNoTooltipView2);
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+
+        // Set a tooltip on the intermediate parent, now it is showing tooltips.
+        setTooltip(mGroupView, "tooltip");
+        injectLongHoverMove(mNoTooltipView);
+        assertFalse(hasTooltip(mNoTooltipView));
+        assertFalse(hasTooltip(mTopmostView));
+        assertTrue(hasTooltip(mGroupView));
+
+        // Move out of this group, the tooltip is now back on the grandparent.
+        injectLongHoverMove(mNoTooltipView2);
+        assertFalse(hasTooltip(mGroupView));
+        assertTrue(hasTooltip(mTopmostView));
+        injectShortClick(mTopmostView);
+        assertFalse(hasTooltip(mTopmostView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipRemoveWhileWaiting() throws Throwable {
+        // Remove the view while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mTooltipView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mGroupView, mTooltipView);
+
+        // Remove and re-add the view while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mTooltipView);
+        addView(mGroupView, mTooltipView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+
+        // Remove the view's parent while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mGroupView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mTopmostView, mGroupView);
+
+        // Remove and re-add view's parent while hovering.
+        injectHoverMove(mTooltipView);
+        removeView(mGroupView);
+        addView(mTopmostView, mGroupView);
+        waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+        assertFalse(hasTooltip(mTooltipView));
+    }
+
+    @Test
+    public void testMouseHoverTooltipRemoveWhileShowing() throws Throwable {
+        // Remove the view while showing the tooltip.
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+        removeView(mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mGroupView, mTooltipView);
+        assertFalse(hasTooltip(mTooltipView));
+
+        // Remove the view's parent while showing the tooltip.
+        injectLongHoverMove(mTooltipView);
+        assertTrue(hasTooltip(mTooltipView));
+        removeView(mGroupView);
+        assertFalse(hasTooltip(mTooltipView));
+        addView(mTopmostView, mGroupView);
+        assertFalse(hasTooltip(mTooltipView));
+    }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 9151783..a011b97 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -2574,6 +2574,35 @@
         assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    @UiThreadTest
+    public void testGetWebViewClient() throws Exception {
+        // getWebViewClient should return a default WebViewClient if it hasn't been set yet
+        WebView webView = new WebView(getActivity());
+        WebViewClient client = webView.getWebViewClient();
+        assertNotNull(client);
+        assertTrue(client instanceof WebViewClient);
+
+        // getWebViewClient should return the client after it has been set
+        WebViewClient client2 = new WebViewClient();
+        assertNotSame(client, client2);
+        webView.setWebViewClient(client2);
+        assertSame(client2, webView.getWebViewClient());
+    }
+
+    @UiThreadTest
+    public void testGetWebChromeClient() throws Exception {
+        // getWebChromeClient should return null if the client hasn't been set yet
+        WebView webView = new WebView(getActivity());
+        WebChromeClient client = webView.getWebChromeClient();
+        assertNull(client);
+
+        // getWebChromeClient should return the client after it has been set
+        WebChromeClient client2 = new WebChromeClient();
+        assertNotSame(client, client2);
+        webView.setWebChromeClient(client2);
+        assertSame(client2, webView.getWebChromeClient());
+    }
+
     private void savePrintedPage(final PrintDocumentAdapter adapter,
             final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
         adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index f2be3c0..d8ab737 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -554,6 +554,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.PointerIconCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
         <receiver android:name="android.widget.cts.appwidget.MyAppWidgetProvider" >
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
diff --git a/tests/tests/widget/res/layout/pointer_icon_layout.xml b/tests/tests/widget/res/layout/pointer_icon_layout.xml
new file mode 100644
index 0000000..605eed2
--- /dev/null
+++ b/tests/tests/widget/res/layout/pointer_icon_layout.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/top"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Button"/>
+
+    <ImageButton
+        android:id="@+id/image_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/icon_green"/>
+
+    <Spinner
+        android:id="@+id/spinner"
+        android:layout_width="match_parent"
+        android:layout_height="20dp"/>
+
+    <TabHost
+        android:id="@android:id/tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <TabWidget
+            android:id="@android:id/tabs"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
+        <FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"/>
+
+    </TabHost>
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index 08354b1..7701726 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -277,6 +277,15 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"/>
 
+            <TextView
+                    android:id="@+id/textview_autosize_xy"
+                    android:layout_width="100dp"
+                    android:layout_height="200dp"
+                    android:text="@string/long_text"
+                    android:autoSizeText="xy"
+                    android:textSize="50dp"
+                    android:autoSizeStepGranularity="2dp" />
+
         </LinearLayout>
 
 </ScrollView>
diff --git a/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java b/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java
new file mode 100644
index 0000000..c0c6b78
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PointerIconCtsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.pointer_icon_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PointerIconTest.java b/tests/tests/widget/src/android/widget/cts/PointerIconTest.java
new file mode 100644
index 0000000..32d07a6
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PointerIconTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.cts.util.WidgetTestUtils;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.View;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PointerIconTest {
+
+    @Rule
+    public final ActivityTestRule<PointerIconCtsActivity> mActivityRule =
+            new ActivityTestRule<>(PointerIconCtsActivity.class);
+
+    private Activity mActivity;
+    private View mTopView;
+    private PointerIcon mHandIcon;
+    private PointerIcon mHelpIcon;
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mTopView = mActivity.findViewById(R.id.top);
+        mHandIcon = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND);
+        mHelpIcon = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP);
+    }
+
+    private void assertPointerIcon(String message, PointerIcon expectedIcon, View target) {
+        final int[] topPos = mTopView.getLocationOnScreen();
+        final int[] targetPos = target.getLocationOnScreen();
+        final int x = targetPos[0] + target.getWidth() / 2 - topPos[0];
+        final int y = targetPos[1] + target.getHeight() / 2 - topPos[1];
+        final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
+        assertEquals(message, expectedIcon, mTopView.onResolvePointerIcon(event, 0));
+    }
+
+    private void assertDefaultWidgetPointerIconBehavior(View view) {
+        assertPointerIcon("Default pointer icon", mHandIcon, view);
+
+        view.setEnabled(false);
+        assertPointerIcon("Disabled view has no pointer icon", null, view);
+
+        view.setEnabled(true);
+        assertPointerIcon("Enabled view has default pointer icon", mHandIcon, view);
+
+        view.setPointerIcon(mHelpIcon);
+        assertPointerIcon("Override pointer icon", mHelpIcon, view);
+
+        view.setPointerIcon(null);
+        assertPointerIcon("Revert to default pointer icon", mHandIcon, view);
+    }
+
+    private TabHost.TabSpec createTabSpec(TabHost tabHost, String label, PointerIcon pointerIcon) {
+        final TextView tabIndicator = new TextView(mActivity);
+        tabIndicator.setText(label);
+        tabIndicator.setPointerIcon(pointerIcon);
+        return tabHost.newTabSpec(label)
+                .setIndicator(tabIndicator)
+                .setContent(tag -> new View(mActivity));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testButton() {
+        assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.button));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testImageButton() {
+        assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.image_button));
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSpinnerButton() {
+        assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.spinner));
+    }
+
+    @Test
+    public void testTabWidget() throws Throwable {
+        final TabHost tabHost = (TabHost) mActivity.findViewById(android.R.id.tabhost);
+
+        WidgetTestUtils.runOnMainAndLayoutSync(
+                mActivityRule,
+                () -> {
+                    tabHost.setup();
+                    tabHost.addTab(createTabSpec(tabHost, "Tab 0", null));
+                    tabHost.addTab(createTabSpec(tabHost, "Tab 1", mHandIcon));
+                    tabHost.addTab(createTabSpec(tabHost, "Tab 2", mHelpIcon));
+                },
+                false /* force layout */);
+
+        mActivityRule.runOnUiThread(() -> {
+            final TabWidget tabWidget = tabHost.getTabWidget();
+
+            tabWidget.setEnabled(false);
+            assertPointerIcon("Disabled Tab 0", null, tabWidget.getChildTabViewAt(0));
+            assertPointerIcon("Disabled Tab 1", null, tabWidget.getChildTabViewAt(1));
+            assertPointerIcon("Disabled Tab 2", null, tabWidget.getChildTabViewAt(2));
+
+            tabWidget.setEnabled(true);
+            assertPointerIcon("Tab 0", mHandIcon, tabWidget.getChildTabViewAt(0));
+            assertPointerIcon("Tab 1", mHandIcon, tabWidget.getChildTabViewAt(1));
+            assertPointerIcon("Tab 2", mHelpIcon, tabWidget.getChildTabViewAt(2));
+        });
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index e4dbe83..074d4fa 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -6273,6 +6273,21 @@
         verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
     }
 
+    @Test
+    public void testAutoSizeXY_obtainStyledAttributes() {
+        DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
+        TextView autoSizeTextViewXY = (TextView) mActivity.findViewById(R.id.textview_autosize_xy);
+
+        // The size has been set to 50dp in the layout but this being an AUTO_SIZE_TYPE_XY TextView,
+        // the size is considered max size thus the value returned by getSize() in this case should
+        // be lower than the one set (given that there is not much available space and the font size
+        // is very high). In theory the values could be equal for a different TextView
+        // configuration.
+        final float sizeSetInPixels = TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, 50f, metrics);
+        assertTrue(autoSizeTextViewXY.getTextSize() < sizeSetInPixels);
+    }
+
     /**
      * Removes all existing views from the layout and adds a basic TextView (for exercising the
      * ClickableSpan onClick() behavior) in order to prevent scrolling. Adds a ClickableSpan to the
diff --git a/tools/cts-api-coverage/src/MANIFEST.mf b/tools/cts-api-coverage/src/MANIFEST.mf
index 63d6674..16533b5 100644
--- a/tools/cts-api-coverage/src/MANIFEST.mf
+++ b/tools/cts-api-coverage/src/MANIFEST.mf
@@ -1,3 +1,3 @@
 Manifest-Version: 1.0
 Main-Class: com.android.cts.apicoverage.CtsApiCoverage
-Class-Path: tradefed-prebuilt.jar
+Class-Path: tradefed.jar
diff --git a/tools/cts-java-scanner-doclet/Android.mk b/tools/cts-java-scanner-doclet/Android.mk
index d647537..dbd760d 100644
--- a/tools/cts-java-scanner-doclet/Android.mk
+++ b/tools/cts-java-scanner-doclet/Android.mk
@@ -22,6 +22,6 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-LOCAL_JAVA_LIBRARIES := junit
+LOCAL_JAVA_LIBRARIES := junit-host
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-media/get_achievable_rates.py b/tools/cts-media/get_achievable_rates.py
index 9dde743..369a982 100755
--- a/tools/cts-media/get_achievable_rates.py
+++ b/tools/cts-media/get_achievable_rates.py
@@ -14,36 +14,9 @@
 # limitations under the License.
 #
 
-import argparse, math, re, sys
+import argparse, json, math, re, sys, zipfile
 import xml.etree.ElementTree as ET
 from collections import defaultdict, namedtuple
-import itertools
-
-
-def createLookup(values, key):
-  """Creates a lookup table for a collection of values based on keys.
-
-  Arguments:
-    values: a collection of arbitrary values. Must be iterable.
-    key: a function of one argument that returns the key for a value.
-
-  Returns:
-    A dict mapping keys (as generated by the key argument) to lists of
-    values. All values in the lists have the same key, and are in the order
-    they appeared in the collection.
-  """
-  lookup = defaultdict(list)
-  for v in values:
-    lookup[key(v)].append(v)
-  return lookup
-
-
-def _intify(value):
-  """Returns a value converted to int if possible, else the original value."""
-  try:
-    return int(value)
-  except ValueError:
-    return value
 
 
 class Size(namedtuple('Size', ['width', 'height'])):
@@ -51,43 +24,50 @@
   def __str__(self):
     return '%dx%d' % (self.width, self.height)
 
+def nicekey(v):
+  """Returns a nicer sort key for sorting strings.
 
-class _VideoResultBase(object):
-  """Helper methods for results. Not for use by applications.
+  This sorts using lower case, with numbers in numerical order first."""
+  key = []
+  num = False
+  for p in re.split('(\d+)', v.lower()):
+    if num:
+      key.append(('0', int(p)))
+    elif p:
+      key.append((p, 0))
+    num = not num
+  return key + [(v, 0)]
 
-  Attributes:
-    codec: The name of the codec (string) or None
-    size: Size representing the video size or None
-    mime: The mime-type of the codec (string) or None
-    rates: The measured achievable frame rates
-    is_decoder: True iff codec is a decoder.
-  """
+def nice(v):
+  """Returns a nicer representation for objects in debug messages.
 
-  def __init__(self, is_decoder):
-    self.codec = None
-    self.mime = None
-    self.size = None
-    self._rates_from_failure = []
-    self._rates_from_message = []
-    self.is_decoder = is_decoder
+  Dictionaries are sorted, size is WxH, unicode removed, and floats have 1 digit precision."""
+  if isinstance(v, dict):
+    return 'dict(' + ', '.join(k + '=' + nice(v) for k, v in sorted(v.items(), key=lambda i: nicekey(i[0]))) + ')'
+  if isinstance(v, str):
+    return repr(v)
+  if isinstance(v, int):
+    return str(v)
+  if isinstance(v, Size):
+    return repr(str(v))
+  if isinstance(v, float):
+    return '%.1f' % v
+  if isinstance(v, type(u'')):
+    return repr(str(v))
+  raise ValueError(v)
 
-  def _inited(self):
-    """Returns true iff codec, mime and size was set."""
-    return None not in (self.codec, self.mime, self.size)
-
-  def __len__(self):
-    # don't report any result if codec name, mime type and size is unclear
-    if not self._inited():
-      return 0
-    return len(self.rates)
-
-  @property
-  def rates(self):
-    return self._rates_from_failure or self._rates_from_message
+class ResultParser:
+  @staticmethod
+  def _intify(value):
+    """Returns a value converted to int if possible, else the original value."""
+    try:
+      return int(value)
+    except ValueError:
+      return value
 
   def _parseDict(self, value):
     """Parses a MediaFormat from its string representation sans brackets."""
-    return dict((k, _intify(v))
+    return dict((k, self._intify(v))
                 for k, v in re.findall(r'([^ =]+)=([^ [=]+(?:|\[[^\]]+\]))(?:, |$)', value))
 
   def _cleanFormat(self, format):
@@ -110,293 +90,270 @@
       if key.endswith('Format'):
         self._cleanFormat(value)
     else:
-      value = _intify(value)
+      value = self._intify(value)
     return key, value
 
-  def _parseValuesFromBracket(self, line):
-    """Returns the values enclosed in brackets without the brackets.
 
-    Parses a line matching the pattern "<tag>: [<values>]" and returns <values>.
+def perc(data, p, fn=round):
+  """Returns a percentile value from a sorted array.
 
-    Raises:
-      ValueError: if the line does not match the pattern.
-    """
-    try:
-      return re.match(r'^[^:]+: *\[(?P<values>.*)\]\.$', line).group('values')
-    except AttributeError:
-      raise ValueError('line does not match "tag: [value]": %s' % line)
-
-  def _parseRawData(self, line):
-    """Parses the raw data line for video performance tests.
-
-    Yields:
-      Dict objects corresponding to parsed results, mapping string keys to
-      int, string or dict values.
-    """
-    try:
-      values = self._parseValuesFromBracket(line)
-      result = {}
-      for m in re.finditer(self.MESSAGE_PATTERN + r'(?P<sep>,? +|$)', values):
-        key, value = self._parsePartialResult(m)
-        result[key] = value
-        if m.group('sep') != ' ':
-          yield result
-          result = {}
-    except ValueError:
-      print >> sys.stderr, 'could not parse line %s' % repr(line)
-
-  def _tryParseMeasuredFrameRate(self, line):
-    """Parses a line starting with 'Measured frame rate:'."""
-    if line.startswith('Measured frame rate: '):
-      try:
-        values = self._parseValuesFromBracket(line)
-        values = re.split(r' *, *', values)
-        self._rates_from_failure = list(map(float, values))
-      except ValueError:
-        print >> sys.stderr, 'could not parse line %s' % repr(line)
-
-  def parse(self, test):
-    """Parses the ValueArray and FailedScene lines of a test result.
-
-    Arguments:
-      test: An ElementTree <Test> element.
-    """
-    failure = test.find('FailedScene')
-    if failure is not None:
-      trace = failure.find('StackTrace')
-      if trace is not None:
-        for line in re.split(r'[\r\n]+', trace.text):
-          self._parseFailureLine(line)
-    details = test.find('Details')
-    if details is not None:
-      for array in details.iter('ValueArray'):
-        message = array.get('message')
-        self._parseMessage(message, array)
-
-  def _parseFailureLine(self, line):
-    raise NotImplementedError
-
-  def _parseMessage(self, message, array):
-    raise NotImplementedError
-
-  def getData(self):
-    """Gets the parsed test result data.
-
-    Yields:
-       Result objects containing at least codec, size, mime and rates attributes."""
-    yield self
+  Arguments:
+    data: sorted data
+    p:    percentile value (0-100)
+    fn:   method used for rounding the percentile to an integer index in data
+  """
+  return data[int(fn((len(data) - 1) * p / 100))]
 
 
-class VideoEncoderDecoderTestResult(_VideoResultBase):
-  """Represents a result from a VideoEncoderDecoderTest performance case."""
+def genXml(data, A=None):
+  yield '<?xml version="1.0" encoding="utf-8" ?>'
+  yield '<!-- Copyright 2016 The Android Open Source Project'
+  yield ''
+  yield '     Licensed under the Apache License, Version 2.0 (the "License");'
+  yield '     you may not use this file except in compliance with the License.'
+  yield '     You may obtain a copy of the License at'
+  yield ''
+  yield '          http://www.apache.org/licenses/LICENSE-2.0'
+  yield ''
+  yield '     Unless required by applicable law or agreed to in writing, software'
+  yield '     distributed under the License is distributed on an "AS IS" BASIS,'
+  yield '     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.'
+  yield '     See the License for the specific language governing permissions and'
+  yield '     limitations under the License.'
+  yield '-->'
+  yield ''
+  yield '<MediaCodecs>'
+  last_section = None
+  from collections import namedtuple
+  Comp = namedtuple('Comp', 'is_decoder google mime name')
+  Result = namedtuple('Result', 'mn mx p95 med geo p5')
+  for comp_, cdata in sorted(data.items()):
+    comp = Comp(*comp_)
+    section = 'Decoders' if comp.is_decoder else 'Encoders'
+    if section != last_section:
+      if last_section:
+        yield '    </%s>' % last_section
+      yield '    <%s>' % section
+      last_section = section
+    yield '        <MediaCodec name="%s" type="%s" update="true">' % (comp.name, comp.mime)
+    for size, sdata in sorted(cdata.items()):
+      data = sorted(sdata)
+      N = len(data)
+      mn, mx = data[0], data[-1]
 
-  def __init__(self, unused_m):
-    super(VideoEncoderDecoderTestResult, self).__init__(is_decoder=False)
+      if N < 20 and not A.ignore:
+        raise ValueError("need at least 20 data points for %s size %s; have %s" %
+                         (comp.name, size, N))
 
-  # If a VideoEncoderDecoderTest succeeds, it provides the results in the
-  # message of a ValueArray. If fails, it provides the results in the failure
-  # using raw data. (For now it also includes some data in the ValueArrays even
-  # if it fails, which we ignore.)
+      TO = 2.2     # tolerance with margin
+      T = TO / 1.1 # tolerance without margin
 
-  def _parseFailureLine(self, line):
-    """Handles parsing a line from the failure log."""
-    self._tryParseMeasuredFrameRate(line)
-    if line.startswith('Raw data: '):
-      for result in self._parseRawData(line):
-        fmt = result['EncOutputFormat']
-        self.size = Size(fmt['width'], fmt['height'])
-        self.codec = result['codec']
-        self.mime = fmt['mime']
+      Final = namedtuple('Final', 'comment c2 var qual')
+      lastFinal = None
+      for RG in (10, 15, 20, 25, 30, 40, 50):
+        P = 50./RG
+        quality = 0
+        p95, med, p5 = perc(data, P, math.floor), perc(data, 50, round), perc(data, 100 - P, math.ceil)
+        geo = math.sqrt(p5 * p95)
+        comment = ''
+        pub_lo, pub_hi = min(int(p95 * T), round(geo)), max(math.ceil(p5 / T), round(geo))
+        if pub_lo > med:
+          if pub_lo > med * 1.1:
+            quality += 0.5
+            comment += ' SLOW'
+          pub_lo = int(med)
+        if N < 2 * RG:
+          comment += ' N=%d' % N
+          quality += 2
+        RGVAR = False
+        if p5 / p95 > T ** 3:
+          quality += 3
+          RGVAR = True
+          if pub_hi > pub_lo * TO:
+            quality += 1
+            if RG == 10:
+              # find best pub_lo and pub_hi
+              for i in range(N / 2):
+                pub_lo_, pub_hi_ = min(int(data[N / 2 - i - 1] * T), round(geo), int(med)), max(math.ceil(data[N / 2 + i] / T), round(geo))
+                if pub_hi_ > pub_lo_ * TO:
+                  # ???
+                  pub_lo = min(pub_lo, math.ceil(pub_hi_ / TO))
+                  break
+                pub_lo, pub_hi = pub_lo_, pub_hi_
+        if mn < pub_lo / T or mx > pub_hi * T or pub_lo <= pub_hi / T:
+          quality += 1
+          comment += ' FLAKY('
+          if round(mn, 1) < pub_lo / T:
+            comment += 'mn=%.1f < ' % mn
+          comment += 'RANGE'
+          if round(mx, 1) > pub_hi * T:
+            comment += ' < mx=%.1f' % mx
+          comment += ')'
+        if False:
+          comment += ' DATA(mn=%1.f p%d=%1.f accept=%1.f-%1.f p50=%1.f p%d=%1.f mx=%1.f)' % (
+            mn, 100-P, p95, pub_lo / T, pub_hi * T, med, P, p5, mx)
+        var = math.sqrt(p5/p95)
+        if p95 < geo / T or p5 > geo * T:
+          if RGVAR:
+            comment += ' RG.VARIANCE:%.1f' % ((p5/p95) ** (1./3))
+          else:
+            comment += ' variance:%.1f' % var
+        comment = comment.replace('RANGE', '%d - %d' % (math.ceil(pub_lo / T), int(pub_hi * T)))
+        c2 = ''
+        if N >= 2 * RG:
+          c2 += ' N=%d' % N
+        if var <= T or p5 / p95 > T ** 3:
+          c2 += ' v%d%%=%.1f' % (round(100 - 2 * P), var)
+        if A and A.dbg:
+          c2 += ' E=%s' % (str(quality))
+        if c2:
+          c2 = ' <!--%s -->' % c2
 
-  def _parseMessage(self, message, array):
-    """Handles parsing a message from ValueArrays."""
-    if message.startswith('codec='):
-      result = dict(self._parsePartialResult(m)
-                  for m in re.finditer(self.MESSAGE_PATTERN + '(?: |$)', message))
-      if 'EncInputFormat' in result:
-        self.codec = result['codec']
-        fmt = result['EncInputFormat']
-        self.size = Size(fmt['width'], fmt['height'])
-        self.mime = result['EncOutputFormat']['mime']
-        self._rates_from_message.append(1000000./result['min'])
+        if comment:
+          comment = '            <!-- measured %d%%:%d-%d med:%d%s -->' % (round(100 - 2 * P), int(p95), math.ceil(p5), int(round(med)), comment)
+        if A and A.dbg: yield '<!-- --> %s%s' % (comment, c2)
+        c2 = '            <Limit name="measured-frame-rate-%s" range="%d-%d" />%s' % (size, pub_lo, pub_hi, c2)
+        final = Final(comment, c2, var, quality)
+        if lastFinal and final.var > lastFinal.var * math.sqrt(1.3):
+          if A and A.dbg: yield '<!-- RANGE JUMP -->'
+          break
+        elif not lastFinal or quality <= lastFinal.qual:
+          lastFinal = final
+        if N < 2 * RG or quality >= 4:
+          break
+      comment, c2, var, quality = lastFinal
+
+      if comment:
+        yield comment
+      yield c2
+    yield '        </MediaCodec>'
+  if last_section:
+    yield '    </%s>' % last_section
+  yield '</MediaCodecs>'
 
 
-class VideoDecoderPerfTestResult(_VideoResultBase):
-  """Represents a result from a VideoDecoderPerfTest performance case."""
-
-  # If a VideoDecoderPerfTest succeeds, it provides the results in the message
-  # of a ValueArray. If fails, it provides the results in the failure only
-  # using raw data.
-
-  def __init__(self, unused_m):
-    super(VideoDecoderPerfTestResult, self).__init__(is_decoder=True)
-
-  def _parseFailureLine(self, line):
-    """Handles parsing a line from the failure log."""
-    self._tryParseMeasuredFrameRate(line)
-    # if the test failed, we can only get the codec/size/mime from the raw data.
-    if line.startswith('Raw data: '):
-      for result in self._parseRawData(line):
-        fmt = result['DecOutputFormat']
-        self.size = Size(fmt['width'], fmt['height'])
-        self.codec = result['codec']
-        self.mime = result['mime']
-
-  def _parseMessage(self, message, array):
-    """Handles parsing a message from ValueArrays."""
-    if message.startswith('codec='):
-      result = dict(self._parsePartialResult(m)
-                  for m in re.finditer(self.MESSAGE_PATTERN + '(?: |$)', message))
-      if result.get('decodeto') == 'surface':
-        self.codec = result['codec']
-        fmt = result['DecOutputFormat']
-        self.size = Size(fmt['width'], fmt['height'])
-        self.mime = result['mime']
-        self._rates_from_message.append(1000000. / result['min'])
-
-
-class Results(object):
-  """Container that keeps all test results."""
+class Data:
   def __init__(self):
-      self._results = [] # namedtuples
-      self._device = None
+    self.data = set()
+    self.kind = {}
+    self.devices = set()
+    self.parser = ResultParser()
 
-  VIDEO_ENCODER_DECODER_TEST_REGEX = re.compile(
-      'test(.*)(\d{4})x(\d{4})(Goog|Other)$')
+  def summarize(self, A=None):
+    devs = sorted(self.devices)
+    #           device  > (not encoder,goog,mime,codec)  >  size > fps
+    xmlInfo = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
 
-  VIDEO_DECODER_PERF_TEST_REGEX = re.compile(
-      'test(VP[89]|H26[34]|MPEG4|HEVC)(\d+)x(\d+)(.*)$')
+    for mime, encoder, goog in sorted(set(self.kind.values())):
+      for dev, build, codec, size, num, std, avg, p0, p5, p10, p20, p30, p40, p50, p60, p70, p80, p90, p95, p100 in self.data:
+        if self.kind[codec] != (mime, encoder, goog):
+          continue
 
-  TestCaseSpec = namedtuple('TestCaseSpec', 'package path class_ regex result_class')
+        if p95 > 2: # ignore measurements at or below 2fps
+          xmlInfo[dev][(not encoder, goog, mime, codec)][size].append(p95)
+        else:
+          print >> sys.stderr, "warning: p95 value is suspiciously low: %s" % (
+            nice(dict(config=dict(dev=dev, codec=codec, size=str(size), N=num),
+                 data=dict(std=std, avg=avg, p0=p0, p5=p5, p10=p10, p20=p20, p30=p30, p40=p40,
+                           p50=p50, p60=p60, p70=p70, p80=p80, p90=p90, p95=p95, p100=p100))))
+    for dev, ddata in xmlInfo.items():
+      outFile = '{}.media_codecs_performance.xml'.format(dev)
+      print >> sys.stderr, "generating", outFile
+      with open(outFile, "wt") as out:
+        for l in genXml(ddata, A=A):
+          out.write(l + '\n')
+          print l
+      print >> sys.stderr, "generated", outFile
 
-  def _getTestCases(self):
-    return [
-      self.TestCaseSpec(package='CtsDeviceVideoPerf',
-                   path='TestSuite/TestSuite/TestSuite/TestSuite/TestCase',
-                   class_='VideoEncoderDecoderTest',
-                   regex=self.VIDEO_ENCODER_DECODER_TEST_REGEX,
-                   result_class=VideoEncoderDecoderTestResult),
-      self.TestCaseSpec(package='CtsMediaTestCases',
-                   path='TestSuite/TestSuite/TestSuite/TestCase',
-                   class_='VideoDecoderPerfTest',
-                   regex=self.VIDEO_DECODER_PERF_TEST_REGEX,
-                   result_class=VideoDecoderPerfTestResult)
-    ]
+  def parse_fmt(self, fmt):
+    return self.parser._parseDict(fmt)
 
-  def _verifyDeviceInfo(self, device):
-    assert self._device in (None, device), "expected %s device" % self._device
-    self._device = device
+  def parse_perf(self, a, device, build):
+    def rateFn(i):
+      if i is None:
+        return i
+      elif i == 0:
+        return 1e6
+      return 1000. / i
 
-  def importXml(self, xml):
-    self._verifyDeviceInfo(xml.find('DeviceInfo/BuildInfo').get('buildName'))
+    points = ('avg', 'min', 'p5', 'p10', 'p20', 'p30', 'p40', 'p50', 'p60', 'p70', 'p80', 'p90', 'p95', 'max')
+    a = dict(a)
+    codec = a['codec_name'] + ''
+    mime = a['mime_type']
+    size = Size(a['width'], a['height'])
+    if 'decode_to' in a:
+      fmt = self.parse_fmt(a['output_format'])
+      ofmt = self.parse_fmt(a['input_format'])
+    else:
+      fmt = self.parse_fmt(a['input_format'])
+      ofmt = self.parse_fmt(a['output_format'])
+    size = Size(max(fmt['width'], ofmt['width']), max(fmt['height'], ofmt['height']))
 
-    packages = createLookup(self._getTestCases(), lambda tc: tc.package)
-
-    for pkg in xml.iter('TestPackage'):
-      tests_in_package = packages.get(pkg.get('name'))
-      if not tests_in_package:
-        continue
-      paths = createLookup(tests_in_package, lambda tc: tc.path)
-      for path, tests_in_path in paths.items():
-        classes = createLookup(tests_in_path, lambda tc: tc.class_)
-        for tc in pkg.iterfind(path):
-          tests_in_class = classes.get(tc.get('name'))
-          if not tests_in_class:
-            continue
-          for test in tc.iter('Test'):
-            for tc in tests_in_class:
-              m = tc.regex.match(test.get('name'))
-              if m:
-                result = tc.result_class(m)
-                result.parse(test)
-                self._results.append(result)
-
-  def importFile(self, path):
-    print >> sys.stderr, 'Importing "%s"...' % path
     try:
-      return self.importXml(ET.parse(path))
-    except ET.ParseError:
-      raise ValueError('not a valid XML file')
+      prefix = 'time_avg_stats_'
+      if prefix + 'stdev' in a and a[prefix + 'avg']:
+        stdev = (a[prefix + 'stdev'] * 1e3 / a[prefix + 'avg'] ** 2)
+        data = ((device, build, codec, size, a[prefix  + 'num'], stdev) +
+                tuple(rateFn(a.get(prefix + i)) for i in points))
+        self.data.add(data)
+        self.kind[codec] = (mime, 'decode_to' not in a, codec.lower().startswith('omx.google.'))
+        self.devices.add(data[0])
+    except (KeyError, ZeroDivisionError):
+      print >> sys.stderr, a
+      raise
 
-  def getData(self):
-    for result in self._results:
-      for data in result.getData():
-        yield data
-
-  def dumpXml(self, results):
-    yield '<?xml version="1.0" encoding="utf-8" ?>'
-    yield '<!-- Copyright 2015 The Android Open Source Project'
-    yield ''
-    yield '     Licensed under the Apache License, Version 2.0 (the "License");'
-    yield '     you may not use this file except in compliance with the License.'
-    yield '     You may obtain a copy of the License at'
-    yield ''
-    yield '          http://www.apache.org/licenses/LICENSE-2.0'
-    yield ''
-    yield '     Unless required by applicable law or agreed to in writing, software'
-    yield '     distributed under the License is distributed on an "AS IS" BASIS,'
-    yield '     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.'
-    yield '     See the License for the specific language governing permissions and'
-    yield '     limitations under the License.'
-    yield '-->'
-    yield ''
-    yield '<MediaCodecs>'
-    last_section = None
-    Comp = namedtuple('Comp', 'is_decoder google mime name')
-    by_comp = createLookup(results,
-                           lambda e: Comp(is_decoder=e.is_decoder, google='.google.' in e.codec, mime=e.mime, name=e.codec))
-    for comp in sorted(by_comp):
-      section = 'Decoders' if comp.is_decoder else 'Encoders'
-      if section != last_section:
-        if last_section:
-          yield '    </%s>' % last_section
-        yield '    <%s>' % section
-        last_section = section
-      yield '        <MediaCodec name="%s" type="%s" update="true">' % (comp.name, comp.mime)
-      by_size = createLookup(by_comp[comp], lambda e: e.size)
-      for size in sorted(by_size):
-        values = list(itertools.chain(*(e.rates for e in by_size[size])))
-        min_, max_ = min(values), max(values)
-        med_ = int(math.sqrt(min_ * max_))
-        yield '            <Limit name="measured-frame-rate-%s" range="%d-%d" />' % (size, med_, med_)
-      yield '        </MediaCodec>'
-    if last_section:
-      yield '    </%s>' % last_section
-    yield '</MediaCodecs>'
-
-
-class Main(object):
-  """Executor of this utility."""
-
-  def __init__(self):
-    self._result = Results()
-
-    self._parser = argparse.ArgumentParser('get_achievable_framerates')
-    self._parser.add_argument('result_xml', nargs='+')
-
-  def _parseArgs(self):
-    self._args = self._parser.parse_args()
-
-  def _importXml(self, xml):
-    self._result.importFile(xml)
-
-  def _report(self):
-    for line in self._result.dumpXml(r for r in self._result.getData() if r):
-      print line
-
-  def run(self):
-    self._parseArgs()
-    try:
-      for xml in self._args.result_xml:
+  def parse_json(self, json, device, build):
+    for test, results in json:
+      if test in ("video_encoder_performance", "video_decoder_performance"):
         try:
-          self._importXml(xml)
-        except (ValueError, IOError, AssertionError) as e:
-          print >> sys.stderr, e
-          raise KeyboardInterrupt
-      self._report()
-    except KeyboardInterrupt:
-      print >> sys.stderr, 'Interrupted.'
+          if isinstance(results, list) and len(results[0]) and len(results[0][0]) == 2 and len(results[0][0][0]):
+            for result in results:
+              self.parse_perf(result, device, build)
+          else:
+            self.parse_perf(results, device, build)
+        except KeyboardInterrupt:
+          raise
 
-if __name__ == '__main__':
-  Main().run()
+  def parse_result(self, result):
+    device, build = '', ''
+    if not result.endswith('.zip'):
+      print >> sys.stderr, "cannot parse %s" % result
+      return
 
+    try:
+      with zipfile.ZipFile(result) as zip:
+        resultInfo, testInfos = None, []
+        for info in zip.infolist():
+          if re.search(r'/GenericDeviceInfo.deviceinfo.json$', info.filename):
+            resultInfo = info
+          elif re.search(r'/Cts(Media|Video)TestCases\.reportlog\.json$', info.filename):
+            testInfos.append(info)
+        if resultInfo:
+          try:
+            jsonFile = zip.open(resultInfo)
+            jsonData = json.load(jsonFile, encoding='utf-8')
+            device, build = jsonData['build_device'], jsonData['build_id']
+          except ValueError:
+            print >> sys.stderr, "could not parse %s" % resultInfo.filename
+        for info in testInfos:
+          jsonFile = zip.open(info)
+          try:
+            jsonData = json.load(jsonFile, encoding='utf-8', object_pairs_hook=lambda items: items)
+          except ValueError:
+            print >> sys.stderr, "cannot parse JSON in %s" % info.filename
+          self.parse_json(jsonData, device, build)
+
+    except zipfile.BadZipfile:
+      raise ValueError('bad zipfile')
+
+
+P = argparse.ArgumentParser("gar_v2")
+P.add_argument("--dbg", "-v", action='store_true', help="dump debug info into xml")
+P.add_argument("--ignore", "-I", action='store_true', help="ignore minimum sample count")
+P.add_argument("result_zip", nargs="*")
+A = P.parse_args()
+
+D = Data()
+for res in A.result_zip:
+  D.parse_result(res)
+D.summarize(A=A)
diff --git a/tools/cts-native-scanner/tests/Android.mk b/tools/cts-native-scanner/tests/Android.mk
index 29c5514..562f0b9 100644
--- a/tools/cts-native-scanner/tests/Android.mk
+++ b/tools/cts-native-scanner/tests/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_MODULE := cts-native-scanner-tests
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-native-scanner
+LOCAL_JAVA_LIBRARIES := tradefed cts-native-scanner
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 
diff --git a/tools/cts-native-scanner/tests/run_unit_tests.sh b/tools/cts-native-scanner/tests/run_unit_tests.sh
index a42e42b..e85fa7a 100755
--- a/tools/cts-native-scanner/tests/run_unit_tests.sh
+++ b/tools/cts-native-scanner/tests/run_unit_tests.sh
@@ -24,7 +24,7 @@
 }
 
 JAR_DIR=${ANDROID_HOST_OUT}/framework
-JARS="ddmlib-prebuilt.jar tradefed-prebuilt.jar hosttestlib.jar cts-native-scanner.jar cts-native-scanner-tests.jar"
+JARS="ddmlib-prebuilt.jar tradefed.jar hosttestlib.jar cts-native-scanner.jar cts-native-scanner-tests.jar"
 
 for JAR in $JARS; do
     checkFile ${JAR_DIR}/${JAR}
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index f09b581..16a9e5f 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -80,7 +80,7 @@
 fi;
 
 JAR_DIR=${CTS_ROOT}/android-cts/tools
-JARS="tradefed-prebuilt
+JARS="tradefed
   hosttestlib
   compatibility-host-util
   compatibility-host-util-tests
diff --git a/tools/cts-tradefed/res/config/cts-presubmit.xml b/tools/cts-tradefed/res/config/cts-presubmit.xml
new file mode 100644
index 0000000..3f721f1
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-presubmit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs CTS presubmit test cases">
+
+    <include name="cts-automated" />
+
+    <option name="plan" value="cts" />
+
+    <!-- Include modules with presubmit test cases. -->
+    <option name="compatibility:include-filter" value="CtsAccountManagerTestCases" />
+
+    <!-- Only run tests with @Presubmit annotation. -->
+    <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+    <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.Presubmit" />
+    <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+
+</configuration>
diff --git a/tools/cts-tradefed/tests/Android.mk b/tools/cts-tradefed/tests/Android.mk
index 280cdfb..2a391c0 100644
--- a/tools/cts-tradefed/tests/Android.mk
+++ b/tools/cts-tradefed/tests/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_MODULE := cts-tradefed-tests
 LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed
+LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed
+# We ship the Deqp Runner tests with the CTS one to validate them.
+LOCAL_STATIC_JAVA_LIBRARIES := CtsDeqpRunnerTests
 
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-xml-generator/src/Android.mk b/tools/cts-xml-generator/src/Android.mk
index ea81763..9e5e646 100644
--- a/tools/cts-xml-generator/src/Android.mk
+++ b/tools/cts-xml-generator/src/Android.mk
@@ -25,7 +25,7 @@
 LOCAL_MODULE := cts-xml-generator
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := tradefed
 
 LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib compatibility-host-util
 
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index f1219c1..51ecc2c 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -18,7 +18,7 @@
 
 package android.cts.security;
 
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -63,7 +63,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        sepolicyAnalyze = buildHelper.getTestFile("sepolicy-analyze");
         sepolicyAnalyze.setExecutable(true);
 
         /* obtain sepolicy file from running device */
diff --git a/tools/utils/Android.mk b/tools/utils/Android.mk
index 92bc420..6b01e57 100644
--- a/tools/utils/Android.mk
+++ b/tools/utils/Android.mk
@@ -24,7 +24,7 @@
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
-LOCAL_JAVA_LIBRARIES := junit tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := junit-host tradefed
 LOCAL_STATIC_JAVA_LIBRARIES := compatibility-host-util vogarexpectlib
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 4a4e7ae..4935b5e 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -44,7 +44,7 @@
 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit jsr305lib
+LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit-host jsr305lib
 
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
@@ -70,7 +70,7 @@
 
 include $(BUILD_SYSTEM)/base_rules.mk
 
-vmteststf_dep_jars := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/, cts-tf-dalvik-buildutil.jar dasm.jar dx.jar cfassembler.jar junit.jar)
+vmteststf_dep_jars := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/, cts-tf-dalvik-buildutil.jar dasm.jar dx.jar cfassembler.jar junit-host.jar)
 
 $(LOCAL_BUILT_MODULE): PRIVATE_JACK_EXTRA_ARGS := $(LOCAL_JACK_EXTRA_ARGS)
 
@@ -86,8 +86,8 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_JACK_VERSION := $(LOCAL_JACK_VERSION)
 oj_jack := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj,,COMMON)/classes.jack
 libart_jack := $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart,,COMMON)/classes.jack
-$(LOCAL_BUILT_MODULE): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
-$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(JACK) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar | setup-jack-server
+$(LOCAL_BUILT_MODULE): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar
+$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(JACK) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar | setup-jack-server
 	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
 	$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
 	# generated and compile the host side junit tests
diff --git a/tools/vm-tests-tf/targetprep/Android.mk b/tools/vm-tests-tf/targetprep/Android.mk
index 8abde93..a05b658 100644
--- a/tools/vm-tests-tf/targetprep/Android.mk
+++ b/tools/vm-tests-tf/targetprep/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
 
 LOCAL_MODULE_TAGS := optional