Merge "setAutoTimeRequired disabled on managed profile" into rvc-dev
diff --git a/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py b/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
index 95ff8b8..4af6543 100644
--- a/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
+++ b/apps/CameraITS/tests/scene2_b/test_auto_per_frame_control.py
@@ -28,6 +28,7 @@
 DELTA_GAIN_THRESH = 0.03  # >3% gain change --> luma change in same dir
 DELTA_LUMA_THRESH = 0.03  # 3% frame-to-frame noise test_burst_sameness_manual
 DELTA_NO_GAIN_THRESH = 0.01  # <1% gain change --> min luma change
+LSC_TOL = 0.005  # allow <0.5% change in lens shading correction
 NAME = os.path.basename(__file__).split('.')[0]
 NUM_CAPS = 1
 NUM_FRAMES = 30
@@ -35,6 +36,46 @@
 VALID_STABLE_LUMA_MAX = 0.9
 
 
+def lsc_unchanged(lsc_avlb, lsc, idx):
+    """Determine if lens shading correction unchanged.
+
+    Args:
+        lsc_avlb:   bool; True if lens shading correction available
+        lsc:        list; lens shading correction matrix
+        idx:        int; frame index
+    Returns:
+        boolean
+    """
+    if lsc_avlb:
+        diff = list((np.array(lsc[idx]) - np.array(lsc[idx-1])) /
+                    np.array(lsc[idx-1]))
+        diff = map(abs, diff)
+        max_abs_diff = max(diff)
+        if max_abs_diff > LSC_TOL:
+            print '  max abs(LSC) change:', round(max_abs_diff, 4)
+            return False
+        else:
+            return True
+    else:
+        return True
+
+
+def tonemap_unchanged(raw_cap, tonemap_g, idx):
+    """Determine if tonemap unchanged.
+
+    Args:
+        raw_cap:    bool; True if RAW capture
+        tonemap_g:  list; green tonemap
+        idx:        int; frame index
+    Returns:
+        boolean
+    """
+    if not raw_cap:
+        return tonemap_g[idx-1] == tonemap_g[idx]
+    else:
+        return True
+
+
 def is_awb_af_stable(cap_info, i):
     awb_gains_0 = cap_info[i-1]['awb_gains']
     awb_gains_1 = cap_info[i]['awb_gains']
@@ -80,16 +121,21 @@
             ae_states = []
             lumas = []
             total_gains = []
+            tonemap_g = []
+            lsc = []
             num_caps = NUM_CAPS
             num_frames = NUM_FRAMES
             raw_cap = f == 0 and raw_avlb and debug
+            lsc_avlb = its.caps.lsc_map(props) and not raw_cap
+            print 'lens shading correction available:', lsc_avlb
+            if lsc_avlb:
+                req['android.statistics.lensShadingMapMode'] = 1
             name_suffix = 'YUV'
             if raw_cap:
                 name_suffix = 'RAW'
                 # break up caps if RAW to reduce load
                 num_caps = NUM_CAPS * 6
                 num_frames = NUM_FRAMES / 6
-
             for j in range(num_caps):
                 caps = cam.do_capture([req]*num_frames, fmt)
                 for i, cap in enumerate(caps):
@@ -127,8 +173,12 @@
                     print 'AWB state: %d, AWB gains: %s\n AWB matrix: %s' % (
                             awb_state, str(frame['awb_gains']),
                             str(awb_ccm))
-                    if debug:
-                        print 'Tonemap curve:', cap['metadata']['android.tonemap.curve']
+                    if not raw_cap:
+                        tonemap = cap['metadata']['android.tonemap.curve']
+                        tonemap_g.append(tonemap['green'])
+                        print 'G tonemap curve:', tonemap_g[idx]
+                    if lsc_avlb:
+                        lsc.append(cap['metadata']['android.statistics.lensShadingCorrectionMap']['map'])
 
                     img = its.image.convert_capture_to_rgb_image(
                             cap, props=props)
@@ -179,32 +229,37 @@
                     # Threshold change to trigger check. Small delta_gain might
                     # not be enough to generate a reliable delta_luma to
                     # overcome frame-to-frame variation.
-                    if abs(delta_gain_rel) > DELTA_GAIN_THRESH:
-                        print 'frame %d: %.2f%% delta gain,' % (
-                                i, delta_gain_rel*100),
-                        print '%.2f%% delta luma' % (delta_luma_rel*100)
-                        if delta_gain * delta_luma < 0.0:
-                            failed.append(msg)
-                    elif abs(delta_gain_rel) < DELTA_NO_GAIN_THRESH:
-                        print 'frame %d: <|%.1f%%| delta gain,' % (
-                                i, DELTA_NO_GAIN_THRESH*100),
-                        print '%.2f%% delta luma' % (delta_luma_rel*100)
-                        msg = '%s: ' % fmt['format']
-                        msg += 'frame %d: gain %.1f -> %.1f (%.1f%%), ' % (
-                                i, prev_total_gain, total_gain,
-                                delta_gain_rel*100)
-                        msg += 'luma %f -> %f (%.1f%%)  ' % (
-                                prev_luma, luma, delta_luma_rel*100)
-                        msg += '<|%.1f%%| GAIN, >|%.f%%| LUMA DELTA' % (
-                                DELTA_NO_GAIN_THRESH*100, DELTA_LUMA_THRESH*100)
-                        if abs(delta_luma_rel) > DELTA_LUMA_THRESH:
-                            failed.append(msg)
+                    if (tonemap_unchanged(raw_cap, tonemap_g, i) and
+                                lsc_unchanged(lsc_avlb, lsc, i)):
+                        if abs(delta_gain_rel) > DELTA_GAIN_THRESH:
+                            print ' frame %d: %.2f%% delta gain,' % (
+                                    i, delta_gain_rel*100),
+                            print '%.2f%% delta luma' % (delta_luma_rel*100)
+                            if delta_gain * delta_luma < 0.0:
+                                failed.append(msg)
+                        elif abs(delta_gain_rel) < DELTA_NO_GAIN_THRESH:
+                            print ' frame %d: <|%.1f%%| delta gain,' % (
+                                    i, DELTA_NO_GAIN_THRESH*100),
+                            print '%.2f%% delta luma' % (delta_luma_rel*100)
+                            msg = '%s: ' % fmt['format']
+                            msg += 'frame %d: gain %.1f -> %.1f (%.1f%%), ' % (
+                                    i, prev_total_gain, total_gain,
+                                    delta_gain_rel*100)
+                            msg += 'luma %f -> %f (%.1f%%)  ' % (
+                                    prev_luma, luma, delta_luma_rel*100)
+                            msg += '<|%.1f%%| GAIN, >|%.f%%| LUMA DELTA' % (
+                                    DELTA_NO_GAIN_THRESH*100, DELTA_LUMA_THRESH*100)
+                            if abs(delta_luma_rel) > DELTA_LUMA_THRESH:
+                                failed.append(msg)
+                        else:
+                            print ' frame %d: %.1f%% delta gain,' % (
+                                    i, delta_gain_rel*100),
+                            print '%.2f%% delta luma' % (delta_luma_rel*100)
                     else:
-                        print 'frame %d: %.1f%% delta gain,' % (
-                                i, delta_gain_rel*100),
-                        print '%.2f%% delta luma' % (delta_luma_rel*100)
+                        print ' frame %d -> %d: tonemap' % (i-1, i),
+                        print 'or lens shading correction changed'
                 else:
-                    print 'frame %d -> %d: AWB/AF changed' % (i-1, i)
+                    print ' frame %d -> %d: AWB/AF changed' % (i-1, i)
 
             for i in range(len(lumas)):
                 luma = lumas[i]
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 0a0226f..fb7cb0e 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -60,6 +60,7 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
     <uses-feature android:name="android.hardware.usb.accessory" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
@@ -1982,7 +1983,8 @@
             <meta-data android:name="android.nfc.cardemulation.host_nfcf_service" android:resource="@xml/felicaservice"/>
         </service>
         <!-- Service used for Camera ITS tests -->
-        <service android:name=".camera.its.ItsService" >
+        <service android:name=".camera.its.ItsService"
+            android:foregroundServiceType="camera">
             <intent-filter>
                 <action android:name="com.android.cts.verifier.camera.its.START"/>
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3564,8 +3566,6 @@
             <meta-data android:name="test_category" android:value="@string/test_category_tv" />
             <meta-data android:name="test_required_features"
                        android:value="android.software.leanback" />
-            <meta-data android:name="test_required_configs"
-                       android:value="config_hdmi_source"/>
         </activity>
         <activity android:name=".tv.display.DisplayModesTestActivity"
                   android:label="@string/tv_display_modes_test"
diff --git a/apps/CtsVerifier/jni/midi/Android.bp b/apps/CtsVerifier/jni/midi/Android.bp
index 4e707eb..f437360 100644
--- a/apps/CtsVerifier/jni/midi/Android.bp
+++ b/apps/CtsVerifier/jni/midi/Android.bp
@@ -26,8 +26,7 @@
         "system/core/include/cutils",
     ],
     sdk_version: "current",
-    //stl: "c++_static"
-    stl: "system",
+    stl: "libc++_static",
     shared_libs: [
         "liblog",
         "libamidi",
diff --git a/apps/CtsVerifier/jni/verifier/Android.bp b/apps/CtsVerifier/jni/verifier/Android.bp
index 2bdb74c..e34e86f 100644
--- a/apps/CtsVerifier/jni/verifier/Android.bp
+++ b/apps/CtsVerifier/jni/verifier/Android.bp
@@ -21,7 +21,7 @@
         "com_android_cts_verifier_camera_StatsImage.cpp",
     ],
     sdk_version: "current",
-    stl: "system",
+    stl: "libc++_static",
     shared_libs: ["liblog"],
     cflags: [
         "-Wall",
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 51a4810..d1a8c1a 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -61,6 +61,10 @@
     <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>
+    <string name="no_storage_io_parser_exception">Cannot save report to external
+        storage, see log for details. Or try running the following command if
+        you haven\'t yet.\n\"adb shell appops set com.android.cts.verifier
+        MANAGE_EXTERNAL_STORAGE 0\"</string>
     <string name="report_saved">Report saved to: %s</string>
 
     <!-- Strings for IntentDrivenTestActivity -->
@@ -4041,20 +4045,22 @@
         Please do the following:\n
         1) You should have received NotificationBot.apk together with the CTS verifier. If you built the CTS verifier yourself, build the NotificationBot.apk by issuing the following command on the host:\n
             make NotificationBot\n
-        2) Upload the NotificationBot.apk to your device by issuing the following command on the host:\n
+        2) Grant MANAGE_EXTERNAL_STORAGE by issuing the following command on the host:\n
+            adb shell appops set com.android.cts.verifier MANAGE_EXTERNAL_STORAGE 0\n
+        3) Upload the NotificationBot.apk to your device by issuing the following command on the host:\n
             adb push /path/to/NotificationBot.apk /sdcard\n
-        3) Press the Uninstall button.\n
-        4) Press the Open Settings button.\n
-        5) In the screen that opens, verify that you are not told that your administrator installed any apps.\n
-        6) Use the Back button to return to this page.\n
-        7) Press the Install button.\n
-        8) Press the Open Settings button.\n
-        9) In the screen that opens, verify that you are told now that your administrator installed at least one app.\n
-        10) Tap on that information. Verify that a list of apps installed shows.\n
-        11) Verify that the list contains the CTS Robot app.\n
-        12) Use the Back button to return to this page.\n
-        13) Press the Uninstall button.\n
-        14) Issue the following command on the host:\n
+        4) Press the Uninstall button.\n
+        5) Press the Open Settings button.\n
+        6) In the screen that opens, verify that you are not told that your administrator installed any apps.\n
+        7) Use the Back button to return to this page.\n
+        8) Press the Install button.\n
+        9) Press the Open Settings button.\n
+        10) In the screen that opens, verify that you are told now that your administrator installed at least one app.\n
+        11) Tap on that information. Verify that a list of apps installed shows.\n
+        12) Verify that the list contains the CTS Robot app.\n
+        13) Use the Back button to return to this page.\n
+        14) Press the Uninstall button.\n
+        15) Issue the following command on the host:\n
             adb shell rm /sdcard/NotificationBot.apk
     </string>
     <string name="enterprise_privacy_install">Install</string>
@@ -4446,6 +4452,7 @@
 
     <string name="tv_yes">Yes</string>
     <string name="tv_no">No</string>
+    <string name="tv_none">None</string>
     <string name="tv_launch_tv_app">Launch TV app</string>
     <string name="tv_launch_epg">Launch EPG</string>
     <string name="tv_launch_setup">Launch setup</string>
@@ -4578,6 +4585,12 @@
         and disconnect the display within %2$d seconds. Wait at least %3$d seconds and then
         reconnect the display.
     </string>
+    <string name="tv_panel_hdr_types_reported_are_supported">
+        The supported HDR types are: %s\nAre all of them supported by the hardware?
+    </string>
+    <string name="tv_panel_hdr_types_supported_are_reported">
+        Are there other HDR types which are supported by the hardware, but are not listed above?
+    </string>
 
     <!-- Display Modes Test -->
     <string name="tv_display_modes_test">Display Modes Test</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
index f0200a6..f39a409 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ReportExporter.java
@@ -108,7 +108,7 @@
             ZipUtil.createZip(tempDir, reportZipFile);
         } catch (IOException | XmlPullParserException e) {
             LOG.log(Level.WARNING, "I/O exception writing report to storage.", e);
-            return mContext.getString(R.string.no_storage);
+            return mContext.getString(R.string.no_storage_io_parser_exception);
         } finally {
             // delete the temporary directory and its files made for the report
             FileUtil.recursiveDelete(tempDir);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
index ebd2e6f..09d705f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/RingerModeActivity.java
@@ -246,8 +246,17 @@
 
         @Override
         protected void test() {
+            boolean touchSoundEnabled =
+                Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.System.SOUND_EFFECTS_ENABLED, 1) == 1;
             if (mUserVerified) {
-                status = PASS;
+                if (touchSoundEnabled) {
+                    status = PASS;
+                    return;
+                } else {
+                    setFailed();
+                    return;
+                }
             } else {
                 status = WAIT_FOR_USER;
             }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index e843ce7..83a6724 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -22,6 +22,7 @@
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ServiceInfo;
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCaptureSession;
@@ -332,7 +333,8 @@
                     .setContentText("CameraITS Service is running")
                     .setSmallIcon(R.drawable.icon)
                     .setOngoing(true).build();
-            startForeground(SERVICE_NOTIFICATION_ID, notification);
+            startForeground(SERVICE_NOTIFICATION_ID, notification,
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA);
         } catch (java.lang.InterruptedException e) {
             Logt.e(TAG, "Error starting ItsService (interrupted)", e);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/CACertWriter.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/CACertWriter.java
new file mode 100644
index 0000000..5495273
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/CACertWriter.java
@@ -0,0 +1,71 @@
+/*
+ * 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 com.android.cts.verifier.security;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.res.AssetManager;
+import android.net.Uri;
+import android.provider.MediaStore;
+
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class CACertWriter {
+    static final String TAG = CACertWriter.class.getSimpleName();
+
+    private static final String CERT_ASSET_NAME = "myCA.cer";
+
+    public static boolean extractCertToDownloads(
+            Context applicationContext, AssetManager assetManager) {
+        // Use MediaStore API to write the CA cert to the Download folder
+        final ContentValues downloadValues = new ContentValues();
+        downloadValues.put(MediaStore.MediaColumns.DISPLAY_NAME, CERT_ASSET_NAME);
+
+        Uri targetCollection = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
+        ContentResolver resolver = applicationContext.getContentResolver();
+        Uri toOpen = resolver.insert(targetCollection, downloadValues);
+        Log.i(TAG, String.format("Writing CA cert to %s", toOpen));
+
+        InputStream is = null;
+        OutputStream os = null;
+        try {
+            try {
+                is = assetManager.open(CERT_ASSET_NAME);
+                os = resolver.openOutputStream(toOpen);
+                byte[] buffer = new byte[1024];
+                int length;
+                while ((length = is.read(buffer)) > 0) {
+                    os.write(buffer, 0, length);
+                }
+            } finally {
+                if (is != null) is.close();
+                if (os != null) os.close();
+            }
+        } catch (IOException ioe) {
+            Log.w(TAG, String.format("Problem moving cert file to %s", toOpen), ioe);
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/CAInstallNotificationVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/CAInstallNotificationVerifierActivity.java
index ee992e9..13c4244 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/CAInstallNotificationVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/CAInstallNotificationVerifierActivity.java
@@ -27,11 +27,6 @@
 
 import com.android.cts.verifier.R;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
 import com.android.cts.verifier.ArrayTestListAdapter;
 import com.android.cts.verifier.DialogTestListActivity;
 import com.android.cts.verifier.TestListActivity;
@@ -41,8 +36,6 @@
 public class CAInstallNotificationVerifierActivity extends DialogTestListActivity {
     static final String TAG = CAInstallNotificationVerifierActivity.class.getSimpleName();
 
-    private static final String CERT_ASSET_NAME = "myCA.cer";
-
     // From @hidden field in android.provider.Settings
     private static final String ACTION_TRUSTED_CREDENTIALS_USER
             = "com.android.settings.TRUSTED_CREDENTIALS_USER";
@@ -93,25 +86,7 @@
 
         @Override
         public void performTest(DialogTestListActivity activity) {
-            final File certStagingFile = new File("/sdcard/", CERT_ASSET_NAME);
-            InputStream is = null;
-            FileOutputStream os = null;
-            try {
-                try {
-                    is = getAssets().open(CERT_ASSET_NAME);
-                    os = new FileOutputStream(certStagingFile);
-                    byte[] buffer = new byte[1024];
-                    int length;
-                    while ((length = is.read(buffer)) > 0) {
-                        os.write(buffer, 0, length);
-                    }
-                } finally {
-                    if (is != null) is.close();
-                    if (os != null) os.close();
-                    certStagingFile.setReadable(true, false);
-                }
-            } catch (IOException ioe) {
-                Log.w(TAG, "Problem moving cert file to /sdcard/", ioe);
+            if (!CACertWriter.extractCertToDownloads(getApplicationContext(), getAssets())) {
                 return;
             }
             super.performTest(activity);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/CANotifyOnBootActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/CANotifyOnBootActivity.java
index 9c799ab..c3c41ea 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/CANotifyOnBootActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/CANotifyOnBootActivity.java
@@ -14,16 +14,9 @@
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
 public class CANotifyOnBootActivity extends PassFailButtons.Activity {
 
     private static final String TAG = CANotifyOnBootActivity.class.getSimpleName();
-    private static final String CERT_ASSET_NAME = "myCA.cer";
-    private File certStagingFile = new File("/sdcard/", CERT_ASSET_NAME);
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -60,24 +53,7 @@
     class InstallCert implements OnClickListener {
         @Override
         public void onClick(View v) {
-            InputStream is = null;
-            FileOutputStream os = null;
-            try {
-                try {
-                    is = getAssets().open(CERT_ASSET_NAME);
-                    os = new FileOutputStream(certStagingFile);
-                    byte[] buffer = new byte[1024];
-                    int length;
-                    while ((length = is.read(buffer)) > 0) {
-                        os.write(buffer, 0, length);
-                    }
-                } finally {
-                    if (is != null) is.close();
-                    if (os != null) os.close();
-                    certStagingFile.setReadable(true, false);
-                }
-            } catch (IOException ioe) {
-                Log.w(TAG, "Problem moving cert file to /sdcard/", ioe);
+            if (!CACertWriter.extractCertToDownloads(getApplicationContext(), getAssets())) {
                 return;
             }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
index b86c58b..1fd4bdd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/display/DisplayHdrCapabilitiesTestActivity.java
@@ -18,12 +18,14 @@
 
 import android.content.Context;
 import android.hardware.display.DisplayManager;
+import android.util.Log;
 import android.view.Display;
 
 import androidx.annotation.StringRes;
 
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.tv.TvAppVerifierActivity;
+import com.android.cts.verifier.tv.TvUtil;
 
 import com.google.common.base.Throwables;
 import com.google.common.collect.Range;
@@ -32,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Test to verify the HDR Capabilities API is correctly implemented.
@@ -44,6 +47,7 @@
  * no display is connected.
  */
 public class DisplayHdrCapabilitiesTestActivity extends TvAppVerifierActivity {
+    private static final String LOG_TAG = "HdrCapabilitiesTest";
     private static final float MAX_EXPECTED_LUMINANCE = 10_000f;
     private static final int DISPLAY_DISCONNECT_WAIT_TIME_SECONDS = 5;
 
@@ -63,10 +67,16 @@
     @Override
     protected void createTestItems() {
         List<TestStepBase> testSteps = new ArrayList<>();
-        testSteps.add(new NonHdrDisplayTestStep(this));
-        testSteps.add(new HdrDisplayTestStep(this));
-        testSteps.add(new NoDisplayTestStep(this));
-
+        if (TvUtil.isHdmiSourceDevice()) {
+            // The device is a set-top box or a TV dongle
+            testSteps.add(new NonHdrDisplayTestStep(this));
+            testSteps.add(new HdrDisplayTestStep(this));
+            testSteps.add(new NoDisplayTestStep(this));
+        } else {
+            // The device is a TV Panel
+            testSteps.add(new TvPanelReportedTypesAreSupportedTestStep(this));
+            testSteps.add(new TvPanelSupportedTypesAreReportedTestStep(this));
+        }
         mTestSequence = new TestSequence(this, testSteps);
         mTestSequence.init();
     }
@@ -207,4 +217,56 @@
             done();
         }
     }
+
+    private static class TvPanelReportedTypesAreSupportedTestStep extends YesNoTestStep {
+        public TvPanelReportedTypesAreSupportedTestStep(TvAppVerifierActivity context) {
+            super(context, getInstructionText(context));
+        }
+
+        private static String getInstructionText(Context context) {
+            DisplayManager displayManager =
+                    (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+            Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+
+            int[] hdrTypes = display.getHdrCapabilities().getSupportedHdrTypes();
+            String hdrTypesString;
+            if (hdrTypes.length == 0) {
+                hdrTypesString = context.getString(R.string.tv_none);
+            } else {
+                hdrTypesString =
+                        Arrays.stream(hdrTypes)
+                                .mapToObj(DisplayHdrCapabilitiesTestActivity::hdrTypeToString)
+                                .collect(Collectors.joining(", "));
+            }
+
+            return context.getString(
+                    R.string.tv_panel_hdr_types_reported_are_supported, hdrTypesString);
+        }
+    }
+
+    private static class TvPanelSupportedTypesAreReportedTestStep extends YesNoTestStep {
+        public TvPanelSupportedTypesAreReportedTestStep(TvAppVerifierActivity context) {
+            super(context, getInstructionText(context));
+        }
+
+        private static String getInstructionText(Context context) {
+            return context.getString(R.string.tv_panel_hdr_types_supported_are_reported);
+        }
+    }
+
+    private static String hdrTypeToString(@Display.HdrCapabilities.HdrType int type) {
+        switch (type) {
+            case Display.HdrCapabilities.HDR_TYPE_DOLBY_VISION:
+                return "DOLBY_VISION";
+            case Display.HdrCapabilities.HDR_TYPE_HDR10:
+                return "HDR10";
+            case Display.HdrCapabilities.HDR_TYPE_HLG:
+                return "HLG";
+            case Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS:
+                return "HDR10_PLUS";
+            default:
+                Log.e(LOG_TAG, "Unknown HDR type " + type);
+                return "UNKNOWN";
+        }
+    }
 }
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 df3109f..10364af 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
@@ -100,9 +100,12 @@
 
             store.addResult(IS_ACTIVE_ADMIN, deviceAdminPackages.contains(pkg.packageName));
 
-            final boolean isDefaultAccessibilityComponent = pkg.packageName.equals(
-                    defaultAccessibilityComponent.getPackageName()
-            );
+            boolean isDefaultAccessibilityComponent = false;
+            if (defaultAccessibilityComponent != null) {
+              isDefaultAccessibilityComponent = pkg.packageName.equals(
+                      defaultAccessibilityComponent.getPackageName()
+              );
+            }
             store.addResult(DEFAULT_ACCESSIBILITY_SERVICE, isDefaultAccessibilityComponent);
 
             String sha256_cert = PackageUtil.computePackageSignatureDigest(pkg.packageName);
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/AnrMonitor.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/AmMonitor.java
similarity index 67%
rename from common/device-side/util-axt/src/com/android/compatibility/common/util/AnrMonitor.java
rename to common/device-side/util-axt/src/com/android/compatibility/common/util/AmMonitor.java
index ac4879a..93bd1f1 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/AnrMonitor.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/AmMonitor.java
@@ -20,6 +20,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 
 import java.io.BufferedOutputStream;
@@ -30,19 +31,26 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * A utility class interact with "am monitor"
  */
-public final class AnrMonitor {
-    private static final String TAG = "AnrMonitor";
-    private static final String WAIT_FOR_ANR = "Waiting after early ANR...  available commands:";
-    private static final String MONITOR_READY = "Monitoring activity manager...  available commands:";
+public final class AmMonitor {
+    private static final String TAG = "AmMonitor";
+    public static final String WAIT_FOR_EARLY_ANR =
+            "Waiting after early ANR...  available commands:";
+    public static final String WAIT_FOR_ANR =
+            "Waiting after ANR...  available commands:";
+    public static final String WAIT_FOR_CRASHED =
+            "Waiting after crash...  available commands:";
+    public static final String MONITOR_READY =
+            "Monitoring activity manager...  available commands:";
 
     /**
      * Command for the {@link #sendCommand}: continue the process
      */
-    public static final String CMD_CONTINUE = "k";
+    public static final String CMD_CONTINUE = "c";
 
     /**
      * Command for the {@link #sendCommand}: kill the process
@@ -63,12 +71,13 @@
     private final PrintWriter mWritePrinter;
     private final Thread mReaderThread;
 
+    private final ArraySet<String> mNotExpected = new ArraySet<>();
     private final ArrayList<String> mPendingLines = new ArrayList<>();
 
     /**
      * Construct an instance of this class.
      */
-    public AnrMonitor(final Instrumentation instrumentation) {
+    public AmMonitor(final Instrumentation instrumentation, final String[] notExpected) {
         mInstrumentation = instrumentation;
         ParcelFileDescriptor[] pfds = instrumentation.getUiAutomation()
                 .executeShellCommandRw("am monitor");
@@ -78,18 +87,12 @@
         mWriteFd = pfds[1];
         mWriteStream = new ParcelFileDescriptor.AutoCloseOutputStream(mWriteFd);
         mWritePrinter = new PrintWriter(new BufferedOutputStream(mWriteStream));
+        if (notExpected != null) {
+            mNotExpected.addAll(Arrays.asList(notExpected));
+        }
         mReaderThread = new ReaderThread();
         mReaderThread.start();
-        waitFor(3600000L, MONITOR_READY);
-    }
-
-    /**
-     * Wait for the ANR.
-     *
-     * @return true if it was successful, false if it got a timeout.
-     */
-    public boolean waitFor(final long timeout) {
-        return waitFor(timeout, WAIT_FOR_ANR);
+        waitFor(MONITOR_READY, 3600000L);
     }
 
     /**
@@ -97,15 +100,16 @@
      *
      * @return true if it was successful, false if it got a timeout.
      */
-    private boolean waitFor(final long timeout, final String expected) {
+    public boolean waitFor(final String expected, final long timeout) {
         final long waitUntil = SystemClock.uptimeMillis() + timeout;
         synchronized (mPendingLines) {
             while (true) {
                 while (mPendingLines.size() == 0) {
                     final long now = SystemClock.uptimeMillis();
                     if (now >= waitUntil) {
-                        Log.d(TAG, "Timed out waiting for next line: expected=" + expected);
-                        return false;
+                        String msg = "Timed out waiting for next line: expected=" + expected;
+                        Log.d(TAG, msg);
+                        throw new IllegalStateException(msg);
                     }
                     try {
                         mPendingLines.wait(waitUntil - now);
@@ -115,6 +119,13 @@
                 final String line = mPendingLines.remove(0);
                 if (TextUtils.equals(line, expected)) {
                     return true;
+                } else if (TextUtils.equals(line, WAIT_FOR_EARLY_ANR)
+                        || TextUtils.equals(line, WAIT_FOR_ANR)
+                        || TextUtils.equals(line, WAIT_FOR_CRASHED)) {
+                    // If we are getting any of the unexpected state,
+                    // for example, get a crash while waiting for an ANR,
+                    // it could be from another unrelated process, kill it directly.
+                    sendCommand(CMD_KILL);
                 }
             }
         }
@@ -141,8 +152,10 @@
      * @param cmd could be {@link #CMD_KILL}, {@link #CMD_QUIT} or {@link #CMD_CONTINUE}.
      */
     public void sendCommand(final String cmd) {
-        mWritePrinter.println(cmd);
-        mWritePrinter.flush();
+        synchronized (mPendingLines) {
+            mWritePrinter.println(cmd);
+            mWritePrinter.flush();
+        }
     }
 
     private final class ReaderThread extends Thread {
@@ -152,6 +165,13 @@
                 String line;
                 while ((line = mReadReader.readLine()) != null) {
                     Log.i(TAG, "debug: " + line);
+                    if (mNotExpected.contains(line)) {
+                        // If we are getting any of the unexpected state,
+                        // for example, get a crash while waiting for an ANR,
+                        // it could be from another unrelated process, kill it directly.
+                        sendCommand(CMD_KILL);
+                        continue;
+                    }
                     synchronized (mPendingLines) {
                         mPendingLines.add(line);
                         mPendingLines.notifyAll();
diff --git a/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java b/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java
index f388cc3..29d718f 100644
--- a/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java
+++ b/hostsidetests/adb/src/android/adb/cts/AdbHostTest.java
@@ -47,8 +47,8 @@
         File check_ms_os_desc = copyResourceToTempFile("/check_ms_os_desc");
         check_ms_os_desc.setExecutable(true);
 
-        // ANDROID_SERIAL is already set correctly in our environment.
         ProcessBuilder pb = new ProcessBuilder(check_ms_os_desc.getAbsolutePath());
+        pb.environment().put("ANDROID_SERIAL", getDevice().getSerialNumber());
         pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
         pb.redirectErrorStream(true);
         Process p = pb.start();
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java
index 699af1a..2f8790f 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java
@@ -43,6 +43,11 @@
         installPackage(TEST_APK, true);
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        uninstallPackage(TEST_PKG, true);
+    }
+
     public void testIsChangeEnabled() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest", "isChangeEnabled_changeEnabled",
                 /*enabledChanges*/ImmutableSet.of(CTS_SYSTEM_API_CHANGEID),
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/README.md b/hostsidetests/appsecurity/res/pkgsigverify/README.md
new file mode 100644
index 0000000..278a960
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/README.md
@@ -0,0 +1,35 @@
+# pkgsigverify
+
+## Valid cases
+
+APKs in this directory are used by `PkgInstallSignatureVerificationTest`.
+See that class for additional information about their use.
+
+In general, they are differently signed forms of the tinyapp APK and follow
+the following naming scheme:
+
+`${version}-with-${signing-algorithm}-${OID-params}-${keysize}-${extra_info}`
+
+where some fields may not be present, but have the following meaning:
+
+- version: denotes which APK Signature Scheme (v1, v2, and/or v3) was used
+- signing-algorithm: indicates how the signature was generated
+- OID-params: PKI object identifiers indicating how to use the provided key
+  to generate the signature.  See, e.g. rfc3279 and rfc4055.
+- keysize: the size of the key used for signing
+- extra_info: additional notes to distinguish packages. Currently this denotes
+  which test certificates were used to generate a proof-of-rotation object,
+  if one exists, included in the signing block of the APK, as well as the
+  capabilities of those certificates according to APK Signature Scheme v3.
+
+Generation of these apks was performed using the `apksigner` command-line tool,
+which lives at `tools/apksig/src/apksigner/java/com/android/apksigner/` in the
+android source tree.  Please refer to the usage instructions there for how to
+sign APKs using different keystores, providers, etc.  
+
+## Invalid cases
+
+Some of the APKs in this directory were generated by modifying the apksig library (see
+README in tools/apksig/) to create invalid or unsupported outcomes. When possible, their usage is 
+preceded by a description of how `apksig` was modified, and the commit should explicitly show how
+`apksig` was modified.
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/README.txt b/hostsidetests/appsecurity/res/pkgsigverify/README.txt
deleted file mode 100644
index f30eec5..0000000
--- a/hostsidetests/appsecurity/res/pkgsigverify/README.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-APKs in this directory are used by PkgInstallSignatureVerificationTest.
-See that class for additional information about their use.
-
-In general, they are differently signed forms of the tinyapp APK and follow
-the following naming scheme:
-
-${version}-with-${signing-algorithm}-${OID-params}-${keysize}-${extra_info}
-
-where some fields may not be present, but have the following meaning:
-
-version: denotes which APK Signature Scheme (v1, v2, and/or v3) was used
-signing-algorithm: indicates how the signature was generated
-OID-params: PKI object identifiers indicating how to use the provided key
-  to generate the signature.  See, e.g. rfc3279 and rfc4055.
-keysize: the size of the key used for signing
-extra_info: additional notes to distinguish packages. Currently this denotes
-  which test certificates were used to generate a proof-of-rotation object,
-  if one exists, included in the signing block of the APK, as well as the
-  capabilities of those certificates according to APK Signature Scheme v3.
-
-Generation of these apks was performed using the apksigner command-line tool,
-which lives at tools/apksig/src/apksigner/java/com/android/apksigner/ in the
-android source tree.  Please refer to the usage instructions there for how to
-sign APKs using different keystores, providers, etc.  In particular, some of
-the APKs in this directory were generated by modifying the apksig library (see
-README in tools/apksig/) to create invalid or unsupported outcomes.
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv2digest.apk b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv2digest.apk
new file mode 100644
index 0000000..9839f78
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv2digest.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv2digest.apk.idsig b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv2digest.apk.idsig
new file mode 100644
index 0000000..07f2f0d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv2digest.apk.idsig
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv4signature.apk b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv4signature.apk
new file mode 100644
index 0000000..9839f78
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv4signature.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv4signature.apk.idsig b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv4signature.apk.idsig
new file mode 100644
index 0000000..b00c87a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2-badv4signature.apk.idsig
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv2v3digest.apk b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv2v3digest.apk
new file mode 100644
index 0000000..ead1ef8
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv2v3digest.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv2v3digest.apk.idsig b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv2v3digest.apk.idsig
new file mode 100644
index 0000000..5632589
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv2v3digest.apk.idsig
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv4signature.apk b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv4signature.apk
new file mode 100644
index 0000000..ead1ef8
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv4signature.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv4signature.apk.idsig b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv4signature.apk.idsig
new file mode 100644
index 0000000..3de76f9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v2v3-badv4signature.apk.idsig
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv3digest.apk b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv3digest.apk
new file mode 100644
index 0000000..710c7e7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv3digest.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv3digest.apk.idsig b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv3digest.apk.idsig
new file mode 100644
index 0000000..83061cb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv3digest.apk.idsig
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv4signature.apk b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv4signature.apk
new file mode 100644
index 0000000..710c7e7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv4signature.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv4signature.apk.idsig b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv4signature.apk.idsig
new file mode 100644
index 0000000..e0a68db
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v4-digest-v3-badv4signature.apk.idsig
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableFeatureConsistentTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableFeatureConsistentTest.java
deleted file mode 100644
index 48fddc7..0000000
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableFeatureConsistentTest.java
+++ /dev/null
@@ -1,80 +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.
- */
-
-package android.appsecurity.cts;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import static android.appsecurity.cts.AdoptableHostTest.FEATURE_ADOPTABLE_STORAGE;
-import android.platform.test.annotations.AppModeFull;
-
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Set of tests that verify behavior of adopted storage media's consistency between the feature
- * flag and what we sniffed from the underlying fstab.
- */
-@RunWith(DeviceJUnit4ClassRunner.class)
-@AppModeFull(reason = "Instant applications can only be installed on internal storage")
-public class AdoptableFeatureConsistentTest extends BaseHostJUnit4Test {
-
-    private String mHasAdoptable;
-
-    @Before
-    public void setUp() throws Exception {
-        // Caches the initial state of adoptable feature to restore after the tests
-        mHasAdoptable = getDevice().executeShellCommand("sm has-adoptable").trim();
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        // Restores the initial cache value
-        getDevice().executeShellCommand("sm set-force-adoptable" + mHasAdoptable);
-    }
-
-    @Test
-    public void testFeatureTrue() throws Exception {
-        getDevice().executeShellCommand("sm set-force-adoptable true");
-        checkConsistency();
-    }
-
-    @Test
-    public void testFeatureFalse() throws Exception {
-        getDevice().executeShellCommand("sm set-force-adoptable false");
-        checkConsistency();
-    }
-
-    private void checkConsistency() throws Exception {
-        // Reboots the device and blocks until the boot complete flag is set.
-        getDevice().rebootUntilOnline();
-        assertTrue("Device failed to boot", getDevice().waitForBootComplete(120000));
-
-        final boolean hasFeature = getDevice().hasFeature(FEATURE_ADOPTABLE_STORAGE);
-        final boolean hasFstab = Boolean.parseBoolean(getDevice()
-                .executeShellCommand("sm has-adoptable").trim());
-        if (hasFeature != hasFstab) {
-            fail("Inconsistent adoptable storage status; feature claims " + hasFeature
-                    + " but fstab claims " + hasFstab);
-        }
-    }
-}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index 7717623..927f9f5 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -51,7 +51,6 @@
 
     public static final String FEATURE_ADOPTABLE_STORAGE = "feature:android.software.adoptable_storage";
 
-    private boolean mHasAdoptableInitialState;
     private String mListVolumesInitialState;
 
     @Before
@@ -59,16 +58,12 @@
         // Start all possible users to make sure their storage is unlocked
         Utils.prepareMultipleUsers(getDevice(), Integer.MAX_VALUE);
 
+        // Users are starting, wait for all volumes are ready
+        waitForVolumeReady();
+
         // Initial state of all volumes
         mListVolumesInitialState = getDevice().executeShellCommand("sm list-volumes");
 
-        // TODO(b/146491109): Revert this change before shipping and find long-term solution.
-        // Caches the initial state of adoptable feature and sets it to true (if not already set)
-        mHasAdoptableInitialState = Boolean.parseBoolean(
-                getDevice().executeShellCommand("sm has-adoptable").trim());
-        if (!mHasAdoptableInitialState) {
-            setForceAdoptable();
-        }
         getDevice().uninstallPackage(PKG);
 
         // Enable a virtual disk to give us the best shot at being able to pass
@@ -123,9 +118,19 @@
                 CLog.w("Volume state is not recovered: " + result);
             }
         }
-        // Restores the initial cache value (if it is different)
-        if (!mHasAdoptableInitialState) {
-            getDevice().executeShellCommand("sm set-force-adoptable false");
+    }
+
+    /**
+     * Ensure that we have consistency between the feature flag and what we
+     * sniffed from the underlying fstab.
+     */
+    @Test
+    public void testFeatureConsistent() throws Exception {
+        final boolean hasFeature = hasFeature();
+        final boolean hasFstab = hasFstab();
+        if (hasFeature != hasFstab) {
+            fail("Inconsistent adoptable storage status; feature claims " + hasFeature
+                    + " but fstab claims " + hasFstab);
         }
     }
 
@@ -134,7 +139,7 @@
         int attempt = 0;
         boolean noCheckingEjecting = false;
         String result = "";
-        while (!noCheckingEjecting && attempt++ < 20) {
+        while (!noCheckingEjecting && attempt++ < 60) {
             result = getDevice().executeShellCommand("sm list-volumes");
             noCheckingEjecting = !result.contains("ejecting") && !result.contains("checking");
             Thread.sleep(100);
@@ -216,18 +221,6 @@
         }
     }
 
-    private void setForceAdoptable() throws Exception {
-        getDevice().executeShellCommand("sm set-force-adoptable true");
-        int attempt = 0;
-        boolean hasAdoptable = false;
-        while (!hasAdoptable && attempt++ < 5) {
-            Thread.sleep(1000);
-            hasAdoptable = Boolean.parseBoolean(getDevice()
-                    .executeShellCommand("sm has-adoptable").trim());
-        }
-        assertTrue(hasAdoptable);
-    }
-
     private void verifyPrimaryInternal(String diskId) throws Exception {
         // Write some data to shared storage
         new InstallMultiple().addFile(APK).run();
@@ -255,6 +248,7 @@
         runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
         getDevice().executeShellCommand("sm mount " + vol.volId);
         waitForInstrumentationReady();
+        waitForVolumeReady();
 
         runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
         runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
@@ -305,6 +299,7 @@
         runDeviceTests(PKG, CLASS, "testPrimaryUnmounted");
         getDevice().executeShellCommand("sm mount " + vol.volId);
         waitForInstrumentationReady();
+        waitForVolumeReady();
 
         runDeviceTests(PKG, CLASS, "testPrimaryAdopted");
         runDeviceTests(PKG, CLASS, "testPrimaryDataRead");
@@ -375,6 +370,7 @@
             // Kick through a remount cycle, which should purge the adopted app
             getDevice().executeShellCommand("sm mount " + vol.volId);
             waitForInstrumentationReady();
+            waitForVolumeReady();
 
             runDeviceTests(PKG, CLASS, "testDataInternal");
             boolean didThrow = false;
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 2a356ea..fb8a4f2 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -39,7 +39,6 @@
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -215,7 +214,6 @@
      * Verify that app without REQUEST_INSTALL_PACKAGES can't access obb
      * directories belonging to other apps.
      */
-    @Ignore("Re-enable as part of b/148918640")
     @Test
     public void testCantAccessOtherObbDirs() throws Exception {
         try {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index 05a76b4..23e95f1 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -241,7 +241,7 @@
         assertInstallSucceedsForEach(
                 "v2-only-with-rsa-pss-sha512-%s.apk",
                 RSA_KEY_NAMES_2048_AND_LARGER // 1024-bit key is too short for PSS with SHA-512
-                );
+        );
     }
 
     public void testInstallV1SignatureOnlyDoesNotVerify() throws Exception {
@@ -828,6 +828,54 @@
         assertInstallV4Succeeds("v4-digest-v2v3.apk");
     }
 
+    public void testInstallV4WithV2SignerDoesNotVerify() throws Exception {
+        // V4 is only enabled on devices with Incremental feature
+        if (!hasIncrementalFeature()) {
+            return;
+        }
+
+        // APKs generated with:
+        // apksigner sign -v2-signing-enabled true --v3-signing-enabled false --v4-signing-enabled
+
+        // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
+        assertInstallV4FailsWithError("v4-digest-v2-badv4signature.apk", "did not verify");
+        // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
+        assertInstallV4FailsWithError("v4-digest-v2-badv2digest.apk", "did not verify");
+    }
+
+    public void testInstallV4WithV3SignerDoesNotVerify() throws Exception {
+        // V4 is only enabled on devices with Incremental feature
+        if (!hasIncrementalFeature()) {
+            return;
+        }
+
+        // APKs generated with:
+        // apksigner sign -v2-signing-enabled false --v3-signing-enabled true --v4-signing-enabled
+
+        // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
+        assertInstallV4FailsWithError("v4-digest-v3-badv4signature.apk", "did not verify");
+
+        // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
+        assertInstallV4FailsWithError("v4-digest-v3-badv3digest.apk", "did not verify");
+
+    }
+
+    public void testInstallV4WithV2V3SignerDoesNotVerify() throws Exception {
+        // V4 is only enabled on devices with Incremental feature
+        if (!hasIncrementalFeature()) {
+            return;
+        }
+
+        // APKs generated with:
+        // apksigner sign -v2-signing-enabled true --v3-signing-enabled true --v4-signing-enabled
+
+        // Malformed v4 signature - first byte of v4 signing_info.signature is flipped
+        assertInstallV4FailsWithError("v4-digest-v2v3-badv4signature.apk", "did not verify");
+
+        // Malformed digest - first byte of v4 signing_info.apk_digest is flipped
+        assertInstallV4FailsWithError("v4-digest-v2v3-badv2v3digest.apk", "did not verify");
+    }
+
     private boolean hasIncrementalFeature() throws DeviceNotAvailableException {
         return getDevice().hasFeature("android.software.incremental_delivery");
     }
@@ -871,6 +919,19 @@
         }
     }
 
+    private void assertInstallV4FailsWithError(String apkFilenameInResources, String errorSubstring)
+            throws Exception {
+        String installResult = installV4PackageFromResource(apkFilenameInResources);
+        if (installResult.equals("Success\n")) {
+            fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
+                    + " with \"" + errorSubstring + "\"");
+        }
+        assertContains(
+                "Install failure message of " + apkFilenameInResources,
+                errorSubstring,
+                installResult);
+    }
+
     private void assertInstallFailsWithError(
             String apkFilenameInResources, String errorSubstring) throws Exception {
         String installResult = installPackageFromResource(apkFilenameInResources);
@@ -961,7 +1022,7 @@
         }
     }
 
-    private String pushFileToRemote(File localFile) throws DeviceNotAvailableException{
+    private String pushFileToRemote(File localFile) throws DeviceNotAvailableException {
         String remotePath = "/data/local/tmp/pkginstalltest-" + localFile.getName();
         getDevice().pushFile(localFile, remotePath);
         return remotePath;
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
index 620fed1..ee3a683 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppA/src/com/android/cts/appdataisolation/appa/AppATests.java
@@ -188,6 +188,18 @@
         mDevice.waitForIdle();
     }
 
+    private String replacePackageAWithPackageB(String path) {
+        return path.replace(mContext.getPackageName(), APPB_PKG);
+    }
+
+    private void testCanNotAccessAppBExternalDirs() {
+        String appBExternalDir = replacePackageAWithPackageB(
+                mContext.getExternalFilesDir("").getParentFile().getAbsolutePath());
+        String appBObbDir = replacePackageAWithPackageB(mContext.getObbDir().getAbsolutePath());
+        assertDirDoesNotExist(appBExternalDir);
+        assertDirDoesNotExist(appBObbDir);
+    }
+
     @Test
     public void testAppAUnlockDeviceAndVerifyCeDeExternalDataExist() throws Exception {
 
@@ -221,5 +233,9 @@
         testAppAExternalDirsDoExist();
         testAppACurProfileDataAccessible();
         testAppARefProfileDataNotAccessible();
+
+        // Verify after unlocking device, app a has still no access to app b dir.
+        testCannotAccessAppBDataDir();
+        testCanNotAccessAppBExternalDirs();
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java
index 0f069af..c1e3a53 100644
--- a/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java
+++ b/hostsidetests/appsecurity/test-apps/AppDataIsolationTestApp/AppB/src/com/android/cts/appdataisolation/appb/AppBTests.java
@@ -65,7 +65,7 @@
     @Test
     public void testCanNotAccessAppAExternalDirs() {
         String appAExternalDir = replacePackageBWithPackageA(
-                mContext.getExternalFilesDir("").getAbsolutePath());
+                mContext.getExternalFilesDir("").getParentFile().getAbsolutePath());
         String appAObbDir = replacePackageBWithPackageA(mContext.getObbDir().getAbsolutePath());
         assertDirDoesNotExist(appAExternalDir);
         assertDirDoesNotExist(appAObbDir);
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/AndroidManifest.xml
index 09bac4c..d3c5dcc 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/UserAppTest/AndroidManifest.xml
@@ -17,6 +17,12 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.cts.userapptest" >
 
+    <queries>
+        <intent>
+            <action android:name="com.android.cts.instantappusertest.QUERY" />
+        </intent>
+    </queries>
+
     <application
         android:label="@string/app_name" >
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml
index 0e416d9..a8a6cad 100644
--- a/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/PackageAccessApp/AndroidManifest.xml
@@ -16,6 +16,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.cts.packageaccessapp">
 
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml
index d8bc983..243fa23 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml
@@ -20,6 +20,9 @@
 
     <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
 
+    <!-- We need to request the permission, which is denied in the test. -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+
     <application
         android:crossProfile="true">
         <receiver android:name=".CrossProfileEnabledNoPermsAppReceiver">
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceFeatureUtils.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceFeatureUtils.java
new file mode 100644
index 0000000..797bf97
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DeviceFeatureUtils.java
@@ -0,0 +1,26 @@
+/*
+ * 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 com.android.cts.deviceandprofileowner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class DeviceFeatureUtils extends BaseDeviceAdminTest {
+
+    public void testHasFactoryResetProtectionPolicy() {
+        assertThat(mDevicePolicyManager.isFactoryResetProtectionPolicySupported()).isTrue();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DummyApps/dummyapp1/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DummyApps/dummyapp1/AndroidManifest.xml
index a757984..00fe83d 100644
--- a/hostsidetests/devicepolicy/app/DummyApps/dummyapp1/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DummyApps/dummyapp1/AndroidManifest.xml
@@ -30,5 +30,8 @@
                 <action android:name="android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED" />
             </intent-filter>
         </receiver>
+        <activity
+            android:name="android.app.Activity">
+        </activity>
     </application>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/DummyApps/dummyapp2/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DummyApps/dummyapp2/AndroidManifest.xml
index feb0cb7..97c7d76 100644
--- a/hostsidetests/devicepolicy/app/DummyApps/dummyapp2/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DummyApps/dummyapp2/AndroidManifest.xml
@@ -30,5 +30,8 @@
                 <action android:name="android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED" />
             </intent-filter>
         </receiver>
+        <activity
+            android:name="android.app.Activity">
+        </activity>
     </application>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/DummyApps/dummyapp3/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DummyApps/dummyapp3/AndroidManifest.xml
index a6f8648..dbd0778 100644
--- a/hostsidetests/devicepolicy/app/DummyApps/dummyapp3/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DummyApps/dummyapp3/AndroidManifest.xml
@@ -30,5 +30,8 @@
                 <action android:name="android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED" />
             </intent-filter>
         </receiver>
+        <activity
+            android:name="android.app.Activity">
+        </activity>
     </application>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/DummyApps/dummyapp4/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DummyApps/dummyapp4/AndroidManifest.xml
index 19f62c9..7001a87 100644
--- a/hostsidetests/devicepolicy/app/DummyApps/dummyapp4/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DummyApps/dummyapp4/AndroidManifest.xml
@@ -30,5 +30,8 @@
                 <action android:name="android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED" />
             </intent-filter>
         </receiver>
+        <activity
+            android:name="android.app.Activity">
+        </activity>
     </application>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserManagerTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserManagerTest.java
index 8ae404d..6673533 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserManagerTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/UserManagerTest.java
@@ -16,17 +16,35 @@
 
 package com.android.cts.managedprofile;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.UiAutomation;
+import android.os.Process;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.HashSet;
+import java.util.List;
+
 public class UserManagerTest extends AndroidTestCase {
 
     private UserManager mUserManager;
+    private UiAutomation mUiAutomation;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mUserManager = mContext.getSystemService(UserManager.class);
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mUiAutomation.dropShellPermissionIdentity();
+        super.tearDown();
     }
 
     public void testIsManagedProfileReturnsTrue() {
@@ -36,4 +54,37 @@
     public void testIsManagedProfileReturnsFalse() {
         assertFalse(mUserManager.isManagedProfile());
     }
+
+    public void testGetAllProfiles() {
+        List<UserHandle> profiles = mUserManager.getAllProfiles();
+        assertThat(profiles).hasSize(2);
+        assertThat(profiles).contains(Process.myUserHandle());
+    }
+
+    public void testCreateProfile_managedProfile() {
+        mUiAutomation.adoptShellPermissionIdentity("android.permission.CREATE_USERS");
+
+        UserHandle newProfile = mUserManager.createProfile("testProfile1",
+                UserManager.USER_TYPE_PROFILE_MANAGED, new HashSet<String>());
+        assertThat(newProfile).isNotNull();
+
+        List<UserHandle> profiles = mUserManager.getAllProfiles();
+        assertThat(profiles).contains(newProfile);
+    }
+
+    /** This test should be run as the managed profile
+     *  by com.android.cts.devicepolicy.ManagedProfileTest
+     */
+    public void testIsProfileReturnsTrue_runAsProfile() {
+        mUiAutomation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
+        assertThat(mUserManager.isProfile()).isTrue();
+    }
+
+    /** This test should be run as the parent profile
+     *  by com.android.cts.devicepolicy.ManagedProfileTest
+     */
+    public void testIsProfileReturnsFalse_runAsPrimary() {
+        mUiAutomation.adoptShellPermissionIdentity("android.permission.INTERACT_ACROSS_USERS");
+        assertThat(mUserManager.isProfile()).isFalse();
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp b/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp
index ab82993..bf67cc0 100644
--- a/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp
+++ b/hostsidetests/devicepolicy/app/SimpleSmsApp/Android.bp
@@ -15,13 +15,10 @@
 android_test {
     name: "SimpleSmsApp",
     sdk_version: "test_current",
-
-    srcs: ["src/**/*.kt", "src/**/*.java"],
-
+    srcs: ["src/**/*.java"],
     static_libs: [
-        "compatibility-device-util-axt",
+        "cts-devicepolicy-suspensionchecker",
     ],
-
     test_suites: [
         "cts",
     ],
diff --git a/hostsidetests/devicepolicy/app/SimpleSmsApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimpleSmsApp/AndroidManifest.xml
index 6cd7616..7c38b6d 100644
--- a/hostsidetests/devicepolicy/app/SimpleSmsApp/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/SimpleSmsApp/AndroidManifest.xml
@@ -21,10 +21,6 @@
     <uses-permission android:name="android.permission.READ_SMS"/>
 
     <application android:label="SimpleSmsApp">
-        <activity
-            android:name="android.app.Activity"
-            android:exported="true"/>
-
         <!-- BroadcastReceiver that listens for incoming SMS messages -->
         <receiver android:name="android.telephony.cts.sms.SmsReceiver"
                   android:permission="android.permission.BROADCAST_SMS">
@@ -43,7 +39,8 @@
         </receiver>
 
         <!-- Activity that allows the user to send new SMS/MMS messages -->
-        <activity android:name="android.app.Activity" >
+        <activity android:name="android.app.Activity"
+                  android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.SEND" />
                 <action android:name="android.intent.action.SENDTO" />
@@ -71,5 +68,13 @@
         </service>
 
     </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.telephony.cts.sms.simplesmsapp">
+        <meta-data
+            android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
 </manifest>
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index d0e2deb..fd6109c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -1059,7 +1059,7 @@
 
     @Test
     public void testSetMeteredDataDisabledPackages() throws Exception {
-        if (!mHasFeature) {
+        if (!mHasFeature || !hasDeviceFeature("android.hardware.wifi")) {
             return;
         }
         installAppAsUser(METERED_DATA_APP_APK, mUserId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 9b313a0..93cc6eb 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -66,8 +66,8 @@
     private static final String SIMPLE_APP_PKG = "com.android.cts.launcherapps.simpleapp";
     private static final String SIMPLE_APP_ACTIVITY = SIMPLE_APP_PKG + ".SimpleActivity";
 
-    protected static final String SIMPLE_SMS_APP_PKG = "android.telephony.cts.sms.simplesmsapp";
-    protected static final String SIMPLE_SMS_APP_APK = "SimpleSmsApp.apk";
+    private static final String SIMPLE_SMS_APP_PKG = "android.telephony.cts.sms.simplesmsapp";
+    private static final String SIMPLE_SMS_APP_APK = "SimpleSmsApp.apk";
 
     private static final String WIFI_CONFIG_CREATOR_PKG =
             "com.android.cts.deviceowner.wificonfigcreator";
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
index 4fe211f..639c6a3 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
@@ -26,6 +26,8 @@
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.isStatsdEnabled;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.assertFalse;
 
@@ -42,7 +44,12 @@
 
 import org.junit.Test;
 
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 public class ManagedProfileCrossProfileTest extends BaseManagedProfileTest {
@@ -56,6 +63,16 @@
     /** From {@code android.app.AppOpsManager#MODE_DEFAULT}. */
     private static final int MODE_DEFAULT = 3;
 
+    // The apps whose app-ops are maintained and unset are defined by the device-side test.
+    private static final Set<String> UNSET_CROSS_PROFILE_PACKAGES =
+            Sets.newHashSet(
+                    DUMMY_APP_3_PKG,
+                    DUMMY_APP_4_PKG);
+    private static final Set<String> MAINTAINED_CROSS_PROFILE_PACKAGES =
+            Sets.newHashSet(
+                    DUMMY_APP_1_PKG,
+                    DUMMY_APP_2_PKG);
+
     @LargeTest
     @Test
     public void testCrossProfileIntentFilters() throws Exception {
@@ -500,19 +517,10 @@
                 "testSetCrossProfilePackages_sendsBroadcastWhenResettingAppOps_noAsserts");
         waitForBroadcastIdle();
 
-        // The apps whose app-ops are maintained and unset are defined by the device-side test.
-        final Set<String> unsetCrossProfilePackages =
-                Sets.newHashSet(
-                        DUMMY_APP_3_PKG,
-                       DUMMY_APP_4_PKG);
-        final Set<String> maintainedCrossProfilePackages =
-                Sets.newHashSet(
-                        DUMMY_APP_1_PKG,
-                        DUMMY_APP_2_PKG);
         assertDummyAppsReceivedCanInteractAcrossProfilesChangedBroadcast(
-                unsetCrossProfilePackages);
+                UNSET_CROSS_PROFILE_PACKAGES);
         assertDummyAppsDidNotReceiveCanInteractAcrossProfilesChangedBroadcast(
-                maintainedCrossProfilePackages);
+                MAINTAINED_CROSS_PROFILE_PACKAGES);
     }
 
     /** Assumes that logcat is clear before running the test. */
@@ -572,6 +580,68 @@
                         .build());
     }
 
+    @Test
+    public void testSetCrossProfilePackages_killsApps() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installAllDummyApps();
+        launchAllDummyAppsInBothProfiles();
+        Map<String, List<String>> maintainedPackagesPids = getPackagesPids(
+                MAINTAINED_CROSS_PROFILE_PACKAGES);
+        Map<String, List<String>> unsetPackagesPids = getPackagesPids(UNSET_CROSS_PROFILE_PACKAGES);
+
+        runWorkProfileDeviceTest(
+                ".CrossProfileTest",
+                "testSetCrossProfilePackages_resetsAppOps_noAsserts");
+
+        for (String packageName : MAINTAINED_CROSS_PROFILE_PACKAGES) {
+            assertAppRunningInBothProfiles(packageName, maintainedPackagesPids.get(packageName));
+        }
+        for (String packageName : UNSET_CROSS_PROFILE_PACKAGES) {
+            assertAppKilledInBothProfiles(packageName, unsetPackagesPids.get(packageName));
+        }
+    }
+
+    private Map<String, List<String>> getPackagesPids(Set<String> packages) throws Exception {
+        Map<String, List<String>> pids = new HashMap<>();
+        for (String packageName : packages) {
+            pids.put(packageName, Arrays.asList(getAppPid(packageName).split(" ")));
+        }
+        return pids;
+    }
+
+    private void launchAllDummyAppsInBothProfiles() throws Exception {
+        launchAllDummyAppsForUser(mParentUserId);
+        launchAllDummyAppsForUser(mProfileUserId);
+    }
+
+    private void launchAllDummyAppsForUser(int userId) throws Exception {
+        final String dummyActivity = "android.app.Activity";
+        startActivityAsUser(userId, DUMMY_APP_1_PKG, dummyActivity);
+        startActivityAsUser(userId, DUMMY_APP_2_PKG, dummyActivity);
+        startActivityAsUser(userId, DUMMY_APP_3_PKG, dummyActivity);
+        startActivityAsUser(userId, DUMMY_APP_4_PKG, dummyActivity);
+    }
+
+    private void assertAppRunningInBothProfiles(String packageName, List<String> pids)
+            throws Exception {
+        Set<String> currentPids = new HashSet<>(
+                Arrays.asList(getAppPid(packageName).split(" ")));
+        assertThat(currentPids).containsAllIn(pids);
+    }
+
+    private void assertAppKilledInBothProfiles(String packageName,  List<String> pids)
+            throws Exception {
+        Set<String> currentPids = new HashSet<>(
+                Arrays.asList(getAppPid(packageName).split(" ")));
+        assertThat(currentPids).containsNoneIn(pids);
+    }
+
+    private String getAppPid(String packageName) throws Exception {
+        return getDevice().executeShellCommand(String.format("pidof %s", packageName)).trim();
+    }
+
     private void runCrossProfileCalendarTestsWhenWhitelistedAndEnabled() throws Exception {
         try {
             // Setup. Add the test package into cross-profile calendar whitelist, enable
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 55a552b..e452368 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -673,6 +673,40 @@
         }
     }
 
+    @Test
+    public void testCanGetProfiles() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        // getAllProfiles should contain both the primary and profile
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".UserManagerTest",
+                "testGetAllProfiles", mPrimaryUserId);
+
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".UserManagerTest",
+                "testGetAllProfiles", mProfileUserId);
+
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".UserManagerTest",
+                "testIsProfileReturnsFalse_runAsPrimary", mPrimaryUserId);
+
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".UserManagerTest",
+                "testIsProfileReturnsTrue_runAsProfile", mProfileUserId);
+    }
+
+    @Test
+    public void testCanCreateProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        // remove pre-created profile
+        removeUser(mProfileUserId);
+
+        // create profile from installed app
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".UserManagerTest",
+                "testCreateProfile_managedProfile", mPrimaryUserId);
+    }
+
     private void changeUserRestrictionOrFail(String key, boolean value, int userId)
             throws DeviceNotAvailableException {
         changeUserRestrictionOrFail(key, value, userId, MANAGED_PROFILE_PKG);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 0b3b46c..98e1c59 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -250,9 +250,18 @@
             return;
         }
 
+        try {
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DeviceFeatureUtils",
+                    "testHasFactoryResetProtectionPolicy", mUserId);
+        } catch (Exception e) {
+            // Unable to continue running tests because factory reset protection policy is not
+            // supported on the device
+            return;
+        }
+
         assertMetricsLogged(getDevice(), () -> {
-                runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".FactoryResetProtectionPolicyTest", mUserId);
-            }, new DevicePolicyEventWrapper.Builder(EventId.SET_FACTORY_RESET_PROTECTION_VALUE)
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".FactoryResetProtectionPolicyTest", mUserId);
+        }, new DevicePolicyEventWrapper.Builder(EventId.SET_FACTORY_RESET_PROTECTION_VALUE)
                 .setAdminPackageName(DEVICE_ADMIN_PKG)
                 .build());
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index 7f6398c..ea90988 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -52,6 +52,8 @@
     private static final String DUMMY_IME_APK = "DummyIme.apk";
     private static final String DUMMY_IME_PKG = "com.android.cts.dummyime";
     private static final String DUMMY_IME_COMPONENT = DUMMY_IME_PKG + "/.DummyIme";
+    private static final String SIMPLE_SMS_APP_PKG = "android.telephony.cts.sms.simplesmsapp";
+    private static final String SIMPLE_SMS_APP_APK = "SimpleSmsApp.apk";
     private static final String DUMMY_LAUNCHER_APK = "DummyLauncher.apk";
     private static final String DUMMY_LAUNCHER_COMPONENT =
             "com.android.cts.dummylauncher/android.app.Activity";
@@ -442,6 +444,35 @@
     }
 
     @Test
+    public void testPersonalAppsSuspensionSms() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        // Install an SMS app and make it the default.
+        installAppAsUser(SIMPLE_SMS_APP_APK, mPrimaryUserId);
+        addSmsRole(SIMPLE_SMS_APP_PKG, mPrimaryUserId);
+        try {
+            setPersonalAppsSuspended(true);
+            // Default sms app should not be suspended.
+            assertCanStartPersonalApp(SIMPLE_SMS_APP_PKG, true);
+            setPersonalAppsSuspended(false);
+        } finally {
+            removeSmsRole(SIMPLE_SMS_APP_PKG, mPrimaryUserId);
+        }
+    }
+
+    private void addSmsRole(String app, int userId) throws Exception {
+        executeShellCommand(String.format(
+                "cmd role add-role-holder --user %d android.app.role.SMS %s", userId, app));
+    }
+
+    private void removeSmsRole(String app, int userId) throws Exception {
+        executeShellCommand(String.format(
+                "cmd role remove-role-holder --user %d android.app.role.SMS %s", userId, app));
+    }
+
+    @Test
     public void testPersonalAppsSuspensionIme() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
index 11a7aec..9069e1e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
@@ -235,33 +235,31 @@
 
     private void installCrossProfileApps()
             throws FileNotFoundException, DeviceNotAvailableException {
-        installCrossProfileApp(ENABLED_TEST_APK);
-        installCrossProfileApp(USER_ENABLED_TEST_APK);
-        installCrossProfileApp(NOT_ENABLED_TEST_APK);
-        installCrossProfileApp(ENABLED_NO_PERMS_TEST_APK);
+        installCrossProfileApp(ENABLED_TEST_APK, /* grantPermissions= */ true);
+        installCrossProfileApp(USER_ENABLED_TEST_APK, /* grantPermissions= */ true);
+        installCrossProfileApp(NOT_ENABLED_TEST_APK, /* grantPermissions= */ true);
+        installCrossProfileApp(ENABLED_NO_PERMS_TEST_APK, /* grantPermissions= */  false);
     }
 
     private void enableCrossProfileAppsOp() throws DeviceNotAvailableException {
         enableCrossProfileAppsOp(ENABLED_TEST_PACKAGE, mPrimaryUserId);
-        enableCrossProfileAppsOp(USER_ENABLED_TEST_PACKAGE, mPrimaryUserId);
-        enableCrossProfileAppsOp(NOT_ENABLED_TEST_PACKAGE, mPrimaryUserId);
         enableCrossProfileAppsOp(ENABLED_NO_PERMS_TEST_PACKAGE, mPrimaryUserId);
     }
 
-    private void installCrossProfileApp(String apkName)
+    private void installCrossProfileApp(String apkName, boolean grantPermissions)
             throws FileNotFoundException, DeviceNotAvailableException {
-        installAppAsUser(apkName, mPrimaryUserId);
-        installAppAsUser(apkName, mProfileId);
+        installAppAsUser(apkName, grantPermissions, mPrimaryUserId);
+        installAppAsUser(apkName, grantPermissions, mProfileId);
     }
 
     private void enableCrossProfileAppsOp(String packageName, int userId)
             throws DeviceNotAvailableException {
         getDevice().executeShellCommand(
                 String.format("appops set --user %s %s android:interact_across_profiles 0",
-                userId, packageName));
+                        userId, packageName));
         assertThat(getDevice().executeShellCommand(
                 String.format("appops get --user %s %s android:interact_across_profiles",
-                userId, packageName))).contains("INTERACT_ACROSS_PROFILES: allow");
+                        userId, packageName))).contains("INTERACT_ACROSS_PROFILES: allow");
     }
 
     private Map<String, String> createParams(int targetUserId) throws Exception {
diff --git a/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java b/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
index b0facec..23aca24 100644
--- a/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
+++ b/hostsidetests/net/src/com/android/cts/net/NetworkPolicyTestsPreparer.java
@@ -23,6 +23,7 @@
 
 public class NetworkPolicyTestsPreparer implements ITargetPreparer {
     private ITestDevice mDevice;
+    private boolean mOriginalAirplaneModeEnabled;
     private String mOriginalAppStandbyEnabled;
     private String mOriginalBatteryStatsConstants;
     private final static String KEY_STABLE_CHARGING_DELAY_MS = "battery_charged_delay_ms";
@@ -39,15 +40,29 @@
         setBatteryStatsConstants(
                 KEY_STABLE_CHARGING_DELAY_MS + "=" + DESIRED_STABLE_CHARGING_DELAY_MS);
         LogUtil.CLog.d("Original battery_saver_constants: " + mOriginalBatteryStatsConstants);
+
+        mOriginalAirplaneModeEnabled = getAirplaneModeEnabled();
+        // Turn off airplane mode in case another test left the device in that state.
+        setAirplaneModeEnabled(false);
+        LogUtil.CLog.d("Original airplane mode state: " + mOriginalAirplaneModeEnabled);
     }
 
     @Override
     public void tearDown(TestInformation testInformation, Throwable e)
             throws DeviceNotAvailableException {
+        setAirplaneModeEnabled(mOriginalAirplaneModeEnabled);
         setAppStandbyEnabled(mOriginalAppStandbyEnabled);
         setBatteryStatsConstants(mOriginalBatteryStatsConstants);
     }
 
+    private void setAirplaneModeEnabled(boolean enable) throws DeviceNotAvailableException {
+        executeCmd("cmd connectivity airplane-mode " + (enable ? "enable" : "disable"));
+    }
+
+    private boolean getAirplaneModeEnabled() throws DeviceNotAvailableException {
+        return "enabled".equals(executeCmd("cmd connectivity airplane-mode").trim());
+    }
+
     private void setAppStandbyEnabled(String appStandbyEnabled) throws DeviceNotAvailableException {
         if ("null".equals(appStandbyEnabled)) {
             executeCmd("settings delete global app_standby_enabled");
diff --git a/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java b/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java
index b33bfdc..689a095 100644
--- a/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java
+++ b/hostsidetests/os/src/android/os/cts/StaticSharedLibsHostTests.java
@@ -518,6 +518,42 @@
         }
     }
 
+    @AppModeFull(
+            reason = "getDeclaredSharedLibraries() requires ACCESS_SHARED_LIBRARIES permission")
+    public void testGetDeclaredSharedLibraries() throws Exception {
+        getDevice().uninstallPackage(STATIC_LIB_CONSUMER1_PKG);
+        getDevice().uninstallPackage(STATIC_LIB_CONSUMER2_PKG);
+        getDevice().uninstallPackage(STATIC_LIB_PROVIDER1_PKG);
+        getDevice().uninstallPackage(STATIC_LIB_PROVIDER2_PKG);
+        getDevice().uninstallPackage(STATIC_LIB_PROVIDER4_PKG);
+        getDevice().uninstallPackage(STATIC_LIB_PROVIDER_RECURSIVE_PKG);
+        try {
+            // Install library dependency
+            assertNull(install(STATIC_LIB_PROVIDER_RECURSIVE_APK));
+            // Install the first library
+            assertNull(install(STATIC_LIB_PROVIDER1_APK));
+            // Install the second library
+            assertNull(install(STATIC_LIB_PROVIDER2_APK));
+            // Install the third library
+            assertNull(install(STATIC_LIB_PROVIDER4_APK));
+            // Install the first client
+            assertNull(install(STATIC_LIB_CONSUMER1_APK));
+            // Install the second client
+            assertNull(install(STATIC_LIB_CONSUMER2_APK));
+            // Ensure declared libraries are properly reported
+            runDeviceTests(STATIC_LIB_CONSUMER1_PKG,
+                    "android.os.lib.consumer1.UseSharedLibraryTest",
+                    "testDeclaredSharedLibrariesProperlyReported");
+        } finally {
+            getDevice().uninstallPackage(STATIC_LIB_CONSUMER1_PKG);
+            getDevice().uninstallPackage(STATIC_LIB_CONSUMER2_PKG);
+            getDevice().uninstallPackage(STATIC_LIB_PROVIDER1_PKG);
+            getDevice().uninstallPackage(STATIC_LIB_PROVIDER2_PKG);
+            getDevice().uninstallPackage(STATIC_LIB_PROVIDER4_PKG);
+            getDevice().uninstallPackage(STATIC_LIB_PROVIDER_RECURSIVE_PKG);
+        }
+    }
+
     @AppModeInstant
     public void testAppCanSeeOnlyLibrariesItDependOnInstantMode() throws Exception {
         mInstantMode = true;
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
index 3637da0c..24ffae9 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.VersionedPackage;
 import android.os.lib.provider.R;
@@ -161,6 +162,52 @@
     }
 
     @Test
+    public void testDeclaredSharedLibrariesProperlyReported() throws Exception {
+        PackageManager packageManager = InstrumentationRegistry.getContext().getPackageManager();
+        List<SharedLibraryInfo> sharedLibs = SystemUtil.runWithShellPermissionIdentity(() ->
+                packageManager.getDeclaredSharedLibraries(STATIC_LIB_PROVIDER_PKG, 0));
+
+        assertNotNull(sharedLibs);
+
+        boolean firstLibFound = false;
+        boolean secondLibFound = false;
+        boolean thirdLibFound = false;
+
+        for (SharedLibraryInfo sharedLib : sharedLibs) {
+            assertEquals(LIB_NAME, sharedLib.getName());
+            VersionedPackage declaringPackage = sharedLib.getDeclaringPackage();
+            assertEquals(STATIC_LIB_PROVIDER_PKG, declaringPackage.getPackageName());
+            assertSame(SharedLibraryInfo.TYPE_STATIC, sharedLib.getType());
+
+            List<VersionedPackage> dependentPackages = sharedLib.getDependentPackages();
+            final long versionCode = sharedLib.getLongVersion();
+            if (versionCode == 1) {
+                firstLibFound = true;
+                assertSame(1L, declaringPackage.getLongVersionCode());
+                assertSame(1, dependentPackages.size());
+                VersionedPackage dependentPackage = dependentPackages.get(0);
+                assertEquals(STATIC_LIB_CONSUMER1_PKG, dependentPackage.getPackageName());
+                assertSame(1L, dependentPackage.getLongVersionCode());
+            } else if (versionCode == 2) {
+                secondLibFound = true;
+                assertSame(4L, declaringPackage.getLongVersionCode());
+                assertTrue(dependentPackages.isEmpty());
+            } else if (versionCode == 5) {
+                thirdLibFound = true;
+                assertSame(5L, declaringPackage.getLongVersionCode());
+                assertSame(1, dependentPackages.size());
+                VersionedPackage dependentPackage = dependentPackages.get(0);
+                assertEquals(STATIC_LIB_CONSUMER2_PKG, dependentPackage.getPackageName());
+                assertSame(2L, dependentPackage.getLongVersionCode());
+            }
+        }
+
+        assertTrue("Did not find lib " + LIB_NAME + " version 1", firstLibFound);
+        assertTrue("Did not find lib " + LIB_NAME + " version 4", secondLibFound);
+        assertTrue("Did not find lib " + LIB_NAME + " version 5", thirdLibFound);
+    }
+
+    @Test
     public void testAppCanSeeOnlyLibrariesItDependOn() throws Exception {
         // Make sure we see only the lib we depend on via getting its package info
         PackageInfo libPackageInfo = InstrumentationRegistry.getInstrumentation()
diff --git a/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
new file mode 100644
index 0000000..92eafe3
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/MetadataEncryptionTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.compatibility.common.util.CddTest;
+import com.android.compatibility.common.util.PropertyUtil;
+
+/**
+ * Host-side test for metadata encryption.  This is a host-side test because
+ * the "ro.crypto.metadata.enabled" property is not exposed to apps.
+ */
+public class MetadataEncryptionTest extends DeviceTestCase implements IDeviceTest {
+    private ITestDevice mDevice;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setDevice(ITestDevice device) {
+        super.setDevice(device);
+        mDevice = device;
+    }
+
+    /**
+     * Test that metadata encryption is enabled.
+     * To enable metadata encryption, see
+     * https://source.android.com/security/encryption/metadata
+     *
+     * @throws Exception
+     */
+    @CddTest(requirement="9.9.3/C-1-5")
+    public void testMetadataEncryptionIsEnabled() throws Exception {
+        if (PropertyUtil.getFirstApiLevel(mDevice) <= 29) {
+          return; // Requirement does not apply to devices running Q or earlier
+        }
+        assertTrue("Metadata encryption must be enabled",
+            mDevice.getBooleanProperty("ro.crypto.metadata.enabled", false));
+    }
+}
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
index 07313bb..c41493b 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/ApexShimValidationTest.java
@@ -23,7 +23,6 @@
 
 import android.platform.test.annotations.LargeTest;
 
-import com.android.tradefed.device.PackageInfo;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
@@ -33,6 +32,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
 /**
  * Tests to validate that only what is considered a correct shim apex can be installed.
  *
@@ -49,8 +52,10 @@
 public class ApexShimValidationTest extends BaseHostJUnit4Test {
 
     private static final String SHIM_APEX_PACKAGE_NAME = "com.android.apex.cts.shim";
-    private static final String SHIM_APK_PACKAGE_NAME = "com.android.cts.ctsshim";
-    private static final String SHIM_PRIV_APK_PACKAGE_NAME = "com.android.cts.priv.ctsshim";
+    private static final String SHIM_APK_CODE_PATH_PREFIX = "/apex/" + SHIM_APEX_PACKAGE_NAME + "/";
+
+    private static final List<String> ALLOWED_SHIM_PACKAGE_NAMES = Arrays.asList(
+            "com.android.cts.ctsshim", "com.android.cts.priv.ctsshim");
 
     /**
      * Runs the given phase of a test by calling into the device.
@@ -92,23 +97,12 @@
     }
 
     @Test
-    public void testShimApkIsPreInstalledInShimApex() throws Exception {
-        PackageInfo shimApkPackageInfo = getDevice().getAppPackageInfo(SHIM_APK_PACKAGE_NAME);
-        assertWithMessage("CTSShim APK is not pre-installed").that(
-                shimApkPackageInfo).isNotNull();
-        boolean isShimApkInShimApex = shimApkPackageInfo.getCodePath()
-                .startsWith("/apex/" + SHIM_APEX_PACKAGE_NAME + "/app/");
-        assertWithMessage("The active version of CTSShim APK does not come from "
-                + "Shim APEX").that(isShimApkInShimApex).isTrue();
-
-        PackageInfo shimPrivApkPackageInfo = getDevice()
-                .getAppPackageInfo(SHIM_PRIV_APK_PACKAGE_NAME);
-        assertWithMessage("CTSPrivShim APK is not pre-installed").that(
-                shimPrivApkPackageInfo).isNotNull();
-        boolean isPrivShimApkInShimApex = shimPrivApkPackageInfo.getCodePath()
-                .startsWith("/apex/" + SHIM_APEX_PACKAGE_NAME + "/priv-app/");
-        assertWithMessage("The active version of CTSPrivShim APK does not come "
-                + "from Shim APEX").that(isPrivShimApkInShimApex).isTrue();
+    public void testPackageNameOfShimApkIsAllowed() throws Exception {
+        final List<String> shimPackages = getDevice().getAppPackageInfos().stream()
+                .filter(pkg -> pkg.getCodePath().startsWith(SHIM_APK_CODE_PATH_PREFIX))
+                .map(pkg -> pkg.getPackageName()).collect(Collectors.toList());
+        assertWithMessage("Packages in the shim apex are not allowed")
+                .that(shimPackages).containsExactlyElementsIn(ALLOWED_SHIM_PACKAGE_NAMES);
     }
 
     @Test
diff --git a/hostsidetests/stagedinstall/testdata/apex/corrupted_b146895998.apex b/hostsidetests/stagedinstall/testdata/apex/corrupted_b146895998.apex
index fc6b474..1d02697 100644
--- a/hostsidetests/stagedinstall/testdata/apex/corrupted_b146895998.apex
+++ b/hostsidetests/stagedinstall/testdata/apex/corrupted_b146895998.apex
Binary files differ
diff --git a/hostsidetests/statsd/AndroidTest.xml b/hostsidetests/statsd/AndroidTest.xml
index 2da1662..4598f33 100644
--- a/hostsidetests/statsd/AndroidTest.xml
+++ b/hostsidetests/statsd/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Config for CTS Statsd host test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="statsd" />
+    <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
index 25727f1..6b3b981 100644
--- a/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
+++ b/hostsidetests/statsd/apps/statsdapp/src/com/android/server/cts/device/statsd/AtomTests.java
@@ -709,6 +709,49 @@
     }
 
     @Test
+    public void testSliceByWakelockState() {
+        int uid = Process.myUid();
+        int whatAtomId = 9_998;
+        int wakelockType = PowerManager.PARTIAL_WAKE_LOCK;
+        String tag = "StatsdPartialWakelock";
+
+        Context context = InstrumentationRegistry.getContext();
+        PowerManager pm = context.getSystemService(PowerManager.class);
+        PowerManager.WakeLock wl = pm.newWakeLock(wakelockType, tag);
+
+        wl.acquire();
+        sleep(500);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        wl.acquire();
+        sleep(500);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        wl.release();
+        sleep(500);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        wl.release();
+        sleep(500);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+        writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
+    }
+
+    private static void writeSliceByWakelockStateChangedAtom(int atomId, int firstUid,
+                                                            int field2, String field3) {
+        final StatsEvent.Builder builder = StatsEvent.newBuilder()
+                .setAtomId(atomId)
+                .writeAttributionChain(new int[] {firstUid}, new String[] {"tag1"})
+                .writeInt(field2)
+                .writeString(field3)
+                .usePooledBuffer();
+
+        StatsLog.write(builder.build());
+    }
+
+
+    @Test
     public void testWakelockLoad() {
         final int NUM_THREADS = 16;
         CountDownLatch latch = new CountDownLatch(NUM_THREADS);
@@ -839,9 +882,6 @@
     private static final int NETWORK_TIMEOUT_MILLIS = 15000;
     private static final String HTTPS_HOST_URL =
             "https://connectivitycheck.gstatic.com/generate_204";
-    // Minimum and Maximum of iterations of exercise host, @see #doGenerateNetworkTraffic.
-    private static final int MIN_EXERCISE_HOST_ITERATIONS = 1;
-    private static final int MAX_EXERCISE_HOST_ITERATIONS = 19;
 
     private void doGenerateNetworkTraffic(@NonNull Context context,
             @NetworkCapabilities.Transport int transport) throws InterruptedException {
@@ -862,45 +902,9 @@
 
         final long startTime = SystemClock.elapsedRealtime();
         try {
-            // Since history of network stats only have 2 hours of resolution, when it is
-            // being queried, service will assume that history network stats has uniform
-            // distribution and return a fraction of network stats that is originally
-            // subject to 2 hours. To be specific:
-            //    <returned network stats> = <total network stats> * <duration> / 2 hour,
-            // assuming the duration can fit in a 2 hours bucket.
-            // In the other hand, in statsd, the network stats is queried since boot,
-            // that means in order to assert non-zero packet counts, either the test should
-            // be run after enough time since boot, or the packet counts generated here
-            // should be enough. That is to say:
-            //   <total packet counts> * <up time> / 2 hour >= 1,
-            // or
-            //   iterations >= 2 hour / (<up time> * <packets per iteration>)
-            // Thus, iterations can be chosen based on the factors above to make this
-            // function generate enough packets in each direction to accommodate enough
-            // packet counts for a fraction of history bucket.
-            final double iterations = (TimeUnit.HOURS.toMillis(2) / startTime / 7);
-            // While just enough iterations are going to make the test flaky, add a 20%
-            // buffer to stabilize it and make sure it's in a reasonable range, so it won't
-            // consumes more than 100kb of traffic, or generates 0 byte of traffic.
-            final int augmentedIterations =
-                    (int) Math.max(iterations * 1.2, MIN_EXERCISE_HOST_ITERATIONS);
-            if (augmentedIterations > MAX_EXERCISE_HOST_ITERATIONS) {
-                throw new IllegalStateException("Exceeded max allowed iterations"
-                        + ", iterations=" + augmentedIterations
-                        + ", uptime=" + TimeUnit.MILLISECONDS.toSeconds(startTime) + "s");
-            }
-
-            for (int i = 0; i < augmentedIterations; i++) {
-                // By observing results of "dumpsys netstats --uid", typically the single
-                // run of the https request below generates 4200/1080 rx/tx bytes with
-                // around 7/9 rx/tx packets.
-                // This blocks the thread of NetworkCallback, thus no other event
-                // can be processed before return.
-                exerciseRemoteHost(cm, network, new URL(HTTPS_HOST_URL));
-            }
+            exerciseRemoteHost(cm, network, new URL(HTTPS_HOST_URL));
             Log.i(TAG, "exerciseRemoteHost successful in " + (SystemClock.elapsedRealtime()
-                    - startTime) + " ms with iterations=" + augmentedIterations
-                    + ", uptime=" + TimeUnit.MILLISECONDS.toSeconds(startTime) + "s");
+                    - startTime) + " ms");
         } catch (Exception e) {
             Log.e(TAG, "exerciseRemoteHost failed in " + (SystemClock.elapsedRealtime()
                     - startTime) + " ms: " + e);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index e49f3dd..c6cd042 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -68,9 +68,15 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Queue;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 /**
@@ -112,6 +118,11 @@
     public static final String FEATURE_INCREMENTAL_DELIVERY =
             "android.software.incremental_delivery";
 
+    // Telephony phone types
+    public static final int PHONE_TYPE_GSM = 1;
+    public static final int PHONE_TYPE_CDMA = 2;
+    public static final int PHONE_TYPE_CDMA_LTE = 6;
+
     protected static final int WAIT_TIME_SHORT = 500;
     protected static final int WAIT_TIME_LONG = 2_000;
 
@@ -223,9 +234,11 @@
           // TODO(b/134091167): Fix bluetooth source name issue in Auto platform.
           .addAllowedLogSource("com.android.bluetooth")
           .addAllowedLogSource("AID_LMKD")
+          .addAllowedLogSource("AID_RADIO")
           .addAllowedLogSource("AID_ROOT")
           .addAllowedLogSource("AID_STATSD")
           .addAllowedLogSource(DeviceAtomTestCase.DEVICE_SIDE_TEST_PACKAGE)
+          .addDefaultPullPackages("AID_RADIO")
           .addDefaultPullPackages("AID_SYSTEM");
     }
 
@@ -1006,6 +1019,105 @@
         getDevice().executeShellCommand("cmd connectivity airplane-mode disable");
     }
 
+    /**
+     * Returns a list of fields and values for {@code className} from {@link TelephonyDebugService}
+     * output.
+     *
+     * <p>Telephony dumpsys output does not support proto at the moment. This method provides
+     * limited support for parsing its output. Specifically, it does not support arrays or
+     * multi-line values.
+     */
+    private List<Map<String, String>> getTelephonyDumpEntries(String className) throws Exception {
+        // Matches any line with indentation, except for lines with only spaces
+        Pattern indentPattern = Pattern.compile("^(\\s*)[^ ].*$");
+        // Matches pattern for class, e.g. "    Phone:"
+        Pattern classNamePattern = Pattern.compile("^(\\s*)" + Pattern.quote(className) + ":.*$");
+        // Matches pattern for key-value pairs, e.g. "     mPhoneId=1"
+        Pattern keyValuePattern = Pattern.compile("^(\\s*)([a-zA-Z]+[a-zA-Z0-9_]*)\\=(.+)$");
+        String response =
+                getDevice().executeShellCommand("dumpsys activity service TelephonyDebugService");
+        Queue<String> responseLines = new LinkedList<>(Arrays.asList(response.split("[\\r\\n]+")));
+
+        List<Map<String, String>> results = new ArrayList<>();
+        while (responseLines.peek() != null) {
+            Matcher matcher = classNamePattern.matcher(responseLines.poll());
+            if (matcher.matches()) {
+                final int classIndentLevel = matcher.group(1).length();
+                final Map<String, String> instanceEntries = new HashMap<>();
+                while (responseLines.peek() != null) {
+                    // Skip blank lines
+                    matcher = indentPattern.matcher(responseLines.peek());
+                    if (responseLines.peek().length() == 0 || !matcher.matches()) {
+                        responseLines.poll();
+                        continue;
+                    }
+                    // Finish (without consuming the line) if already parsed past this instance
+                    final int indentLevel = matcher.group(1).length();
+                    if (indentLevel <= classIndentLevel) {
+                        break;
+                    }
+                    // Parse key-value pair if it belongs to the instance directly
+                    matcher = keyValuePattern.matcher(responseLines.poll());
+                    if (indentLevel == classIndentLevel + 1 && matcher.matches()) {
+                        instanceEntries.put(matcher.group(2), matcher.group(3));
+                    }
+                }
+                results.add(instanceEntries);
+            }
+        }
+        return results;
+    }
+
+    protected int getActiveSimSlotCount() throws Exception {
+        List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
+        long count = slots.stream().filter(slot -> "true".equals(slot.get("mActive"))).count();
+        return Math.toIntExact(count);
+    }
+
+    /**
+     * Returns the upper bound of active SIM profile count.
+     *
+     * <p>The value is an upper bound as eSIMs without profiles are also counted in.
+     */
+    protected int getActiveSimCountUpperBound() throws Exception {
+        List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
+        long count = slots.stream().filter(slot ->
+                "true".equals(slot.get("mActive"))
+                && "CARDSTATE_PRESENT".equals(slot.get("mCardState"))).count();
+        return Math.toIntExact(count);
+    }
+
+    /**
+     * Returns the upper bound of active eSIM profile count.
+     *
+     * <p>The value is an upper bound as eSIMs without profiles are also counted in.
+     */
+    protected int getActiveEsimCountUpperBound() throws Exception {
+        List<Map<String, String>> slots = getTelephonyDumpEntries("UiccSlot");
+        long count = slots.stream().filter(slot ->
+                "true".equals(slot.get("mActive"))
+                && "CARDSTATE_PRESENT".equals(slot.get("mCardState"))
+                && "true".equals(slot.get("mIsEuicc"))).count();
+        return Math.toIntExact(count);
+    }
+
+    protected boolean hasGsmPhone() throws Exception {
+        // Not using log entries or ServiceState in the dump since they may or may not be present,
+        // which can make the test flaky
+        return getTelephonyDumpEntries("Phone").stream()
+                .anyMatch(phone ->
+                        String.format("%d", PHONE_TYPE_GSM).equals(phone.get("getPhoneType()")));
+    }
+
+    protected boolean hasCdmaPhone() throws Exception {
+        // Not using log entries or ServiceState in the dump due to the same reason as hasGsmPhone()
+        return getTelephonyDumpEntries("Phone").stream()
+                .anyMatch(phone ->
+                        String.format("%d", PHONE_TYPE_CDMA).equals(phone.get("getPhoneType()"))
+                        || String.format("%d", PHONE_TYPE_CDMA_LTE)
+                                .equals(phone.get("getPhoneType()")));
+    }
+
     // Checks that a timestamp has been truncated to be a multiple of 5 min
     protected void assertTimestampIsTruncated(long timestampNs) {
         long fiveMinutesInNs = NS_PER_SEC * 5 * 60;
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
index 0221852..7c83515 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
@@ -23,6 +23,7 @@
 import android.platform.test.annotations.RestrictedBuildTest;
 import android.server.DeviceIdleModeEnum;
 import android.view.DisplayStateEnum;
+import android.telephony.NetworkTypeEnum;
 
 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
 import com.android.os.AtomsProto.AppBreadcrumbReported;
@@ -30,6 +31,8 @@
 import com.android.os.AtomsProto.BatterySaverModeStateChanged;
 import com.android.os.AtomsProto.BuildInformation;
 import com.android.os.AtomsProto.ConnectivityStateChanged;
+import com.android.os.AtomsProto.SimSlotState;
+import com.android.os.AtomsProto.SupportedRadioAccessFamily;
 import com.android.os.StatsLog.ConfigMetricsReportList;
 import com.android.os.StatsLog.EventMetricData;
 
@@ -51,6 +54,28 @@
     private static final String WAKE_LOCK_FILE = "/proc/wakelocks";
     private static final String WAKE_SOURCES_FILE = "/d/wakeup_sources";
 
+    // Bitmask of radio access technologies that all GSM phones should at least partially support
+    protected static final long NETWORK_TYPE_BITMASK_GSM_ALL =
+            (1 << (NetworkTypeEnum.NETWORK_TYPE_GSM_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_GPRS_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_EDGE_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_UMTS_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_HSDPA_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_HSUPA_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_HSPA_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_HSPAP_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_TD_SCDMA_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_LTE_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_LTE_CA_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_NR_VALUE - 1));
+    // Bitmask of radio access technologies that all CDMA phones should at least partially support
+    protected static final long NETWORK_TYPE_BITMASK_CDMA_ALL =
+            (1 << (NetworkTypeEnum.NETWORK_TYPE_CDMA_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_1XRTT_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_EVDO_0_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_EVDO_A_VALUE - 1))
+            | (1 << (NetworkTypeEnum.NETWORK_TYPE_EHRPD_VALUE - 1));
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -665,4 +690,66 @@
         assertThat(foundConnectEvent).isTrue();
         assertThat(foundDisconnectEvent).isTrue();
     }
+
+    public void testSimSlotState() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+        if (!hasFeature(FEATURE_TELEPHONY, true)) {
+            return;
+        }
+
+        StatsdConfig.Builder config = createConfigBuilder();
+        addGaugeAtomWithDimensions(config, Atom.SIM_SLOT_STATE_FIELD_NUMBER, null);
+        uploadConfig(config);
+
+        Thread.sleep(WAIT_TIME_LONG);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_LONG);
+
+        List<Atom> data = getGaugeMetricDataList();
+        assertThat(data).isNotEmpty();
+        SimSlotState atom = data.get(0).getSimSlotState();
+        // NOTE: it is possible for devices with telephony support to have no SIM at all
+        assertThat(atom.getActiveSlotCount()).isEqualTo(getActiveSimSlotCount());
+        assertThat(atom.getSimCount()).isAtMost(getActiveSimCountUpperBound());
+        assertThat(atom.getEsimCount()).isAtMost(getActiveEsimCountUpperBound());
+        // Above assertions do no necessarily enforce the following, since some are upper bounds
+        assertThat(atom.getActiveSlotCount()).isAtLeast(atom.getSimCount());
+        assertThat(atom.getSimCount()).isAtLeast(atom.getEsimCount());
+        assertThat(atom.getEsimCount()).isAtLeast(0);
+        // For GSM phones, at least one slot should be active even if there is no card
+        if (hasGsmPhone()) {
+            assertThat(atom.getActiveSlotCount()).isAtLeast(1);
+        }
+    }
+
+    public void testSupportedRadioAccessFamily() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+        if (!hasFeature(FEATURE_TELEPHONY, true)) {
+            return;
+        }
+
+        StatsdConfig.Builder config = createConfigBuilder();
+        addGaugeAtomWithDimensions(config, Atom.SUPPORTED_RADIO_ACCESS_FAMILY_FIELD_NUMBER, null);
+        uploadConfig(config);
+
+        Thread.sleep(WAIT_TIME_LONG);
+        setAppBreadcrumbPredicate();
+        Thread.sleep(WAIT_TIME_LONG);
+
+        List<Atom> data = getGaugeMetricDataList();
+        assertThat(data).isNotEmpty();
+        SupportedRadioAccessFamily atom = data.get(0).getSupportedRadioAccessFamily();
+        if (hasGsmPhone()) {
+            assertThat(atom.getNetworkTypeBitmask() & NETWORK_TYPE_BITMASK_GSM_ALL)
+                    .isNotEqualTo(0L);
+        }
+        if (hasCdmaPhone()) {
+            assertThat(atom.getNetworkTypeBitmask() & NETWORK_TYPE_BITMASK_CDMA_ALL)
+                    .isNotEqualTo(0L);
+        }
+    }
 }
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index fb08d2d..2d980aa 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -35,6 +35,7 @@
 import com.android.os.AtomsProto.AppCrashOccurred;
 import com.android.os.AtomsProto.AppOps;
 import com.android.os.AtomsProto.AppStartOccurred;
+import com.android.os.AtomsProto.AppUsageEventOccurred;
 import com.android.os.AtomsProto.Atom;
 import com.android.os.AtomsProto.AttributedAppOps;
 import com.android.os.AtomsProto.AttributionNode;
@@ -87,6 +88,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
 
 /**
  * Statsd atom tests that are done via app, for atoms that report a uid.
@@ -108,6 +110,11 @@
     private static final String TEST_INSTALL_PACKAGE =
             "com.android.cts.device.statsd.emptyapp";
     private static final String TEST_REMOTE_DIR = "/data/local/tmp/statsd";
+    private static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
+
+    private static final int WAIT_TIME_FOR_CONFIG_UPDATE_MS = 200;
+    private static final int EXTRA_WAIT_TIME_MS = 5_000; // as buffer when app starting/stopping.
+    private static final int STATSD_REPORT_WAIT_TIME_MS = 500; // make sure statsd finishes log.
 
     @Override
     protected void setUp() throws Exception {
@@ -2104,6 +2111,32 @@
         getDevice().uninstallPackage(TEST_INSTALL_PACKAGE);
     }
 
+    public void testAppForegroundBackground() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+        Set<Integer> onStates = new HashSet<>(Arrays.asList(
+                AppUsageEventOccurred.EventType.MOVE_TO_FOREGROUND_VALUE));
+        Set<Integer> offStates = new HashSet<>(Arrays.asList(
+                AppUsageEventOccurred.EventType.MOVE_TO_BACKGROUND_VALUE));
+
+        List<Set<Integer>> stateSet = Arrays.asList(onStates, offStates); // state sets, in order
+        createAndUploadConfig(Atom.APP_USAGE_EVENT_OCCURRED_FIELD_NUMBER, false);  // False: does not use attribution.
+        Thread.sleep(WAIT_TIME_FOR_CONFIG_UPDATE_MS);
+
+        getDevice().executeShellCommand(String.format(
+            "am start -n '%s' -e %s %s",
+            "com.android.server.cts.device.statsd/.StatsdCtsForegroundActivity",
+            "action", ACTION_SHOW_APPLICATION_OVERLAY));
+        final int waitTime = EXTRA_WAIT_TIME_MS + 5_000; // Overlay may need to sit there a while.
+        Thread.sleep(waitTime + STATSD_REPORT_WAIT_TIME_MS);
+
+        List<EventMetricData> data = getEventMetricDataList();
+        Function<Atom, Integer> appUsageStateFunction = atom -> atom.getAppUsageEventOccurred().getEventType().getNumber();
+        popUntilFind(data, onStates, appUsageStateFunction); // clear out initial appusage states.
+        assertStatesOccurred(stateSet, data, 0, appUsageStateFunction);
+    }
+
     private AtomsProto.PackageInstallerV2Reported installPackageUsingV2AndGetReport(
             String[] apkNames) throws Exception {
         createAndUploadConfig(Atom.PACKAGE_INSTALLER_V2_REPORTED_FIELD_NUMBER);
diff --git a/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java b/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
index aaf94af..81eb4f5 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/metric/CountMetricsTests.java
@@ -27,6 +27,7 @@
 import com.android.os.AtomsProto.AppBreadcrumbReported;
 import com.android.os.AtomsProto.AttributionNode;
 import com.android.os.AtomsProto.BleScanStateChanged;
+import com.android.os.AtomsProto.WakelockStateChanged;
 import com.android.os.StatsLog;
 import com.android.os.StatsLog.ConfigMetricsReport;
 import com.android.os.StatsLog.ConfigMetricsReportList;
@@ -38,6 +39,8 @@
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 public class CountMetricsTests extends DeviceAtomTestCase {
 
@@ -425,4 +428,136 @@
                 .sum();
         assertThat(totalCount).isEqualTo(2);
     }
+
+    public void testSlicedStateCountMetricNoReset() throws Exception {
+        if (statsdDisabled()) {
+            return;
+        }
+
+        int whatMatcherId = 3;
+        int stateId = 4;
+        int onStateGroupId = 5;
+        int offStateGroupId = 6;
+
+        // Atom 9998 {
+        //     repeated AttributionNode attribution_node = 1;
+        //     optional WakeLockLevelEnum type = 2;
+        //     optional string tag = 3;
+        // }
+        int whatAtomId = 9_998;
+
+        StatsdConfigProto.AtomMatcher whatMatcher =
+                MetricsUtils.getAtomMatcher(whatAtomId)
+                        .setId(whatMatcherId)
+                        .build();
+
+        StatsdConfigProto.State state = StatsdConfigProto.State.newBuilder()
+            .setId(stateId)
+            .setAtomId(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
+            .setMap(StatsdConfigProto.StateMap.newBuilder()
+                    .addGroup(StatsdConfigProto.StateMap.StateGroup.newBuilder()
+                            .setGroupId(onStateGroupId)
+                            .addValue(WakelockStateChanged.State.ACQUIRE_VALUE)
+                            .addValue(WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE)
+                    )
+                    .addGroup(StatsdConfigProto.StateMap.StateGroup.newBuilder()
+                            .setGroupId(offStateGroupId)
+                            .addValue(WakelockStateChanged.State.RELEASE_VALUE)
+                            .addValue(WakelockStateChanged.State.CHANGE_RELEASE_VALUE)
+                    )
+            )
+            .build();
+
+        StatsdConfigProto.MetricStateLink stateLink = StatsdConfigProto.MetricStateLink.newBuilder()
+            .setStateAtomId(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
+            .setFieldsInWhat(FieldMatcher.newBuilder()
+                    .setField(whatAtomId)
+                    .addChild(FieldMatcher.newBuilder()
+                            .setField(1)
+                            .setPosition(Position.FIRST)
+                            .addChild(FieldMatcher.newBuilder()
+                                    .setField(AttributionNode.UID_FIELD_NUMBER)
+                            )
+                    )
+                    .addChild(FieldMatcher.newBuilder()
+                            .setField(2)
+                    )
+                    .addChild(FieldMatcher.newBuilder()
+                            .setField(3)
+                    )
+            )
+            .setFieldsInState(FieldMatcher.newBuilder()
+                    .setField(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER)
+                    .addChild(FieldMatcher.newBuilder()
+                            .setField(WakelockStateChanged.ATTRIBUTION_NODE_FIELD_NUMBER)
+                            .setPosition(Position.FIRST)
+                            .addChild(FieldMatcher.newBuilder()
+                                    .setField(AttributionNode.UID_FIELD_NUMBER)
+                            )
+                    )
+                    .addChild(FieldMatcher.newBuilder()
+                            .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
+                    )
+                    .addChild(FieldMatcher.newBuilder()
+                            .setField(WakelockStateChanged.TAG_FIELD_NUMBER)
+                    )
+            )
+            .build();
+
+        StatsdConfigProto.StatsdConfig.Builder builder = createConfigBuilder()
+                .addCountMetric(StatsdConfigProto.CountMetric.newBuilder()
+                    .setId(MetricsUtils.COUNT_METRIC_ID)
+                    .setBucket(StatsdConfigProto.TimeUnit.CTS)
+                    .setWhat(whatMatcherId)
+                    .addSliceByState(stateId)
+                    .addStateLink(stateLink)
+                )
+                .addAtomMatcher(whatMatcher)
+                .addState(state);
+        uploadConfig(builder);
+
+        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSliceByWakelockState");
+
+        StatsLogReport metricReport = getStatsLogReport();
+        LogUtil.CLog.d("Got the following stats log report: \n" + metricReport.toString());
+        assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.COUNT_METRIC_ID);
+        assertThat(metricReport.hasCountMetrics()).isTrue();
+
+        StatsLogReport.CountMetricDataWrapper dataWrapper = metricReport.getCountMetrics();
+        assertThat(dataWrapper.getDataCount()).isEqualTo(2);
+
+
+        List<CountMetricData> sortedDataList = IntStream.range(0, dataWrapper.getDataCount())
+                .mapToObj(i -> {
+                        CountMetricData data = dataWrapper.getData(i);
+                        assertWithMessage("Unexpected SliceByState count for data[%s]", "" + i)
+                                .that(data.getSliceByStateCount()).isEqualTo(1);
+                        return data;
+                })
+                .sorted((data1, data2) ->
+                        Long.compare(data1.getSliceByState(0).getGroupId(),
+                                data2.getSliceByState(0).getGroupId())
+                )
+                .collect(Collectors.toList());
+
+        CountMetricData data = sortedDataList.get(0);
+        assertThat(data.getSliceByState(0).getAtomId())
+                .isEqualTo(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER);
+        assertThat(data.getSliceByState(0).getGroupId())
+                .isEqualTo(onStateGroupId);
+        long totalCount = data.getBucketInfoList().stream()
+                .mapToLong(CountBucketInfo::getCount)
+                .sum();
+        assertThat(totalCount).isEqualTo(6);
+
+        data = sortedDataList.get(1);
+        assertThat(data.getSliceByState(0).getAtomId())
+                .isEqualTo(Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER);
+        assertThat(data.getSliceByState(0).getGroupId())
+                .isEqualTo(offStateGroupId);
+        totalCount = data.getBucketInfoList().stream()
+                .mapToLong(CountBucketInfo::getCount)
+                .sum();
+        assertThat(totalCount).isEqualTo(3);
+    }
 }
diff --git a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
index 85cc7d9..95dbaa6 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/validation/BatteryStatsValidationTests.java
@@ -51,6 +51,7 @@
     @Override
     protected void tearDown() throws Exception {
         plugInUsb();
+        super.tearDown();
     }
 
     /*
diff --git a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
index 2c75a7f..0da168b 100644
--- a/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
+++ b/hostsidetests/userspacereboot/src/com/android/cts/userspacereboot/host/UserspaceRebootHostTest.java
@@ -40,6 +40,7 @@
 /**
  * Host side CTS tests verifying userspace reboot functionality.
  */
+@RequiresDevice
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class UserspaceRebootHostTest extends BaseHostJUnit4Test  {
 
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/IdleConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/IdleConstraintTest.java
index 6d7d95c..3551205 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/IdleConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/IdleConstraintTest.java
@@ -45,12 +45,19 @@
     private JobInfo.Builder mBuilder;
     private UiDevice mUiDevice;
 
+    private String mInitialDisplayTimeout;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mBuilder = new JobInfo.Builder(STATE_JOB_ID, kJobServiceComponent);
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+
+        // Make sure the screen doesn't turn off when the test turns it on.
+        mInitialDisplayTimeout = mUiDevice.executeShellCommand(
+                "settings get system screen_off_timeout");
+        mUiDevice.executeShellCommand("settings put system screen_off_timeout 300000");
     }
 
     @Override
@@ -58,7 +65,12 @@
         mJobScheduler.cancel(STATE_JOB_ID);
         // Put device back in to normal operation.
         toggleScreenOn(true);
-        setCarMode(false);
+        if (isCarModeSupported()) {
+            setCarMode(false);
+        }
+
+        mUiDevice.executeShellCommand(
+                "settings put system screen_off_timeout " + mInitialDisplayTimeout);
 
         super.tearDown();
     }
@@ -153,6 +165,12 @@
         verifyActiveState();
     }
 
+    private boolean isCarModeSupported() {
+        // TVs don't support car mode.
+        return !getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LEANBACK_ONLY);
+    }
+
     /**
      * Check if dock state is supported.
      */
@@ -227,6 +245,10 @@
      * Ensure car mode is considered active.
      */
     public void testCarModePreventsIdle() throws Exception {
+        if (!isCarModeSupported()) {
+            return;
+        }
+
         toggleScreenOn(false);
 
         setCarMode(true);
@@ -239,6 +261,10 @@
     }
 
     private void runIdleJobStartsOnlyWhenIdle() throws Exception {
+        if (!isCarModeSupported()) {
+            return;
+        }
+
         toggleScreenOn(true);
 
         kTestEnvironment.setExpectedExecutions(0);
@@ -276,6 +302,10 @@
     }
 
     public void testIdleJobStartsOnlyWhenIdle_carEndsIdle() throws Exception {
+        if (!isCarModeSupported()) {
+            return;
+        }
+
         runIdleJobStartsOnlyWhenIdle();
 
         setCarMode(true);
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index a1a5b67..c065b1e 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -73,6 +73,8 @@
     private static final long POLL_INTERVAL = 500;
     private static final long DEFAULT_WAIT_TIMEOUT = 2000;
     private static final long SHELL_TIMEOUT = 3_000;
+    // TODO: mark Settings.System.SCREEN_OFF_TIMEOUT as @TestApi
+    private static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
     enum Bucket {
         ACTIVE,
@@ -99,6 +101,7 @@
     private boolean mInitialWiFiState;
     private boolean mInitialAirplaneModeState;
     private String mInitialJobSchedulerConstants;
+    private String mInitialDisplayTimeout;
 
     private TestAppInterface mTestAppInterface;
 
@@ -155,6 +158,10 @@
         // Make sure test jobs can run regardless of bucket.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.JOB_SCHEDULER_CONSTANTS, "min_ready_non_active_jobs_count=0");
+        // Make sure the screen doesn't turn off when the test turns it on.
+        mInitialDisplayTimeout =
+                Settings.System.getString(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT);
+        Settings.System.putString(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, "300000");
     }
 
     @Test
@@ -480,6 +487,9 @@
         mUiDevice.executeShellCommand(
                 "cmd jobscheduler reset-execution-quota -u " + UserHandle.myUserId()
                         + " " + TEST_APP_PACKAGE);
+
+        Settings.System.putString(
+                mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, mInitialDisplayTimeout);
     }
 
     private void setTestPackageRestricted(boolean restricted) throws Exception {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java
index 4384f29..58265f8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityShortcutTest.java
@@ -56,6 +56,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -212,6 +213,32 @@
                 Arrays.asList(mSpeakingA11yServiceName, mShortcutTargetActivityName));
     }
 
+    @Test
+    public void testAccessibilityButtonService_disableSelf_buttonRemoved() {
+        mA11yButtonServiceRule.enableService();
+        mShortcutSettingsRule.configureAccessibilityButton(
+                sUiAutomation, mA11yButtonServiceName);
+        mShortcutSettingsRule.waitForAccessibilityButtonStateChange(
+                sUiAutomation, Arrays.asList(mA11yButtonServiceName));
+
+        mA11yButtonServiceRule.getService().disableSelfAndRemove();
+        mShortcutSettingsRule.waitForAccessibilityButtonStateChange(sUiAutomation,
+                Collections.emptyList());
+    }
+
+    @Test
+    public void testAccessibilityButtonService_disableSelf_shortcutRemoved() {
+        mA11yButtonServiceRule.enableService();
+        mShortcutSettingsRule.configureAccessibilityShortcut(
+                sUiAutomation, mA11yButtonServiceName);
+        mShortcutSettingsRule.waitForAccessibilityShortcutStateChange(
+                sUiAutomation, Arrays.asList(mA11yButtonServiceName));
+
+        mA11yButtonServiceRule.getService().disableSelfAndRemove();
+        mShortcutSettingsRule.waitForAccessibilityShortcutStateChange(sUiAutomation,
+                Collections.emptyList());
+    }
+
     /**
      * Perform shortcut and wait for accessibility button clicked call back.
      *
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 5a8e337..ff2fed4 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -89,6 +89,19 @@
             android:screenOrientation="locked"/>
 
         <service
+            android:name=".StubSystemActionsAccessibilityService"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+            <intent-filter>
+                <action android:name="android.accessibilityservice.AccessibilityService" />
+                <category android:name="android.accessibilityservice.category.FEEDBACK_GENERIC" />
+            </intent-filter>
+
+            <meta-data
+                android:name="android.accessibilityservice"
+                android:resource="@xml/stub_system_actions_a11y_service" />
+        </service>
+
+        <service
                 android:name=".StubGestureAccessibilityService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
             <intent-filter>
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index 73ffb68..7b6be1e 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -147,6 +147,8 @@
 
     <string name="foo_bar_baz">Foo bar baz.</string>
 
+    <string name="stub_system_actions_a11y_service_description">com.android.accessibilityservice.cts.StubSystemActionsAccessibilityService</string>
+
     <string name="stub_gesture_dispatch_a11y_service_description">com.android.accessibilityservice.cts.StubGestureAccessibilityService</string>
 
     <string name="stub_gesture_detector_a11y_service_description">com.android.accessibilityservice.cts.GestureDetectionStubAccessibilityService</string>
diff --git a/tests/accessibilityservice/res/xml/stub_system_actions_a11y_service.xml b/tests/accessibilityservice/res/xml/stub_system_actions_a11y_service.xml
new file mode 100644
index 0000000..e505f5f
--- /dev/null
+++ b/tests/accessibilityservice/res/xml/stub_system_actions_a11y_service.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+                       android:description="@string/stub_system_actions_a11y_service_description"
+/>
\ No newline at end of file
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java
new file mode 100644
index 0000000..f53f126
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java
@@ -0,0 +1,233 @@
+/*
+ * 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.accessibilityservice.cts;
+
+import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
+import static android.app.UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES;
+import static org.junit.Assert.fail;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
+import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule;
+import android.accessibilityservice.AccessibilityService;
+import android.app.Instrumentation;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
+import android.platform.test.annotations.AppModeFull;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilitySystemActionTest {
+    // intent actions to trigger system action callbacks
+    private final static String INTENT_ACTION_SYSTEM_ACTION_CALLBACK_OVERRIDE_BACK = "android.accessibility.cts.end2endtests.action.system_action_callback_override_back";
+    private final static String INTENT_ACTION_SYSTEM_ACTION_CALLBACK_NEW = "android.accessibility.cts.end2endtests.action.system_action_callback_new";
+
+    private final static int NEW_ACTION_ID = 111;
+    private final static String MANAGE_ACCESSIBILITY_PERMISSION = "android.permission.MANAGE_ACCESSIBILITY";
+
+    private static Instrumentation sInstrumentation;
+    private static UiAutomation sUiAutomation;
+
+    private Context mContext;
+    private AccessibilityManager mAccessibilityManager;
+
+    private InstrumentedAccessibilityServiceTestRule<StubSystemActionsAccessibilityService>
+            mServiceRule = new InstrumentedAccessibilityServiceTestRule<>(
+            StubSystemActionsAccessibilityService.class, false);
+
+    private AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+            new AccessibilityDumpOnFailureRule();
+
+    @Rule
+    public final RuleChain mRuleChain = RuleChain
+            .outerRule(mServiceRule)
+            .around(mDumpOnFailureRule);
+
+    StubSystemActionsAccessibilityService mService;
+
+    @BeforeClass
+    public static void oneTimeSetup() {
+        sInstrumentation = InstrumentationRegistry.getInstrumentation();
+        sUiAutomation = sInstrumentation.getUiAutomation(FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+        sUiAutomation.adoptShellPermissionIdentity(MANAGE_ACCESSIBILITY_PERMISSION);
+    }
+
+    @AfterClass
+    public static void finalTearDown() {
+        sUiAutomation.dropShellPermissionIdentity();
+        sUiAutomation.destroy();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mAccessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        // Start stub accessibility service.
+        mService = mServiceRule.enableService();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mService.setLatch(null);
+    }
+
+    @Test
+    @AppModeFull
+    public void testRegisterOverriddenLegacyAction() {
+        assertRegisterAction(AccessibilityService.GLOBAL_ACTION_BACK, null);
+    }
+
+    @Test
+    @AppModeFull
+    public void testUnregisterAction() {
+        assertRegisterAction(AccessibilityService.GLOBAL_ACTION_BACK, null);
+        assertUnregisterAction(AccessibilityService.GLOBAL_ACTION_BACK);
+    }
+
+    @Test
+    @AppModeFull
+    public void testNewActionInGetSystemActions() {
+        assertRegisterAction(NEW_ACTION_ID, null);
+        if (!mService.getSystemActions().contains(
+                new AccessibilityAction(NEW_ACTION_ID, null))) {
+            fail("new action should be in getSystemActions() list");
+        }
+    }
+
+
+    @Test
+    @AppModeFull
+    public void testNewActionNotInGetSystemActions() {
+        assertRegisterAction(NEW_ACTION_ID, null);
+        assertUnregisterAction(NEW_ACTION_ID);
+        if (mService.getSystemActions().contains(
+                new AccessibilityAction(NEW_ACTION_ID, null))) {
+            fail("new action should not be in getSystemActions() list");
+        }
+    }
+
+    @Test
+    @AppModeFull
+    public void testPerformOverriddenLegacyAction() {
+        assertRegisterAction(
+                AccessibilityService.GLOBAL_ACTION_BACK,
+                INTENT_ACTION_SYSTEM_ACTION_CALLBACK_OVERRIDE_BACK);
+        assertPerformGlobalAction(
+                AccessibilityService.GLOBAL_ACTION_BACK,
+                INTENT_ACTION_SYSTEM_ACTION_CALLBACK_OVERRIDE_BACK);
+    }
+
+    @Test
+    @AppModeFull
+    public void testPerformNewAction() {
+        assertRegisterAction(NEW_ACTION_ID, INTENT_ACTION_SYSTEM_ACTION_CALLBACK_NEW);
+        assertPerformGlobalAction(NEW_ACTION_ID, INTENT_ACTION_SYSTEM_ACTION_CALLBACK_NEW);
+    }
+
+    private void assertRegisterAction(int actionID, String pendingIntent) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mService.setLatch(latch);
+        try {
+            RemoteAction r = getRemoteAction(pendingIntent);
+            mAccessibilityManager.registerSystemAction(r, actionID);
+            if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                fail("did not register " + actionID);
+            }
+        } catch (InterruptedException e) {
+            fail("latch.await throws exception");
+        }
+    }
+
+    private void assertUnregisterAction(int actionID) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mService.setLatch(latch);
+        try {
+            mAccessibilityManager.unregisterSystemAction(actionID);
+            if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                fail("did not unregister " + actionID);
+            }
+        } catch (InterruptedException e) {
+            fail("latch.await throws exception");
+        }
+    }
+
+    private void assertPerformGlobalAction(int actionId, String pendingIntent) {
+        final CountDownLatch receiverLatch = new CountDownLatch(1);
+        BroadcastReceiver receiver = new SystemActionBroadcastReceiver(
+                receiverLatch,
+                pendingIntent);
+        mContext.registerReceiver(receiver, new IntentFilter(pendingIntent));
+        try {
+            mService.performGlobalAction(actionId);
+            if (!receiverLatch.await(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                fail("action not triggered; did not receive callback intent");
+            }
+        } catch (InterruptedException e) {
+            fail("latch.await throws exception");
+        } finally {
+            mContext.unregisterReceiver(receiver);
+            mAccessibilityManager.unregisterSystemAction(actionId);
+        }
+    }
+
+    private RemoteAction getRemoteAction(String pendingIntent) {
+        Intent i = new Intent(pendingIntent);
+        PendingIntent p = PendingIntent.getBroadcast(mContext, 0, i, 0);
+        return new RemoteAction(Icon.createWithContentUri("content://test"), "test1", "test1", p);
+    }
+
+    private static class SystemActionBroadcastReceiver extends BroadcastReceiver {
+        private final CountDownLatch mLatch;
+        private final String mExpectedAction;
+
+        public SystemActionBroadcastReceiver(CountDownLatch latch, String expectedAction) {
+            super();
+            mLatch = latch;
+            mExpectedAction = expectedAction;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (mExpectedAction.equals(action)) {
+                mLatch.countDown();
+            }
+        }
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSystemActionsAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSystemActionsAccessibilityService.java
new file mode 100644
index 0000000..b32dc8e
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSystemActionsAccessibilityService.java
@@ -0,0 +1,37 @@
+/*
+ * 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.accessibilityservice.cts;
+
+import android.accessibility.cts.common.InstrumentedAccessibilityService;
+import android.content.Intent;
+
+import java.util.concurrent.CountDownLatch;
+
+public class StubSystemActionsAccessibilityService  extends InstrumentedAccessibilityService {
+    private CountDownLatch latch;
+
+    @Override
+    public void onSystemActionsChanged() {
+        if  (latch != null) {
+            latch.countDown();
+        }
+    }
+
+    void setLatch(CountDownLatch latch) {
+        this.latch = latch;
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
index cfb04b4..83ac347 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/ActivityLaunchUtils.java
@@ -14,12 +14,12 @@
 
 package android.accessibilityservice.cts.utils;
 
+import static android.accessibility.cts.common.ShellCommandBuilder.execShellCommand;
 import static android.accessibilityservice.cts.utils.AsyncUtils.DEFAULT_TIMEOUT_MS;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
-import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Activity;
 import android.app.ActivityOptions;
@@ -58,6 +58,8 @@
  */
 public class ActivityLaunchUtils {
     private static final String LOG_TAG = "ActivityLaunchUtils";
+    private static final String AM_START_HOME_ACTIVITY_COMMAND =
+            "am start -a android.intent.action.MAIN -c android.intent.category.HOME";
 
     // Using a static variable so it can be used in lambdas. Not preserving state in it.
     private static Activity mTempActivity;
@@ -131,7 +133,7 @@
         try {
             executeAndWaitOn(
                     uiAutomation,
-                    () -> uiAutomation.performGlobalAction(AccessibilityService.GLOBAL_ACTION_HOME),
+                    () -> execShellCommand(uiAutomation, AM_START_HOME_ACTIVITY_COMMAND),
                     () -> isHomeScreenShowing(context, uiAutomation),
                     DEFAULT_TIMEOUT_MS,
                     "home screen");
diff --git a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
index c49e89a..9a34f20 100644
--- a/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
+++ b/tests/app/AppExitTest/src/android/app/cts/ActivityManagerAppExitInfoTest.java
@@ -38,7 +38,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -51,20 +50,15 @@
 import android.util.DebugUtils;
 import android.util.Log;
 
+import com.android.compatibility.common.util.AmMonitor;
 import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.MemInfoReader;
 
 import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
 import java.nio.DirectByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
@@ -522,7 +516,8 @@
         // Sleep for a while to make sure it's already blocking its main thread.
         sleep(WAITFOR_MSEC);
 
-        Monitor monitor = new Monitor(mInstrumentation);
+        AmMonitor monitor = new AmMonitor(mInstrumentation,
+                new String[]{AmMonitor.WAIT_FOR_CRASHED});
 
         Intent intent = new Intent();
         intent.setComponent(new ComponentName(STUB_PACKAGE_NAME, STUB_RECEIVER_NAMWE));
@@ -531,13 +526,13 @@
         mContext.sendOrderedBroadcast(intent, null);
 
         // Wait for the early ANR
-        monitor.waitFor(Monitor.WAIT_FOR_EARLY_ANR, timeout);
+        monitor.waitFor(AmMonitor.WAIT_FOR_EARLY_ANR, timeout);
         // Continue, so we could collect ANR traces
-        monitor.sendCommand(Monitor.CMD_CONTINUE);
+        monitor.sendCommand(AmMonitor.CMD_CONTINUE);
         // Wait for the ANR
-        monitor.waitFor(Monitor.WAIT_FOR_ANR, timeout);
+        monitor.waitFor(AmMonitor.WAIT_FOR_ANR, timeout);
         // Kill it
-        monitor.sendCommand(Monitor.CMD_KILL);
+        monitor.sendCommand(AmMonitor.CMD_KILL);
         // Wait the process gone
         waitForGone(mWatcher);
         long now2 = System.currentTimeMillis();
@@ -1138,111 +1133,4 @@
         assertTrue(ArrayUtils.equals(info.getProcessStateSummary(), cookie,
                 cookie == null ? 0 : cookie.length));
     }
-
-    /**
-     * A utility class interact with "am monitor"
-     */
-    private static class Monitor {
-        static final String WAIT_FOR_EARLY_ANR = "Waiting after early ANR...  available commands:";
-        static final String WAIT_FOR_ANR = "Waiting after ANR...  available commands:";
-        static final String WAIT_FOR_CRASHED = "Waiting after crash...  available commands:";
-        static final String CMD_CONTINUE = "c";
-        static final String CMD_KILL = "k";
-
-        final Instrumentation mInstrumentation;
-        final ParcelFileDescriptor mReadFd;
-        final FileInputStream mReadStream;
-        final BufferedReader mReadReader;
-        final ParcelFileDescriptor mWriteFd;
-        final FileOutputStream mWriteStream;
-        final PrintWriter mWritePrinter;
-        final Thread mReaderThread;
-
-        final ArrayList<String> mPendingLines = new ArrayList<>();
-
-        boolean mStopping;
-
-        Monitor(Instrumentation instrumentation) {
-            mInstrumentation = instrumentation;
-            ParcelFileDescriptor[] pfds = instrumentation.getUiAutomation()
-                    .executeShellCommandRw("am monitor");
-            mReadFd = pfds[0];
-            mReadStream = new ParcelFileDescriptor.AutoCloseInputStream(mReadFd);
-            mReadReader = new BufferedReader(new InputStreamReader(mReadStream));
-            mWriteFd = pfds[1];
-            mWriteStream = new ParcelFileDescriptor.AutoCloseOutputStream(mWriteFd);
-            mWritePrinter = new PrintWriter(new BufferedOutputStream(mWriteStream));
-            mReaderThread = new ReaderThread();
-            mReaderThread.start();
-        }
-
-        void waitFor(String expected, long timeout) {
-            long waitUntil = SystemClock.uptimeMillis() + timeout;
-            synchronized (mPendingLines) {
-                while (true) {
-                    while (mPendingLines.size() == 0) {
-                        long now = SystemClock.uptimeMillis();
-                        if (now >= waitUntil) {
-                            String msg = "Timed out waiting for next line: expected=" + expected;
-                            Log.d(TAG, msg);
-                            throw new IllegalStateException(msg);
-                        }
-                        try {
-                            mPendingLines.wait(waitUntil - now);
-                        } catch (InterruptedException e) {
-                        }
-                    }
-                    String line = mPendingLines.remove(0);
-                    if (TextUtils.equals(line, expected)) {
-                        break;
-                    } else if (TextUtils.equals(line, WAIT_FOR_EARLY_ANR)
-                            || TextUtils.equals(line, WAIT_FOR_ANR)
-                            || TextUtils.equals(line, WAIT_FOR_CRASHED)) {
-                        // If we are getting any of the unexpected state,
-                        // for example, get a crash while waiting for an ANR,
-                        // it could be from another unrelated process, kill it directly.
-                        sendCommand(CMD_KILL);
-                    }
-                }
-            }
-        }
-
-        void finish() {
-            synchronized (mPendingLines) {
-                mStopping = true;
-            }
-            mWritePrinter.println("q");
-            try {
-                mWriteStream.close();
-            } catch (IOException e) {
-            }
-            try {
-                mReadStream.close();
-            } catch (IOException e) {
-            }
-        }
-
-        void sendCommand(String cmd) {
-            mWritePrinter.println(cmd);
-            mWritePrinter.flush();
-        }
-
-        final class ReaderThread extends Thread {
-            @Override
-            public void run() {
-                try {
-                    String line;
-                    while ((line = mReadReader.readLine()) != null) {
-                        // Log.i(TAG, "debug: " + line);
-                        synchronized (mPendingLines) {
-                            mPendingLines.add(line);
-                            mPendingLines.notifyAll();
-                        }
-                    }
-                } catch (IOException e) {
-                    Log.w(TAG, "Failed reading", e);
-                }
-            }
-        }
-    }
 }
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 61b5cbc..1be2930 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -44,7 +44,7 @@
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
-import com.android.compatibility.common.util.AnrMonitor;
+import com.android.compatibility.common.util.AmMonitor;
 import com.android.compatibility.common.util.SystemUtil;
 
 import java.io.IOException;
@@ -766,7 +766,8 @@
      */
     public void testAppNotResponding() throws Exception {
         // Setup the ANR monitor
-        AnrMonitor monitor = new AnrMonitor(mInstrumentation);
+        AmMonitor monitor = new AmMonitor(mInstrumentation,
+                new String[]{AmMonitor.WAIT_FOR_CRASHED});
 
         // Now tell it goto ANR
         CommandReceiver.sendCommand(mTargetContext, CommandReceiver.COMMAND_SELF_INDUCED_ANR,
@@ -775,10 +776,10 @@
         try {
 
             // Verify we got the ANR
-            assertTrue(monitor.waitFor(WAITFOR_MSEC));
+            assertTrue(monitor.waitFor(AmMonitor.WAIT_FOR_EARLY_ANR, WAITFOR_MSEC));
 
             // Just kill the test app
-            monitor.sendCommand(AnrMonitor.CMD_KILL);
+            monitor.sendCommand(AmMonitor.CMD_KILL);
         } finally {
             // clean up
             monitor.finish();
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 553c0dc..572f9e7 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -2564,10 +2564,21 @@
         }
     }
 
-    public void testAreBubblesAllowed() {
+    public void testAreBubblesAllowed_appNone() throws Exception {
+        setBubblesAppPref(0 /* none */);
         assertFalse(mNotificationManager.areBubblesAllowed());
     }
 
+    public void testAreBubblesAllowed_appSelected() throws Exception {
+        setBubblesAppPref(2 /* selected */);
+        assertFalse(mNotificationManager.areBubblesAllowed());
+    }
+
+    public void testAreBubblesAllowed_appAll() throws Exception {
+        setBubblesAppPref(1 /* all */);
+        assertTrue(mNotificationManager.areBubblesAllowed());
+    }
+
     public void testNotificationIcon() {
         int id = 6000;
 
@@ -2872,6 +2883,7 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
             createDynamicShortcut();
 
             Notification.Builder nb = getConversationNotification();
@@ -2893,6 +2905,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             setUpNotifListener();
 
@@ -2918,6 +2932,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             setUpNotifListener();
 
@@ -2939,6 +2955,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             setUpNotifListener();
 
@@ -2964,6 +2982,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             setUpNotifListener();
 
@@ -3003,6 +3023,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
 
             Notification.Builder nb = getConversationNotification();
@@ -3026,6 +3048,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
 
             Notification.Builder nb = getConversationNotification();
@@ -3049,6 +3073,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
 
             Notification.BubbleMetadata data =
@@ -3070,6 +3096,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3091,6 +3119,8 @@
         try {
             setBubblesGlobal(false);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3112,6 +3142,7 @@
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
             setBubblesChannelAllowed(false);
+
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3133,6 +3164,7 @@
             setBubblesGlobal(true);
             setBubblesAppPref(2 /* selected */);
             setBubblesChannelAllowed(false);
+
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3154,6 +3186,7 @@
             setBubblesGlobal(true);
             setBubblesAppPref(2 /* selected */);
             setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3176,6 +3209,7 @@
             setBubblesGlobal(true);
             setBubblesAppPref(0 /* none */);
             setBubblesChannelAllowed(false);
+
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3198,6 +3232,7 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
             createDynamicShortcut();
             Notification.BubbleMetadata data =
                     new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID)
@@ -3205,12 +3240,11 @@
             Notification.Builder nb = getConversationNotification();
 
             boolean shouldBeBubble = !mActivityManager.isLowRamDevice();
-            sendAndVerifyBubble(1, nb, data, shouldBeBubble);
+            sendAndVerifyBubble(42, nb, data, shouldBeBubble);
             mListener.resetData();
 
             deleteShortcuts();
-
-            verifyNotificationBubbleState(1, false /* should be bubble */);
+            verifyNotificationBubbleState(42, false /* should be bubble */);
         } finally {
             deleteShortcuts();
         }
@@ -3224,6 +3258,8 @@
         try {
             setBubblesGlobal(true);
             setBubblesAppPref(1 /* all */);
+            setBubblesChannelAllowed(true);
+
             createDynamicShortcut();
             setUpNotifListener();
 
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 5b1a86e..6c229e0 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -24,6 +24,7 @@
 
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
+import android.app.PendingIntent;
 import android.autofillservice.cts.InstrumentedAutoFillService.Replier;
 import android.autofillservice.cts.inline.InlineUiBot;
 import android.content.ClipboardManager;
@@ -441,6 +442,11 @@
             return Helper.createInlinePresentation(message);
         }
 
+        protected InlinePresentation createInlinePresentation(String message,
+                                                              PendingIntent attribution) {
+            return Helper.createInlinePresentation(message, attribution);
+        }
+
         @NonNull
         protected AutofillManager getAutofillManager() {
             return mContext.getSystemService(AutofillManager.class);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java b/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java
index 6c29197..ce2c7a2 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutofillTestWatcher.java
@@ -21,6 +21,7 @@
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.TestNameUtils;
 
@@ -66,6 +67,7 @@
 
     @Override
     protected void finished(Description description) {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         final String testName = description.getDisplayName();
         cleanAllActivities();
         Log.i(TAG, "Finished " + testName);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index ecd5cd2..533b8df 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -32,11 +32,13 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.app.Activity;
+import android.app.PendingIntent;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
 import android.app.assist.AssistStructure.WindowNode;
 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.Bitmap;
@@ -65,7 +67,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.autofill.InlinePresentationBuilder;
+import androidx.autofill.inline.v1.InlineSuggestionUi;
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.BitmapUtils;
@@ -1518,15 +1520,29 @@
     }
 
     public static InlinePresentation createInlinePresentation(String message) {
-        return new InlinePresentation(new InlinePresentationBuilder(message).build(),
-                new InlinePresentationSpec.Builder(new Size(100, 100), new Size(400, 100))
-                        .build(), /* pinned= */ false);
+        final PendingIntent dummyIntent =
+                PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+        return createInlinePresentation(message, dummyIntent, false);
+    }
+
+    public static InlinePresentation createInlinePresentation(String message,
+            PendingIntent attribution) {
+        return createInlinePresentation(message, attribution, false);
     }
 
     public static InlinePresentation createPinnedInlinePresentation(String message) {
-        return new InlinePresentation(new InlinePresentationBuilder(message).build(),
+        final PendingIntent dummyIntent =
+                PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+        return createInlinePresentation(message, dummyIntent, true);
+    }
+
+    private static InlinePresentation createInlinePresentation(@NonNull String message,
+            @NonNull PendingIntent attribution, boolean pinned) {
+        return new InlinePresentation(
+                InlineSuggestionUi.newContentBuilder().setAttribution(attribution)
+                        .setTitle(message).build().getSlice(),
                 new InlinePresentationSpec.Builder(new Size(100, 100), new Size(400, 100))
-                        .build(), /* pinned= */ true);
+                        .build(), /* pinned= */ pinned);
     }
 
     private Helper() {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 534aa5c..6baa5a1 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -83,7 +83,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
-import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -498,7 +497,6 @@
         sReplier.getNextFillRequest();
         callback.assertUiShownEvent(username);
         final Rect usernamePickerBoundaries1 = mUiBot.assertDatasets("DUDE").getVisibleBounds();
-        final Bitmap usernameScreenshot1 = mUiBot.takeScreenshot(mActivity);
         Log.v(TAG,
                 "Username1 at " + usernameBoundaries1 + "; picker at " + usernamePickerBoundaries1);
         // TODO(b/37566627): assertions below might be too aggressive - use range instead?
@@ -512,7 +510,6 @@
         callback.assertUiHiddenEvent(username);
         callback.assertUiShownEvent(password);
         final Rect passwordPickerBoundaries1 = mUiBot.assertDatasets("SWEET").getVisibleBounds();
-        final Bitmap passwordScreenshot1 = mUiBot.takeScreenshot(mActivity);
         Log.v(TAG,
                 "Password1 at " + passwordBoundaries1 + "; picker at " + passwordPickerBoundaries1);
         // TODO(b/37566627): assertions below might be too aggressive - use range instead?
@@ -526,7 +523,6 @@
         callback.assertUiHiddenEvent(password);
         callback.assertUiShownEvent(username);
         final Rect usernamePickerBoundaries2 = mUiBot.assertDatasets("DUDE").getVisibleBounds();
-        final Bitmap usernameScreenshot2 = mUiBot.takeScreenshot(mActivity);
         Log.v(TAG,
                 "Username2 at " + usernameBoundaries2 + "; picker at " + usernamePickerBoundaries2);
 
@@ -535,20 +531,23 @@
         callback.assertUiHiddenEvent(username);
         callback.assertUiShownEvent(password);
         final Rect passwordPickerBoundaries2 = mUiBot.assertDatasets("SWEET").getVisibleBounds();
-        final Bitmap passwordScreenshot2 = mUiBot.takeScreenshot(mActivity);
         Log.v(TAG,
                 "Password2 at " + passwordBoundaries2 + "; picker at " + passwordPickerBoundaries2);
 
         // Assert final state matches initial...
         // ... for username
-        assertThat(usernameBoundaries2).isEqualTo(usernameBoundaries1);
-        assertThat(usernamePickerBoundaries2).isEqualTo(usernamePickerBoundaries1);
-        Helper.assertBitmapsAreSame("username", usernameScreenshot1, usernameScreenshot2);
+        assertWithMessage("Username2 at %s; Username1 at %s", usernameBoundaries2,
+                usernamePickerBoundaries1).that(usernameBoundaries2).isEqualTo(usernameBoundaries1);
+        assertWithMessage("Username2 picker at %s; Username1 picker at %s",
+                usernamePickerBoundaries2, usernamePickerBoundaries1).that(
+                usernamePickerBoundaries2).isEqualTo(usernamePickerBoundaries1);
 
         // ... for password
-        assertThat(passwordBoundaries2).isEqualTo(passwordBoundaries1);
-        assertThat(passwordPickerBoundaries2).isEqualTo(passwordPickerBoundaries1);
-        Helper.assertBitmapsAreSame("password", passwordScreenshot1, passwordScreenshot2);
+        assertWithMessage("Password2 at %s; Password1 at %s", passwordBoundaries2,
+                passwordBoundaries1).that(passwordBoundaries2).isEqualTo(passwordBoundaries1);
+        assertWithMessage("Password2 picker at %s; Password1 picker at %s",
+                passwordPickerBoundaries2, passwordPickerBoundaries1).that(
+                passwordPickerBoundaries2).isEqualTo(passwordPickerBoundaries1);
 
         // Final sanity check
         callback.assertNumberUnhandledEvents(0);
@@ -1534,10 +1533,10 @@
                     .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
                     .build());
             mActivity.forceAutofillOnUsername();
-            mUiBot.waitForIdle();
         } else {
-            mActivity.onUsername(View::requestFocus);
+            mUiBot.selectByRelativeId(ID_USERNAME);
         }
+        mUiBot.waitForIdle();
 
         // Sanity check.
         mUiBot.assertNoDatasetsEver();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index 6fd973e..9b17dd4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -211,8 +211,6 @@
     }
 
     private void autofill4PartitionsTest(boolean manually) throws Exception {
-        final int expectedFlag = manually ? FLAG_MANUAL_REQUEST : 0;
-
         // Set service.
         enableService();
 
@@ -233,11 +231,12 @@
         // Trigger auto-fill.
         mActivity.triggerAutofill(manually, 1, 1);
         final FillRequest fillRequest1 = sReplier.getNextFillRequest();
-        assertThat(fillRequest1.flags).isEqualTo(expectedFlag);
 
         if (manually) {
+            assertHasFlags(fillRequest1.flags, FLAG_MANUAL_REQUEST);
             assertValue(fillRequest1.structure, ID_L1C1, "");
         } else {
+            assertThat(fillRequest1.flags).isEqualTo(0);
             assertTextIsSanitized(fillRequest1.structure, ID_L1C1);
         }
         assertTextIsSanitized(fillRequest1.structure, ID_L1C2);
@@ -265,13 +264,14 @@
         // Trigger auto-fill.
         mActivity.triggerAutofill(manually, 2, 1);
         final FillRequest fillRequest2 = sReplier.getNextFillRequest();
-        assertThat(fillRequest2.flags).isEqualTo(expectedFlag);
 
         assertValue(fillRequest2.structure, ID_L1C1, "l1c1");
         assertValue(fillRequest2.structure, ID_L1C2, "l1c2");
         if (manually) {
+            assertHasFlags(fillRequest2.flags, FLAG_MANUAL_REQUEST);
             assertValue(fillRequest2.structure, ID_L2C1, "");
         } else {
+            assertThat(fillRequest2.flags).isEqualTo(0);
             assertTextIsSanitized(fillRequest2.structure, ID_L2C1);
         }
         assertTextIsSanitized(fillRequest2.structure, ID_L2C2);
@@ -299,15 +299,16 @@
         // Trigger auto-fill.
         mActivity.triggerAutofill(manually, 3, 1);
         final FillRequest fillRequest3 = sReplier.getNextFillRequest();
-        assertThat(fillRequest3.flags).isEqualTo(expectedFlag);
 
         assertValue(fillRequest3.structure, ID_L1C1, "l1c1");
         assertValue(fillRequest3.structure, ID_L1C2, "l1c2");
         assertValue(fillRequest3.structure, ID_L2C1, "l2c1");
         assertValue(fillRequest3.structure, ID_L2C2, "l2c2");
         if (manually) {
+            assertHasFlags(fillRequest3.flags, FLAG_MANUAL_REQUEST);
             assertValue(fillRequest3.structure, ID_L3C1, "");
         } else {
+            assertThat(fillRequest3.flags).isEqualTo(0);
             assertTextIsSanitized(fillRequest3.structure, ID_L3C1);
         }
         assertTextIsSanitized(fillRequest3.structure, ID_L3C2);
@@ -335,7 +336,6 @@
         // Trigger auto-fill.
         mActivity.triggerAutofill(manually, 4, 1);
         final FillRequest fillRequest4 = sReplier.getNextFillRequest();
-        assertThat(fillRequest4.flags).isEqualTo(expectedFlag);
 
         assertValue(fillRequest4.structure, ID_L1C1, "l1c1");
         assertValue(fillRequest4.structure, ID_L1C2, "l1c2");
@@ -344,8 +344,10 @@
         assertValue(fillRequest4.structure, ID_L3C1, "l3c1");
         assertValue(fillRequest4.structure, ID_L3C2, "l3c2");
         if (manually) {
+            assertHasFlags(fillRequest4.flags, FLAG_MANUAL_REQUEST);
             assertValue(fillRequest4.structure, ID_L4C1, "");
         } else {
+            assertThat(fillRequest4.flags).isEqualTo(0);
             assertTextIsSanitized(fillRequest4.structure, ID_L4C1);
         }
         assertTextIsSanitized(fillRequest4.structure, ID_L4C2);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
index b84a96e..70f1d86 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Timeouts.java
@@ -29,6 +29,8 @@
     public static final long MOCK_IME_TIMEOUT_MS = 5_000;
     public static final long DRAWABLE_TIMEOUT_MS = 5_000;
 
+    public static final long LONG_PRESS_MS = 3000;
+
     /**
      * Timeout until framework binds / unbinds from service.
      */
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index d904add..0bfceb5 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -17,6 +17,7 @@
 package android.autofillservice.cts;
 
 import static android.autofillservice.cts.Timeouts.DATASET_PICKER_NOT_SHOWN_NAPTIME_MS;
+import static android.autofillservice.cts.Timeouts.LONG_PRESS_MS;
 import static android.autofillservice.cts.Timeouts.SAVE_NOT_SHOWN_NAPTIME_MS;
 import static android.autofillservice.cts.Timeouts.SAVE_TIMEOUT;
 import static android.autofillservice.cts.Timeouts.UI_DATASET_PICKER_TIMEOUT;
@@ -372,6 +373,14 @@
     }
 
     /**
+     * Finds the suggestion by name and perform long click on suggestion to trigger attribution
+     * intent.
+     */
+    public void longPressSuggestion(String name) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
      * Selects a view by text.
      *
      * <p><b>NOTE:</b> when selecting an option in dataset picker is shown, prefer
@@ -826,7 +835,7 @@
     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);
+        field.click(LONG_PRESS_MS);
 
         List<UiObject2> menuItems = waitForObjects(
                 By.res("android", RESOURCE_ID_CONTEXT_MENUITEM), mDefaultTimeout);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedTimeouts.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedTimeouts.java
index 2eef6e3..7bfdfc8 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedTimeouts.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedTimeouts.java
@@ -23,7 +23,7 @@
  */
 final class AugmentedTimeouts {
 
-    private static final long ONE_TIMEOUT_TO_RULE_THEN_ALL_MS = 1_500;
+    private static final long ONE_TIMEOUT_TO_RULE_THEN_ALL_MS = 1_000;
     private static final long ONE_NAPTIME_TO_RULE_THEN_ALL_MS = 3_000;
 
     /**
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java
index be3f1ab..78361f1 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedLoginActivityTest.java
@@ -91,6 +91,42 @@
     }
 
     @Test
+    public void testAugmentedAutoFill_noFiltering() throws Exception {
+        // Set services
+        enableService();
+        enableAugmentedService();
+
+        // Set expectations
+        final EditText username = mActivity.getUsername();
+        final EditText password = mActivity.getPassword();
+        final AutofillId usernameId = username.getAutofillId();
+        final AutofillId passwordId = password.getAutofillId();
+        final AutofillValue usernameValue = username.getAutofillValue();
+        sReplier.addResponse(NO_RESPONSE);
+        sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+                .addInlineSuggestion(new CannedAugmentedFillResponse.Dataset.Builder("Augment Me")
+                        .setField(usernameId, "dude", createInlinePresentation("dude"))
+                        .setField(passwordId, "sweet", createInlinePresentation("sweet"))
+                        .build())
+                .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("req1")
+                        .build(), usernameId)
+                .build());
+
+        // Trigger auto-fill
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdleSync();
+        sReplier.getNextFillRequest();
+        sAugmentedReplier.getNextFillRequest();
+
+        // Assert suggestion
+        mUiBot.assertDatasets("dude");
+
+        // Suggestion was not shown.
+        mActivity.onUsername((v) -> v.setText("d"));
+        mUiBot.assertNoDatasetsEver();
+    }
+
+    @Test
     public void testAugmentedAutoFill_twoDatasetThenFilledSecond() throws Exception {
         // Set services
         enableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
index 108ae74..204bb43 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineLoginActivityTest.java
@@ -27,10 +27,13 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.app.PendingIntent;
 import android.autofillservice.cts.CannedFillResponse;
+import android.autofillservice.cts.DummyActivity;
 import android.autofillservice.cts.Helper;
 import android.autofillservice.cts.InstrumentedAutoFillService;
 import android.autofillservice.cts.LoginActivityCommonTestCase;
+import android.content.Intent;
 import android.service.autofill.FillContext;
 
 import org.junit.Test;
@@ -156,4 +159,43 @@
         assertWithMessage("Password node is focused").that(
                 findNodeByResourceId(request.structure, ID_PASSWORD).isFocused()).isFalse();
     }
+
+    @Test
+    public void testLongClickAttribution() throws Exception {
+        // Set service.
+        enableService();
+
+        Intent intent = new Intent(mContext, DummyActivity.class);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+
+        final CannedFillResponse.Builder builder = new CannedFillResponse.Builder()
+                .addDataset(new CannedFillResponse.CannedDataset.Builder()
+                        .setField(ID_USERNAME, "dude")
+                        .setPresentation(createPresentation("The Username"))
+                        .setInlinePresentation(
+                                createInlinePresentation("The Username", pendingIntent))
+                        .build());
+
+        sReplier.addResponse(builder.build());
+        mActivity.expectAutoFill("dude");
+
+        // Trigger auto-fill.
+        mUiBot.selectByRelativeId(ID_USERNAME);
+        mUiBot.waitForIdleSync();
+
+        mUiBot.assertDatasets("The Username");
+
+        // Long click on suggestion
+        mUiBot.longPressSuggestion("The Username");
+        mUiBot.waitForIdleSync();
+
+        // Make sure the attribution showed worked
+        mUiBot.selectByText("foo");
+
+        // Go back to the filled app.
+        mUiBot.pressBack();
+
+        sReplier.getNextFillRequest();
+        mUiBot.waitForIdleSync();
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java
index 1d1803a..463fd7b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineUiBot.java
@@ -17,6 +17,7 @@
 package android.autofillservice.cts.inline;
 
 import static android.autofillservice.cts.Timeouts.DATASET_PICKER_NOT_SHOWN_NAPTIME_MS;
+import static android.autofillservice.cts.Timeouts.LONG_PRESS_MS;
 import static android.autofillservice.cts.Timeouts.UI_TIMEOUT;
 
 import android.autofillservice.cts.UiBot;
@@ -74,6 +75,16 @@
     }
 
     @Override
+    public void longPressSuggestion(String name) throws Exception {
+        final UiObject2 strip = findSuggestionStrip(UI_TIMEOUT);
+        final UiObject2 dataset = strip.findObject(By.text(name));
+        if (dataset == null) {
+            throw new AssertionError("no dataset " + name + " in " + getChildrenAsText(strip));
+        }
+        dataset.click(LONG_PRESS_MS);
+    }
+
+    @Override
     public UiObject2 assertDatasets(String...names) throws Exception {
         final UiObject2 picker = findSuggestionStrip(UI_TIMEOUT);
         return assertDatasets(picker, names);
diff --git a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
index afd2beb..4a88c84 100644
--- a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
@@ -88,11 +88,12 @@
 
     private static final double NS_PER_MS = 1000000.0;
     private static final int MAX_IMAGE_COUNT = 3;
-    private static final int NUM_FRAMES_CHECKED = 30;
+    private static final int NUM_FRAMES_CHECKED = 300;
 
     private static final double FRAME_DURATION_THRESHOLD = 0.03;
     private static final double FOV_THRESHOLD = 0.03;
     private static final double ASPECT_RATIO_THRESHOLD = 0.03;
+    private static final long MAX_TIMESTAMP_DIFFERENCE_THRESHOLD = 10000000; // 10ms
 
     private StateWaiter mSessionWaiter;
 
@@ -1221,15 +1222,43 @@
                 }
             }
         }
+
         double logicalAvgDurationMs2 = (logicalTimestamps2[NUM_FRAMES_CHECKED-1] -
                 logicalTimestamps2[0])/(NS_PER_MS*(NUM_FRAMES_CHECKED-1));
-
-        // Check framerate slow down with physical streams, but do not enforce.
+        // Check CALIBRATED synchronization between physical cameras
+        Integer syncType = mStaticInfo.getCharacteristics().get(
+                CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE);
         double fpsRatio = (logicalAvgDurationMs2 - logicalAvgDurationMs)/logicalAvgDurationMs;
-        if (fpsRatio > FRAME_DURATION_THRESHOLD) {
-            Log.w(TAG, "The average frame duration with concurrent physical streams is" +
-                logicalAvgDurationMs2 + " ms vs " + logicalAvgDurationMs +
-                " ms for logical streams only");
+        if (syncType == CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED) {
+            // Check framerate doesn't slow down with physical streams
+            mCollector.expectTrue(
+                    "The average frame duration with concurrent physical streams is" +
+                    logicalAvgDurationMs2 + " ms vs " + logicalAvgDurationMs +
+                    " ms for logical streams only", fpsRatio <= FRAME_DURATION_THRESHOLD);
+
+            long maxTimestampDelta = 0;
+            for (int i = 0; i < NUM_FRAMES_CHECKED; i++) {
+                long delta = Math.abs(physicalTimestamps[0][i] - physicalTimestamps[1][i]);
+                if (delta > maxTimestampDelta) {
+                    maxTimestampDelta = delta;
+                }
+            }
+
+            Log.i(TAG, "Maximum difference between physical camera timestamps: "
+                    + maxTimestampDelta);
+
+            // The maximum timestamp difference should not be larger than the threshold.
+            mCollector.expectTrue(
+                    "The maximum timestamp deltas between the physical cameras "
+                    + maxTimestampDelta + " is larger than " + MAX_TIMESTAMP_DIFFERENCE_THRESHOLD,
+                    maxTimestampDelta <= MAX_TIMESTAMP_DIFFERENCE_THRESHOLD);
+        } else {
+            // Do not enforce fps check for APPROXIMATE synced device.
+            if (fpsRatio > FRAME_DURATION_THRESHOLD) {
+                Log.w(TAG, "The average frame duration with concurrent physical streams is" +
+                        logicalAvgDurationMs2 + " ms vs " + logicalAvgDurationMs +
+                        " ms for logical streams only");
+            }
         }
 
         if (VERBOSE) {
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index c0d01b2..fe642c3 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -100,6 +100,10 @@
                   android:resizeableActivity="true"
                   android:taskAffinity="nobody.but.SideActivity"/>
 
+        <activity android:name="android.server.wm.ActivityManagerTestBase$ConfigChangeHandlingActivity"
+            android:resizeableActivity="true"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen" />
+
         <activity android:name="android.server.wm.lifecycle.ActivityLifecycleClientTestBase$FirstActivity" />
 
         <activity android:name="android.server.wm.lifecycle.ActivityLifecycleClientTestBase$SecondActivity"/>
@@ -406,7 +410,7 @@
         <activity android:name="android.server.wm.StartActivityAsUserActivity"
                   android:directBootAware="true"/>
 
-        <activity android:name="android.server.wm.WindowInsetsAnimationTests$TestActivity"
+        <activity android:name="android.server.wm.WindowInsetsAnimationTestBase$TestActivity"
                   android:theme="@android:style/Theme.Material.NoActionBar" />
 
         <activity android:name="android.server.wm.ForceRelayoutTestBase$TestActivity"
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 8d2f216..f1423f0 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
@@ -297,6 +297,12 @@
         public static final String EXTRA_CUTOUT_EXISTS = "cutoutExists";
     }
 
+    /** Extra key constants for {@link android.server.wm.app.LandscapeOrientationActivity}. */
+    public static class LandscapeOrientationActivity {
+        public static final String EXTRA_CONFIG_INFO_IN_ON_CREATE = "config_info_in_on_create";
+        public static final String EXTRA_DISPLAY_REAL_SIZE = "display_real_size";
+    }
+
     /** Extra key constants for {@link android.server.wm.app.FontScaleActivity}. */
     public static class FontScaleActivity {
         public static final String EXTRA_FONT_PIXEL_SIZE = "fontPixelSize";
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java
index 5eb30d5..00984fa 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/LandscapeOrientationActivity.java
@@ -16,11 +16,35 @@
 
 package android.server.wm.app;
 
+import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_CONFIG_INFO_IN_ON_CREATE;
+import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_DISPLAY_REAL_SIZE;
+
 import android.content.res.Configuration;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.server.wm.CommandSession.ConfigInfo;
+import android.view.Display;
 
 public class LandscapeOrientationActivity extends AbstractLifecycleLogActivity {
 
     @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (!getIntent().hasExtra(EXTRA_CONFIG_INFO_IN_ON_CREATE)) {
+            return;
+        }
+        withTestJournalClient(client -> {
+            final Bundle extras = new Bundle();
+            final Display display = getDisplay();
+            final Point size = new Point();
+            display.getRealSize(size);
+            extras.putParcelable(EXTRA_CONFIG_INFO_IN_ON_CREATE, new ConfigInfo(this, display));
+            extras.putParcelable(EXTRA_DISPLAY_REAL_SIZE, size);
+            client.putExtras(extras);
+        });
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
         dumpConfigInfo();
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 19ba5c0..8bff8c4 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
@@ -69,6 +69,7 @@
 
 import java.util.List;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Stream;
 
 /**
  * This class covers all test cases for starting/blocking background activities.
@@ -212,28 +213,26 @@
     }
 
     @Test
-    public void testActivityNotBlockedwhenForegroundActivityLaunchInSameTask() throws Exception {
+    public void testActivityBroughtToTopOfTaskWhenLaunchedInTheBackground() throws Exception {
         // Start foreground activity, and foreground activity able to launch background activity
         // successfully
         Intent intent = new Intent();
         intent.setComponent(APP_A_FOREGROUND_ACTIVITY);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.putExtra(LAUNCH_BACKGROUND_ACTIVITY_EXTRA, true);
-        intent.putExtra(START_ACTIVITY_FROM_FG_ACTIVITY_DELAY_MS_EXTRA, 2000);
         mContext.startActivity(intent);
         boolean result = waitForActivityFocused(ACTIVITY_FOCUS_TIMEOUT_MS,
                 APP_A_FOREGROUND_ACTIVITY);
         assertTrue("Not able to launch background activity", result);
         assertTaskStack(new ComponentName[]{APP_A_FOREGROUND_ACTIVITY}, APP_A_FOREGROUND_ACTIVITY);
-
-        // The foreground activity will be paused but will attempt to restart itself in onPause()
         pressHomeAndResumeAppSwitch();
 
+        mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_A_BACKGROUND_ACTIVITY));
+
         result = waitForActivityFocused(APP_A_FOREGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
         assertFalse("Previously foreground Activity should not be able to relaunch itself", result);
-        assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY},
+        assertTaskStack(new ComponentName[] {APP_A_BACKGROUND_ACTIVITY, APP_A_FOREGROUND_ACTIVITY},
                 APP_A_FOREGROUND_ACTIVITY);
     }
 
@@ -322,13 +321,8 @@
 
         // 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);
+        mContext.sendBroadcast(getLaunchActivitiesBroadcast(APP_A_BACKGROUND_ACTIVITY,
+                APP_A_SECOND_BACKGROUND_ACTIVITY));
 
         // There should be 2 activities in the background (not focused) INITIALIZING
         result = waitForActivityFocused(APP_A_BACKGROUND_ACTIVITY);
@@ -450,16 +444,32 @@
         assertTaskStack(new ComponentName[]{APP_A_BACKGROUND_ACTIVITY}, APP_A_BACKGROUND_ACTIVITY);
     }
 
+    private Intent getLaunchActivitiesBroadcast(ComponentName... componentNames) {
+        Intent broadcastIntent = new Intent(ACTION_LAUNCH_BACKGROUND_ACTIVITIES);
+        Intent[] intents = Stream.of(componentNames)
+                .map(c -> {
+                    Intent intent = new Intent();
+                    intent.setComponent(c);
+                    return intent;
+                })
+                .toArray(Intent[]::new);
+        broadcastIntent.putExtra(LAUNCH_INTENTS_EXTRA, intents);
+        return broadcastIntent;
+    }
+
     private void pressHomeAndResumeAppSwitch() {
         // Press home key to ensure stopAppSwitches is called because the last-stop-app-switch-time
         // is a criteria of allowing background start.
         pressHomeButton();
-        // Waiting for home visible before resuming app switches to make sure the part that sets the
-        // stop-app-switches time from pressHomeButton() doesn't race with resumeAppSwitches()
-        mWmState.waitForHomeActivityVisible();
         // Resume the stopped state (it won't affect last-stop-app-switch-time) so we don't need to
         // wait extra time to prevent the next launch from being delayed.
         resumeAppSwitches();
+        mWmState.waitForHomeActivityVisible();
+        // Resuming app switches again after home became visible because the previous call might
+        // have raced with pressHomeButton().
+        // TODO(b/155454710): Remove previous call after making sure all the tests don't depend on
+        // the timing here.
+        resumeAppSwitches();
     }
 
     private void assertTaskStack(ComponentName[] expectedComponents,
diff --git a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
index a664f0b..25e12ab 100644
--- a/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/jetpack/AndroidManifest.xml
@@ -29,6 +29,7 @@
         <activity android:name="android.server.wm.jetpack.TestConfigChangeHandlingActivity"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
         />
+        <activity android:name="android.server.wm.jetpack.TestGetWindowLayoutInfoActivity" />
     </application>
 
     <!--  self-instrumenting test package. -->
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
index 4e67f8a..7b9bcf6 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionTest.java
@@ -62,14 +62,18 @@
     private ActivityTestRule<TestConfigChangeHandlingActivity> mConfigHandlingActivityTestRule =
             new ActivityTestRule<>(TestConfigChangeHandlingActivity.class,
                     false /* initialTouchMode */, false /* launchActivity */);
+    private ActivityTestRule<TestGetWindowLayoutInfoActivity> mGetWindowLayoutInfoActivityTestRule =
+            new ActivityTestRule<>(TestGetWindowLayoutInfoActivity.class,
+                    false /* initialTouchMode */, false /* launchActivity */);
 
     /**
-     * This chain rule will launch TestActivity before each test starts, and cleanup both activities
+     * This chain rule will launch TestActivity before each test starts, and cleanup all activities
      * after each test finishes.
      */
     @Rule
-    public TestRule chain =
-            RuleChain.outerRule(mActivityTestRule).around(mConfigHandlingActivityTestRule);
+    public TestRule chain = RuleChain.outerRule(mActivityTestRule)
+            .around(mConfigHandlingActivityTestRule)
+            .around(mGetWindowLayoutInfoActivityTestRule);
 
     private TestActivity mActivity;
     private TestInterfaceCompat mExtension;
@@ -165,6 +169,21 @@
     }
 
     @Test
+    public void testGetWindowLayoutInfo_activityNotAttached_notReturnIncorrectValue() {
+        // No display feature to compare, finish test early.
+        assumeHasDisplayFeatures();
+
+        // The value is verified inside TestGetWindowLayoutInfoActivity
+        TestGetWindowLayoutInfoActivity.resetResumeCounter();
+        TestGetWindowLayoutInfoActivity testGetWindowLayoutInfoActivity =
+                mGetWindowLayoutInfoActivityTestRule.launchActivity(new Intent());
+
+        // Make sure the activity has gone through all states.
+        assertThat(TestGetWindowLayoutInfoActivity.waitForOnResume()).isTrue();
+        assertThat(testGetWindowLayoutInfoActivity.waitForLayout()).isTrue();
+    }
+
+    @Test
     public void testGetWindowLayoutInfo_configChanged_windowLayoutUpdates() {
         // No display feature to compare, finish test early.
         assumeHasDisplayFeatures();
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestGetWindowLayoutInfoActivity.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestGetWindowLayoutInfoActivity.java
new file mode 100644
index 0000000..e9f6c66
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/TestGetWindowLayoutInfoActivity.java
@@ -0,0 +1,91 @@
+/*
+ * 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.server.wm.jetpack;
+
+import static android.server.wm.jetpack.JetpackExtensionTestBase.getActivityWindowToken;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.server.wm.jetpack.wrapper.TestInterfaceCompat;
+import android.server.wm.jetpack.wrapper.TestWindowLayoutInfo;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Activity that can verify the return value of
+ * {@link android.server.wm.jetpack.wrapper.TestInterfaceCompat#getWindowLayoutInfo(IBinder)} on
+ * activity's different states.
+ */
+public class TestGetWindowLayoutInfoActivity extends TestActivity {
+
+    private TestInterfaceCompat mExtension;
+    @Nullable private TestWindowLayoutInfo prevWindowLayoutInfo;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mExtension = ExtensionUtils.getInterfaceCompat(this);
+        assertCorrectWindowLayoutInfoOrException(true /* isOkToThrowException */);
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        assertCorrectWindowLayoutInfoOrException(true /* isOkToThrowException */);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        assertCorrectWindowLayoutInfoOrException(true /* isOkToThrowException */);
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
+        assertCorrectWindowLayoutInfoOrException(false /* isOkToThrowException */);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    private void assertCorrectWindowLayoutInfoOrException(boolean isOkToThrowException) {
+        IBinder windowToken = getActivityWindowToken(this);
+        if (windowToken == null) {
+            return;
+        }
+
+        TestWindowLayoutInfo windowLayoutInfo = null;
+        try {
+            windowLayoutInfo = mExtension.getWindowLayoutInfo(windowToken);
+        } catch (Exception e) {
+            assertThat(isOkToThrowException).isTrue();
+        }
+
+        if (prevWindowLayoutInfo == null) {
+            prevWindowLayoutInfo = windowLayoutInfo;
+        } else {
+            assertThat(windowLayoutInfo).isEqualTo(prevWindowLayoutInfo);
+        }
+    }
+}
\ 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 868187c..c898ef6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -23,6 +23,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.server.wm.ComponentNameUtils.getWindowName;
 import static android.server.wm.StateLogger.logE;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
@@ -35,6 +37,8 @@
 import static android.server.wm.app.Components.PORTRAIT_ORIENTATION_ACTIVITY;
 import static android.server.wm.app.Components.RESIZEABLE_ACTIVITY;
 import static android.server.wm.app.Components.TEST_ACTIVITY;
+import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_CONFIG_INFO_IN_ON_CREATE;
+import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_DISPLAY_REAL_SIZE;
 import static android.server.wm.translucentapp26.Components.SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
@@ -53,11 +57,19 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.content.ComponentName;
-import android.content.res.Configuration;
+import android.content.Context;
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
 import android.server.wm.CommandSession.ActivitySession;
+import android.server.wm.CommandSession.ConfigInfo;
 import android.server.wm.CommandSession.SizeInfo;
+import android.server.wm.TestJournalProvider.TestJournalContainer;
+import android.server.wm.settings.SettingsSession;
+import android.view.Display;
 
 import org.junit.Test;
 
@@ -68,7 +80,7 @@
  *     atest CtsWindowManagerDeviceTestCases:AppConfigurationTests
  */
 @Presubmit
-public class AppConfigurationTests extends ActivityManagerTestBase {
+public class AppConfigurationTests extends MultiDisplayTestBase {
 
     private static final int SMALL_WIDTH_DP = 426;
     private static final int SMALL_HEIGHT_DP = 320;
@@ -311,21 +323,21 @@
         mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */);
         SizeInfo reportedSizes = getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         assertEquals("portrait activity should be in portrait",
-                Configuration.ORIENTATION_PORTRAIT, reportedSizes.orientation);
+                ORIENTATION_PORTRAIT, reportedSizes.orientation);
         separateTestJournal();
 
         launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY);
         mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */);
         reportedSizes = getLastReportedSizesForActivity(LANDSCAPE_ORIENTATION_ACTIVITY);
         assertEquals("landscape activity should be in landscape",
-                Configuration.ORIENTATION_LANDSCAPE, reportedSizes.orientation);
+                ORIENTATION_LANDSCAPE, reportedSizes.orientation);
         separateTestJournal();
 
         launchActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */);
         reportedSizes = getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         assertEquals("portrait activity should be in portrait",
-                Configuration.ORIENTATION_PORTRAIT, reportedSizes.orientation);
+                ORIENTATION_PORTRAIT, reportedSizes.orientation);
     }
 
     @Test
@@ -337,7 +349,7 @@
         final SizeInfo initialReportedSizes =
                 getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY);
         assertEquals("portrait activity should be in portrait",
-                Configuration.ORIENTATION_PORTRAIT, initialReportedSizes.orientation);
+                ORIENTATION_PORTRAIT, initialReportedSizes.orientation);
         separateTestJournal();
 
         launchActivity(SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY, WINDOWING_MODE_FULLSCREEN);
@@ -407,9 +419,9 @@
 
         // Launch an activity that requests different orientation and check that it will be applied
         final boolean launchingPortrait;
-        if (initialOrientation == Configuration.ORIENTATION_LANDSCAPE) {
+        if (initialOrientation == ORIENTATION_LANDSCAPE) {
             launchingPortrait = true;
-        } else if (initialOrientation == Configuration.ORIENTATION_PORTRAIT) {
+        } else if (initialOrientation == ORIENTATION_PORTRAIT) {
             launchingPortrait = false;
         } else {
             fail("Unexpected orientation value: " + initialOrientation);
@@ -436,6 +448,46 @@
     }
 
     @Test
+    public void testRotatedInfoWithFixedRotationTransform() {
+        assumeTrue("Skipping test: no rotation support", supportsRotation());
+
+        // TODO(b/143053092): Remove the settings if it becomes stable.
+        mObjectTracker.manage(new SettingsSession<>(
+                Settings.Global.getUriFor("fixed_rotation_transform"),
+                Settings.Global::getInt, Settings.Global::putInt)).set(1);
+
+        getLaunchActivityBuilder()
+                .setUseInstrumentation()
+                .setTargetActivity(LANDSCAPE_ORIENTATION_ACTIVITY)
+                // Request the info from onCreate because at that moment the real display hasn't
+                // rotated but the activity is rotated.
+                .setIntentExtra(bundle -> bundle.putBoolean(EXTRA_CONFIG_INFO_IN_ON_CREATE, true))
+                .execute();
+        mWmState.waitForLastOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+        final SizeInfo reportedSizes = getActivityDisplaySize(LANDSCAPE_ORIENTATION_ACTIVITY);
+        final Bundle extras = TestJournalContainer.get(LANDSCAPE_ORIENTATION_ACTIVITY).extras;
+        final Point onCreateRealDisplaySize = extras.getParcelable(EXTRA_DISPLAY_REAL_SIZE);
+        final ConfigInfo onCreateConfigInfo = extras.getParcelable(EXTRA_CONFIG_INFO_IN_ON_CREATE);
+        final SizeInfo onCreateSize = onCreateConfigInfo.sizeInfo;
+
+        assertEquals("The last reported size should be the same as the one from onCreate",
+                reportedSizes, onCreateConfigInfo.sizeInfo);
+
+        final Display display = mDm.getDisplay(Display.DEFAULT_DISPLAY);
+        final Point expectedRealDisplaySize = new Point();
+        display.getRealSize(expectedRealDisplaySize);
+
+        assertEquals("The activity should get the final display rotation in onCreate",
+                display.getRotation(), onCreateConfigInfo.rotation);
+        assertEquals("The activity should get the final display size in onCreate",
+                expectedRealDisplaySize, onCreateRealDisplaySize);
+        assertEquals("The app size of activity should have the same orientation",
+                expectedRealDisplaySize.x > expectedRealDisplaySize.y,
+                onCreateSize.displayWidth > onCreateSize.displayHeight);
+    }
+
+    @Test
     public void testNonFullscreenActivityPermitted() throws Exception {
         if(!supportsRotation()) {
             //cannot physically rotate the screen on automotive device, skip
@@ -472,7 +524,7 @@
         // Request portrait
         mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_PORTRAIT);
         mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT);
-        waitForBroadcastActivityReady(Configuration.ORIENTATION_PORTRAIT);
+        waitForBroadcastActivityReady(ORIENTATION_PORTRAIT);
 
         // Finish activity
         mBroadcastActionTrigger.finishBroadcastReceiverActivity();
@@ -503,7 +555,7 @@
         launchActivityInNewTask(BROADCAST_RECEIVER_ACTIVITY);
         mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_LANDSCAPE);
         mWmState.waitForLastOrientation(SCREEN_ORIENTATION_LANDSCAPE);
-        waitForBroadcastActivityReady(Configuration.ORIENTATION_LANDSCAPE);
+        waitForBroadcastActivityReady(ORIENTATION_LANDSCAPE);
         mBroadcastActionTrigger.finishBroadcastReceiverActivity();
 
         // Verify that activity brought to front is in originally requested orientation.
@@ -520,7 +572,7 @@
         launchActivityInNewTask(BROADCAST_RECEIVER_ACTIVITY);
         mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_PORTRAIT);
         mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT);
-        waitForBroadcastActivityReady(Configuration.ORIENTATION_PORTRAIT);
+        waitForBroadcastActivityReady(ORIENTATION_PORTRAIT);
         mBroadcastActionTrigger.finishBroadcastReceiverActivity();
 
         // Verify that activity brought to front is in originally requested orientation.
@@ -577,6 +629,52 @@
     }
 
     /**
+     * Test that the orientation for a simulated display context will not change when the device is
+     * rotated.
+     */
+    @Test
+    public void testAppContextDerivedDisplayContextOrientationWhenRotating() {
+        assumeTrue("Skipping test: no rotation support", supportsRotation());
+        assumeTrue("Skipping test: no multi-display support", supportsMultiDisplay());
+
+        RotationSession rotationSession = createManagedRotationSession();
+        rotationSession.set(ROTATION_0);
+
+        TestActivitySession<ConfigChangeHandlingActivity> activitySession
+                = createManagedTestActivitySession();
+        activitySession.launchTestActivityOnDisplaySync(ConfigChangeHandlingActivity.class,
+                Display.DEFAULT_DISPLAY);
+        final ConfigChangeHandlingActivity activity = activitySession.getActivity();
+
+        VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
+        WindowManagerState.DisplayContent displayContent = virtualDisplaySession
+                .setSimulateDisplay(true)
+                .setSimulationDisplaySize(100 /* width */, 200 /* height */)
+                .createDisplay();
+
+        DisplayManager dm = activity.getSystemService(DisplayManager.class);
+        Display simulatedDisplay = dm.getDisplay(displayContent.mId);
+        Context simulatedDisplayContext = activity.getApplicationContext()
+                .createDisplayContext(simulatedDisplay);
+        assertEquals(ORIENTATION_PORTRAIT,
+                simulatedDisplayContext.getResources().getConfiguration().orientation);
+
+        separateTestJournal();
+
+        final int[] rotations = {ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0};
+        for (final int rotation : rotations) {
+            rotationSession.set(rotation);
+
+            assertRelaunchOrConfigChanged(activity.getComponentName(), 0 /* numRelaunch */,
+                    1 /* numConfigChange */);
+            separateTestJournal();
+
+            assertEquals("Display context orientation must not be changed", ORIENTATION_PORTRAIT,
+                    simulatedDisplayContext.getResources().getConfiguration().orientation);
+        }
+    }
+
+    /**
      * Test that activity orientation will not change when trying to rotate fixed-orientation
      * activity.
      * Also verify that occluded activity will not get config changes.
@@ -639,7 +737,7 @@
         // Request portrait
         mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_PORTRAIT);
         mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT);
-        waitForBroadcastActivityReady(Configuration.ORIENTATION_PORTRAIT);
+        waitForBroadcastActivityReady(ORIENTATION_PORTRAIT);
 
         // Finish activity
         mBroadcastActionTrigger.moveTopTaskToBack();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
index 8a5d21c..4336898 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CrossAppDragAndDropTests.java
@@ -31,7 +31,6 @@
 import android.content.ComponentName;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
 import android.os.SystemClock;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.Presubmit;
@@ -93,8 +92,6 @@
     private static final String EXTRA_MODE = "mode";
     private static final String EXTRA_LOGTAG = "logtag";
 
-    protected DisplayManager mDm;
-
     private Map<String, String> mSourceResults;
     private Map<String, String> mTargetResults;
 
@@ -113,7 +110,6 @@
         mSourceLogTag = SOURCE_LOG_TAG + mSessionId;
         mTargetLogTag = TARGET_LOG_TAG + mSessionId;
 
-        mDm = mContext.getSystemService(DisplayManager.class);
         cleanupState();
         mUseTaskOrganizer = false;
     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
index 45acc41..48a01d3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayCutoutTests.java
@@ -46,9 +46,11 @@
 import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.Activity;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -232,6 +234,7 @@
     }
 
     private void runTest(int cutoutMode, TestDef test, int orientation) {
+        assumeTrue("Skipping test: orientation not supported", supportsOrientation(orientation));
         final TestActivity activity = launchAndWait(mDisplayCutoutActivity,
                 cutoutMode, orientation);
 
@@ -508,6 +511,25 @@
         return activity;
     }
 
+    private boolean supportsOrientation(int orientation) {
+        String systemFeature = "";
+        switch(orientation) {
+            case SCREEN_ORIENTATION_PORTRAIT:
+            case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+                systemFeature = PackageManager.FEATURE_SCREEN_PORTRAIT;
+                break;
+            case SCREEN_ORIENTATION_LANDSCAPE:
+            case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+                systemFeature = PackageManager.FEATURE_SCREEN_LANDSCAPE;
+                break;
+            default:
+                throw new UnsupportedOperationException("Orientation not supported");
+        }
+
+        return getInstrumentation().getTargetContext().getPackageManager()
+                .hasSystemFeature(systemFeature);
+    }
+
     public static class TestActivity extends Activity {
 
         static final String EXTRA_CUTOUT_MODE = "extra.cutout_mode";
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplaySizeTest.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplaySizeTest.java
index 1ef4920..667ed05 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplaySizeTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplaySizeTest.java
@@ -107,7 +107,7 @@
         try {
             final int initialLength = 500;
             final int newLength = 1000;
-            final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+            final DisplayManager displayManager = mDm;
             virtualDisplay = displayManager.createVirtualDisplay("CtsDisplay", initialLength,
                     initialLength, 160 /* densityDpi */, null /* surface */, 0 /* flags */);
             final Display targetDisplay = virtualDisplay.getDisplay();
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 a72a299..6ad0dc1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayTests.java
@@ -178,15 +178,13 @@
     private Configuration getDisplayResourcesConfiguration(int displayWidth, int displayHeight)
             throws Exception  {
         final Context context = getInstrumentation().getContext();
-        final DisplayManager displayManager =
-                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
 
         try (final VirtualDisplaySession virtualDisplaySession = new VirtualDisplaySession()) {
             final DisplayContent displayContent = virtualDisplaySession
                     .setSimulateDisplay(true)
                     .setSimulationDisplaySize(displayWidth, displayHeight)
                     .createDisplay();
-            final Display display = displayManager.getDisplay(displayContent.mId);
+            final Display display = mDm.getDisplay(displayContent.mId);
             Configuration config = context.createDisplayContext(display)
                     .getResources().getConfiguration();
             return config;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java
index 1c9f174..74b3c7b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MinimalPostProcessingTests.java
@@ -27,11 +27,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.ComponentName;
-import android.hardware.display.DisplayManager;
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.filters.FlakyTest;
-
 import org.junit.Test;
 
 @Presubmit
@@ -55,14 +52,11 @@
     }
 
     private boolean isMinimalPostProcessingSupported(int displayId) {
-        return mContext.getSystemService(DisplayManager.class)
-                .getDisplay(displayId)
-                .isMinimalPostProcessingSupported();
+        return mDm.getDisplay(displayId).isMinimalPostProcessingSupported();
     }
 
     private boolean isMinimalPostProcessingRequested(int displayId) {
-        return mContext.getSystemService(DisplayManager.class)
-                .isMinimalPostProcessingRequested(displayId);
+        return mDm.isMinimalPostProcessingRequested(displayId);
     }
 
     private int getDisplayId(ComponentName name) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
index 1a6f665..44bd353 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayActivityLaunchTests.java
@@ -26,7 +26,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.server.wm.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
 import static android.server.wm.ActivityLauncher.KEY_NEW_TASK;
-import static android.server.wm.ActivityLauncher.KEY_TARGET_COMPONENT;
 import static android.server.wm.ComponentNameUtils.getActivityName;
 import static android.server.wm.UiDeviceUtils.pressHomeButton;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
@@ -69,7 +68,6 @@
 import android.server.wm.CommandSession.SizeInfo;
 import android.server.wm.WindowManagerState.ActivityTask;
 import android.server.wm.WindowManagerState.DisplayContent;
-import android.util.DisplayMetrics;
 import android.view.SurfaceView;
 
 import com.android.compatibility.common.util.SystemUtil;
@@ -772,9 +770,8 @@
     @Test
     public void testImmediateLaunchOnNewDisplay() {
         // Create new virtual display and immediately launch an activity on it.
-        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
         SurfaceView surfaceView = new SurfaceView(mContext);
-        VirtualDisplay virtualDisplay = displayManager.createVirtualDisplay(
+        final VirtualDisplay virtualDisplay = mDm.createVirtualDisplay(
                 "testImmediateLaunchOnNewDisplay", /*width=*/ 400, /*height=*/ 400,
                 /*densityDpi=*/ 320, surfaceView.getHolder().getSurface(),
                 DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
@@ -836,8 +833,6 @@
 
     @Test
     public void testLaunchPendingIntentActivity() throws Exception {
-        final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
-
         final DisplayContent displayContent = createManagedVirtualDisplaySession()
                 .setSimulateDisplay(true)
                 .createDisplay();
@@ -850,7 +845,7 @@
         final int resultCode = 1;
         // Activity should be launched on target display according to the caller context.
         final Context displayContext =
-                mContext.createDisplayContext(displayManager.getDisplay(displayContent.mId));
+                mContext.createDisplayContext(mDm.getDisplay(displayContent.mId));
         getPendingIntentActivity(TOP_ACTIVITY).send(displayContext, resultCode, null /* intent */);
         waitAndAssertTopResumedActivity(TOP_ACTIVITY, displayContent.mId,
                 "Activity launched on secondary display and on top");
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
index e9a889d..caf44c9 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
@@ -37,7 +37,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.WindowManagerState.DisplayContent;
@@ -199,8 +198,7 @@
                 .setSimulateDisplay(true)
                 .createDisplay();
 
-        final Display display = mContext.getSystemService(DisplayManager.class)
-                .getDisplay(newDisplay.mId);
+        final Display display = mDm.getDisplay(newDisplay.mId);
         final Context newDisplayContext = mContext.createDisplayContext(display);
         final InputMethodManager imm = newDisplayContext.getSystemService(InputMethodManager.class);
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
index 7f14db4..efe194f 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
@@ -60,7 +60,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.WindowManagerState.DisplayContent;
@@ -440,8 +439,7 @@
                 .setPublicDisplay(false)
                 .createDisplay();
         try {
-            final Display display = mContext.getSystemService(DisplayManager.class).getDisplay(
-                    newDisplay.mId);
+            final Display display = mDm.getDisplay(newDisplay.mId);
             final Context newDisplayContext = mContext.createDisplayContext(display);
             newDisplayContext.getSystemService(WindowManager.class).addView(new View(mContext),
                     new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index c50f5d5..be945d6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -203,8 +203,8 @@
     @Test
     public void testNavBarShowingOnDisplayWithDecor() {
         assumeHasBars();
-        final DisplayContent newDisplay = createManagedExternalDisplaySession()
-                .setPublicDisplay(true).setShowSystemDecorations(true).createVirtualDisplay();
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
+                .setSimulateDisplay(true).setShowSystemDecorations(true).createDisplay();
 
         mWmState.waitAndAssertNavBarShownOnDisplay(newDisplay.mId);
     }
@@ -219,8 +219,8 @@
         mWmState.waitForHomeActivityVisible();
         final List<WindowState> expected = mWmState.getAllNavigationBarStates();
 
-        createManagedExternalDisplaySession().setPublicDisplay(true)
-                .setShowSystemDecorations(false).createVirtualDisplay();
+        createManagedVirtualDisplaySession().setSimulateDisplay(true)
+                .setShowSystemDecorations(false).createDisplay();
 
         waitAndAssertNavBarStatesAreTheSame(expected);
     }
@@ -251,9 +251,9 @@
         // display, go back to verify whether the nav bar states are unchanged to verify that no nav
         // bars were added to a display that was added before executing this method that shouldn't
         // have nav bars (i.e. private or without system ui decor).
-        try (final ExternalDisplaySession secondDisplaySession = new ExternalDisplaySession()) {
+        try (final VirtualDisplaySession secondDisplaySession = new VirtualDisplaySession()) {
             final DisplayContent supportsSysDecorDisplay = secondDisplaySession
-                    .setPublicDisplay(true).setShowSystemDecorations(true).createVirtualDisplay();
+                    .setSimulateDisplay(true).setShowSystemDecorations(true).createDisplay();
             mWmState.waitAndAssertNavBarShownOnDisplay(supportsSysDecorDisplay.mId);
             // This display has finished his task. Just close it.
         }
@@ -287,6 +287,19 @@
         assertEquals("No stacks on newly launched virtual display", 0, newDisplay.mRootTasks.size());
     }
 
+    /** Tests launching a home activity on untrusted virtual display. */
+    @Test
+    public void testLaunchHomeActivityOnUntrustedVirtualSecondaryDisplay() {
+        createManagedHomeActivitySession(SECONDARY_HOME_ACTIVITY);
+
+        // Create new virtual display with system decoration support flag.
+        final DisplayContent newDisplay = createManagedExternalDisplaySession()
+                .setPublicDisplay(true).setShowSystemDecorations(true).createVirtualDisplay();
+
+        // Secondary home activity can't be launched on the untrusted virtual display.
+        assertEquals("No stacks on untrusted virtual display", 0, newDisplay.mRootTasks.size());
+    }
+
     /**
      * Tests launching a single instance home activity on virtual display with system decoration
      * support.
@@ -339,10 +352,11 @@
     }
 
     private void assertSecondaryHomeResumedOnNewDisplay(ComponentName homeComponentName) {
-        // Create new virtual display with system decoration support.
-        final DisplayContent newDisplay = createManagedExternalDisplaySession()
+        // Create new simulated display with system decoration support.
+        final DisplayContent newDisplay = createManagedVirtualDisplaySession()
+                .setSimulateDisplay(true)
                 .setShowSystemDecorations(true)
-                .createVirtualDisplay();
+                .createDisplay();
 
         waitAndAssertActivityStateOnDisplay(homeComponentName, STATE_RESUMED,
                 newDisplay.mId, "Activity launched on secondary display must be resumed");
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 dbaedc1..6f97aa6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
@@ -83,6 +83,7 @@
  * @see DisplayTests
  * @see MultiDisplayKeyguardTests
  * @see MultiDisplayLockedKeyguardTests
+ * @see AppConfigurationTests
  */
 public class MultiDisplayTestBase extends ActivityManagerTestBase {
 
@@ -777,6 +778,12 @@
             return this;
         }
 
+        /**
+         * @deprecated untrusted virtual display won't have system decorations even it has the flag.
+         * Only use this method to verify that. To test secondary display with system decorations,
+         * please use simulated display.
+         */
+        @Deprecated
         ExternalDisplaySession setShowSystemDecorations(boolean showSystemDecorations) {
             mShowSystemDecorations = showSystemDecorations;
             return this;
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 feb8947..ab3d71a 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -26,6 +26,7 @@
 import static android.server.wm.ComponentNameUtils.getActivityName;
 import static android.server.wm.ComponentNameUtils.getWindowName;
 import static android.server.wm.UiDeviceUtils.pressWindowButton;
+import static android.server.wm.WindowManagerState.STATE_PAUSED;
 import static android.server.wm.WindowManagerState.STATE_RESUMED;
 import static android.server.wm.WindowManagerState.STATE_STOPPED;
 import static android.server.wm.app.Components.ALWAYS_FOCUSABLE_PIP_ACTIVITY;
@@ -97,6 +98,8 @@
 import android.util.Log;
 import android.util.Size;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.compatibility.common.util.AppOpsUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -207,6 +210,8 @@
 
     @Test
     public void testPinnedStackInBoundsAfterRotation() {
+        // Launch an activity that is not fixed-orientation so that the display can rotate
+        launchActivity(TEST_ACTIVITY);
         // Launch an activity into the pinned stack
         launchActivity(PIP_ACTIVITY,
                 EXTRA_ENTER_PIP, "true",
@@ -421,26 +426,25 @@
         // Go home and ensure that there is a pinned stack
         separateTestJournal();
         launchHomeActivity();
-        waitForEnterPip(PIP_ACTIVITY);
+        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
         assertPinnedStackExists();
 
         final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY);
-        // Check that onPictureInPictureRequested was called to try to enter pip from there
-        assertEquals("onPictureInPictureRequested", 1,
-                lifecycleCounts.getCount(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED));
-        // Check that onPause + onUserLeaveHint were called only once. These assertions verify that
-        // onPictureInPictureRequested doesn't attempt to trigger these callbacks because going
-        // home is already causing them to be called
-        assertEquals("onPause", 1, lifecycleCounts.getCount(ActivityCallback.ON_PAUSE));
-        assertEquals("onUserLeaveHint", 1,
-                lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT));
-
-        final int lastUserLeaveHintIndex =
-                lifecycleCounts.getLastIndex(ActivityCallback.ON_USER_LEAVE_HINT);
-        final int lastPipRequestedIndex =
-                lifecycleCounts.getLastIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
-        // Check that onPictureInPictureRequested was called first and onUserLeaveHint after
-        assertThat(lastPipRequestedIndex, lessThan(lastUserLeaveHintIndex));
+        // Check the order of the callbacks accounting for a task overlay activity that might show.
+        // The PIP request (with a user leave hint) should come before the pip mode change.
+        final int firstUserLeaveIndex =
+                lifecycleCounts.getFirstIndex(ActivityCallback.ON_USER_LEAVE_HINT);
+        final int firstPipRequestedIndex =
+                lifecycleCounts.getFirstIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
+        final int firstPipModeChangedIndex =
+                lifecycleCounts.getFirstIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_MODE_CHANGED);
+        assertTrue("missing request", firstPipRequestedIndex != -1);
+        assertTrue("missing user leave", firstUserLeaveIndex != -1);
+        assertTrue("missing pip mode changed", firstPipModeChangedIndex != -1);
+        assertTrue("pip requested not before pause",
+                firstPipRequestedIndex < firstUserLeaveIndex);
+        assertTrue("unexpected user leave hint",
+                firstUserLeaveIndex < firstPipModeChangedIndex);
     }
 
     @Test
@@ -455,26 +459,24 @@
         // Call onPictureInPictureRequested and verify activity enters pip
         separateTestJournal();
         mBroadcastActionTrigger.doAction(ACTION_ON_PIP_REQUESTED);
-        waitForEnterPip(PIP_ACTIVITY);
+        waitForEnterPipAnimationComplete(PIP_ACTIVITY);
         assertPinnedStackExists();
 
         final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY);
-        // Check that onPictureInPictureRequested was called
-        assertEquals("onPictureInPictureRequested", 1,
-                lifecycleCounts.getCount(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED));
-        // Verify that cycling through userLeaveHint was not necessary since the activity overrode
-        // onPictureInPictureRequested and entered PIP mode from there
-        assertEquals("onUserLeaveHint", 0,
-                lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT));
-        // Verify onPause does get called when the activity eventually enters PIP mode
-        assertEquals("onPause", 1, lifecycleCounts.getCount(ActivityCallback.ON_PAUSE));
-
-        final int lastOnPauseIndex =
-                lifecycleCounts.getLastIndex(ActivityCallback.ON_PAUSE);
-        final int lastPipRequestedIndex =
-                lifecycleCounts.getLastIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
-        // Check that onPictureInPictureRequested was called first and onPause after
-        assertThat(lastPipRequestedIndex, lessThan(lastOnPauseIndex));
+        // Check the order of the callbacks accounting for a task overlay activity that might show.
+        // The PIP request (without a user leave hint) should come before the pip mode change.
+        final int firstUserLeaveIndex =
+                lifecycleCounts.getFirstIndex(ActivityCallback.ON_USER_LEAVE_HINT);
+        final int firstPipRequestedIndex =
+                lifecycleCounts.getFirstIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED);
+        final int firstPipModeChangedIndex =
+                lifecycleCounts.getFirstIndex(ActivityCallback.ON_PICTURE_IN_PICTURE_MODE_CHANGED);
+        assertTrue("missing request", firstPipRequestedIndex != -1);
+        assertTrue("missing pip mode changed", firstPipModeChangedIndex != -1);
+        assertTrue("pip requested not before pause",
+                firstPipRequestedIndex < firstPipModeChangedIndex);
+        assertTrue("unexpected user leave hint",
+                firstUserLeaveIndex == -1 || firstUserLeaveIndex > firstPipModeChangedIndex);
     }
 
     @Test
@@ -931,6 +933,7 @@
         separateTestJournal();
         removeStacksInWindowingModes(WINDOWING_MODE_PINNED);
         waitForExitPipToFullscreen(PIP_ACTIVITY);
+        waitForValidPictureInPictureCallbacks(PIP_ACTIVITY);
 
         // Confirm that we get stop before the multi-window and picture-in-picture mode change
         // callbacks
@@ -995,6 +998,7 @@
     }
 
     @Test
+    @FlakyTest(bugId=156314330)
     public void testFinishPipActivityWithTaskOverlay() throws Exception {
         // Launch PiP activity
         launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
@@ -1038,6 +1042,7 @@
         assertEquals("onPause", 0, lifecycleCounts.getCount(ActivityCallback.ON_PAUSE));
     }
 
+    @FlakyTest(bugId = 156003518)
     @Test
     public void testPinnedStackWithDockedStack() throws Exception {
         assumeTrue(supportsSplitScreenMultiWindow());
@@ -1134,7 +1139,7 @@
                 EXTRA_ENTER_PIP, "true",
                 EXTRA_START_ACTIVITY, getActivityName(PIP_ACTIVITY),
                 EXTRA_FINISH_SELF_ON_RESUME, "true");
-        waitForEnterPip(TEST_ACTIVITY_WITH_SAME_AFFINITY);
+        waitForEnterPip(PIP_ACTIVITY);
         assertPinnedStackExists();
 
         // Launch the root activity again, of the matching task and ensure that we expand to
@@ -1142,7 +1147,7 @@
         int activityTaskId = mWmState.getTaskByActivity(PIP_ACTIVITY).mTaskId;
         launchHomeActivity();
         launchActivity(TEST_ACTIVITY_WITH_SAME_AFFINITY);
-        waitForExitPipToFullscreen(TEST_ACTIVITY_WITH_SAME_AFFINITY);
+        waitForExitPipToFullscreen(PIP_ACTIVITY);
         assertPinnedStackDoesNotExist();
         assertEquals(activityTaskId, mWmState.getTaskByActivity(
                 PIP_ACTIVITY).mTaskId);
@@ -1277,32 +1282,26 @@
      * subsequent animation to start).
      */
     private void waitForEnterPip(ComponentName activityName) {
-        mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName)
-                .setWindowingMode(WINDOWING_MODE_PINNED)
-                .setActivityType(ACTIVITY_TYPE_STANDARD)
-                .build());
+        mWmState.waitForWithAmState(wmState -> {
+            ActivityTask task = wmState.getTaskByActivity(activityName);
+            return task != null && task.getWindowingMode() == WINDOWING_MODE_PINNED;
+        }, "checking task windowing mode");
     }
 
     /**
      * Waits until the picture-in-picture animation has finished.
-     * TODO(b/149947030): use the transition completed signal from TaskOrganizer
      */
     private void waitForEnterPipAnimationComplete(ComponentName activityName) {
         waitForEnterPip(activityName);
-        final Rect pinnedStackBounds = new Rect();
         mWmState.waitForWithAmState(wmState -> {
-            final Rect displayStableBounds = wmState.getStableBounds();
-            Rect newBounds = wmState.getStandardStackByWindowingMode(WINDOWING_MODE_PINNED)
-                    .getBounds();
-            if (pinnedStackBounds.equals(newBounds)
-                    && (displayStableBounds.width() / 2) > newBounds.width()
-                    && (displayStableBounds.height() / 2) > newBounds.height()) {
-                return true;
-            } else if (newBounds != null) {
-                pinnedStackBounds.set(newBounds);
+            ActivityTask task = wmState.getTaskByActivity(activityName);
+            if (task == null) {
+                return false;
             }
-            return false;
-        }, "stack bounds stabilized, consider in pinned mode");
+            WindowManagerState.Activity activity = task.getActivity(activityName);
+            return activity.getWindowingMode() == WINDOWING_MODE_PINNED
+                    && activity.getState().equals(STATE_PAUSED);
+        }, "checking activity windowing mode");
     }
 
     /**
@@ -1316,28 +1315,20 @@
 
     /**
      * Waits until the picture-in-picture animation to fullscreen has finished.
-     * TODO(b/149947030): use the transition completed signal from TaskOrganizer
      */
     private void waitForExitPipToFullscreen(ComponentName activityName) {
-        mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName)
-                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
-                .setActivityType(ACTIVITY_TYPE_STANDARD)
-                .build());
-        final Rect stackBounds = new Rect();
         mWmState.waitForWithAmState(wmState -> {
-            final Rect displayStableBounds = wmState.getStableBounds();
             final ActivityTask task = wmState.getTaskByActivity(activityName);
-            if (task == null) return false;
-            Rect newBounds = task.getBounds();
-            if (stackBounds.equals(newBounds)
-                    && (displayStableBounds.width() / 2) < newBounds.width()
-                    && (displayStableBounds.height() / 2) < newBounds.height()) {
-                return true;
-            } else if (newBounds != null) {
-                stackBounds.set(newBounds);
+            if (task == null) {
+                return false;
             }
-            return false;
-        }, "stack bounds stabilized, consider in fullscreen mode");
+            final WindowManagerState.Activity activity = task.getActivity(activityName);
+            return activity.getWindowingMode() != WINDOWING_MODE_PINNED;
+        }, "checking activity windowing mode");
+        mWmState.waitForWithAmState(wmState -> {
+            final ActivityTask task = wmState.getTaskByActivity(activityName);
+            return task != null && task.getWindowingMode() != WINDOWING_MODE_PINNED;
+        }, "checking task windowing mode");
     }
 
     /**
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java b/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java
index 3619bed..5e813d1 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Intent;
-import android.hardware.display.DisplayManager;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.app.Components;
 import android.view.Display;
@@ -38,8 +37,7 @@
 
     @Test
     public void testPresentationFollowsDisplayFlag() {
-        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
-        for (Display display : displayManager.getDisplays()) {
+        for (Display display : mDm.getDisplays()) {
             launchPresentationActivity(display.getDisplayId());
             if ((display.getFlags() & Display.FLAG_PRESENTATION) != Display.FLAG_PRESENTATION) {
                 assertNoPresentationDisplayed();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
index 474d9d2..ef4760e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/SurfaceControlViewHostTests.java
@@ -54,6 +54,8 @@
 import androidx.test.rule.ActivityTestRule;
 
 import com.android.compatibility.common.util.CtsTouchUtils;
+import com.android.compatibility.common.util.WidgetTestUtils;
+
 
 import android.platform.test.annotations.Presubmit;
 
@@ -78,7 +80,7 @@
     private View mEmbeddedView;
     private WindowManager.LayoutParams mEmbeddedLayoutParams;
 
-    private boolean mClicked = false;
+    private volatile boolean mClicked = false;
 
     /*
      * Configurable state to control how the surfaceCreated callback
@@ -220,7 +222,8 @@
         mActivityRule.runOnUiThread(() -> {
                 mVr.relayout(bigEdgeLength, bigEdgeLength);
         });
-        mInstrumentation.waitForIdleSync();
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule,
+            mEmbeddedView, null);
 
         // But after the click should hit.
         CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, mActivityRule, mSurfaceView);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java b/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java
index 9617c7b..5e3e030 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/VrDisplayTests.java
@@ -29,6 +29,7 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.content.ComponentName;
+import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 import android.server.wm.WindowManagerState.DisplayContent;
@@ -46,6 +47,7 @@
  *     atest CtsWindowManagerDeviceTestCases:VrDisplayTests
  */
 @Presubmit
+@FlakyTest
 @android.server.wm.annotation.Group3
 public class VrDisplayTests extends MultiDisplayTestBase {
     private static final int VR_VIRTUAL_DISPLAY_WIDTH = 700;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTestBase.java
index 2422945..83407f6 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowContextTestBase.java
@@ -19,19 +19,17 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
 import android.content.Context;
-import android.hardware.display.DisplayManager;
 import android.view.Display;
 
 /**  Base class for window context tests */
 class WindowContextTestBase extends MultiDisplayTestBase {
-    private DisplayManager mDisplayManager = mContext.getSystemService(DisplayManager.class);
 
     Context createWindowContext(int displayId) {
         return createWindowContext(displayId, TYPE_APPLICATION_OVERLAY);
     }
 
     Context createWindowContext(int displayId, int type) {
-        final Display display = mDisplayManager.getDisplay(displayId);
+        final Display display = mDm.getDisplay(displayId);
         return mContext.createDisplayContext(display).createWindowContext(
                 type, null /* options */);
     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
index 7b38972..6e21f4b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -44,7 +44,7 @@
 import android.graphics.Insets;
 import android.os.CancellationSignal;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.WindowInsetsAnimationTests.TestActivity;
+import android.server.wm.WindowInsetsAnimationTestBase.TestActivity;
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java
new file mode 100644
index 0000000..32255d2
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationImeTests.java
@@ -0,0 +1,156 @@
+/*
+ * 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.server.wm;
+
+import static android.graphics.Insets.NONE;
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.withSettings;
+
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.Presubmit;
+import android.view.WindowInsets;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.cts.mockime.ImeSettings;
+import com.android.cts.mockime.MockImeSessionRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+/**
+ * Same as {@link WindowInsetsAnimationTests} but IME specific.
+ *
+ * Build/Install/Run:
+ *     atest CtsWindowManagerDeviceTestCases:WindowInsetsAnimationImeTests
+ */
+@Presubmit
+public class WindowInsetsAnimationImeTests extends WindowInsetsAnimationTestBase {
+
+    @Rule
+    public final MockImeSessionRule mMockImeSessionRule = new MockImeSessionRule(
+            InstrumentationRegistry.getInstrumentation().getContext(),
+            InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+            new ImeSettings.Builder()
+    );
+
+    @Before
+    public void setup() throws Exception {
+        super.setUp();
+        assumeTrue("MockIme cannot be used for devices that do not support installable IMEs",
+                mInstrumentation.getContext().getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_INPUT_METHODS));
+        mActivity = startActivity(TestActivity.class);
+        mRootView = mActivity.getWindow().getDecorView();
+    }
+
+    @Test
+    public void testImeAnimationCallbacksShowAndHide() {
+        WindowInsets before = mActivity.mLastWindowInsets;
+        getInstrumentation().runOnMainSync(
+                () -> mRootView.getWindowInsetsController().show(ime()));
+
+        waitForOrFail("Waiting until animation done", () -> mActivity.mCallback.animationDone);
+        commonAnimationAssertions(mActivity, before, true /* show */, ime());
+        mActivity.mCallback.animationDone = false;
+
+        before = mActivity.mLastWindowInsets;
+
+        getInstrumentation().runOnMainSync(
+                () -> mRootView.getWindowInsetsController().hide(ime()));
+
+        waitForOrFail("Waiting until animation done", () -> mActivity.mCallback.animationDone);
+
+        commonAnimationAssertions(mActivity, before, false /* show */, ime());
+    }
+
+    @Test
+    @FlakyTest(detail = "Promote once confirmed non-flaky")
+    public void testAnimationCallbacks_overlapping_opposite() {
+        WindowInsets before = mActivity.mLastWindowInsets;
+
+        MultiAnimCallback callbackInner = new MultiAnimCallback();
+        MultiAnimCallback callback = mock(MultiAnimCallback.class,
+                withSettings()
+                        .spiedInstance(callbackInner)
+                        .defaultAnswer(CALLS_REAL_METHODS)
+                        .verboseLogging());
+        mActivity.mView.setWindowInsetsAnimationCallback(callback);
+
+        getInstrumentation().runOnMainSync(
+                () -> mRootView.getWindowInsetsController().hide(navigationBars()));
+        getInstrumentation().runOnMainSync(
+                () -> mRootView.getWindowInsetsController().show(ime()));
+
+        waitForOrFail("Waiting until animation done", () -> callback.animationDone);
+
+        WindowInsets after = mActivity.mLastWindowInsets;
+
+        InOrder inOrder = inOrder(callback, mActivity.mListener);
+
+        inOrder.verify(callback).onPrepare(eq(callback.navBarAnim));
+
+        inOrder.verify(mActivity.mListener).onApplyWindowInsets(any(), argThat(
+                argument -> NONE.equals(argument.getInsets(navigationBars()))
+                        && NONE.equals(argument.getInsets(ime()))));
+
+        inOrder.verify(callback).onStart(eq(callback.navBarAnim), argThat(
+                argument -> argument.getLowerBound().equals(NONE)
+                        && argument.getUpperBound().equals(before.getInsets(navigationBars()))));
+
+        inOrder.verify(callback).onPrepare(eq(callback.imeAnim));
+        inOrder.verify(mActivity.mListener).onApplyWindowInsets(
+                any(), eq(mActivity.mLastWindowInsets));
+
+        inOrder.verify(callback).onStart(eq(callback.imeAnim), argThat(
+                argument -> argument.getLowerBound().equals(NONE)
+                        && !argument.getUpperBound().equals(NONE)));
+
+        inOrder.verify(callback).onEnd(eq(callback.navBarAnim));
+        inOrder.verify(callback).onEnd(eq(callback.imeAnim));
+
+        assertAnimationSteps(callback.navAnimSteps, false /* showAnimation */);
+        assertAnimationSteps(callback.imeAnimSteps, false /* showAnimation */);
+
+        assertEquals(before.getInsets(navigationBars()),
+                callback.navAnimSteps.get(0).insets.getInsets(navigationBars()));
+        assertEquals(after.getInsets(navigationBars()),
+                callback.navAnimSteps.get(callback.navAnimSteps.size() - 1).insets
+                        .getInsets(navigationBars()));
+
+        assertEquals(before.getInsets(ime()),
+                callback.imeAnimSteps.get(0).insets.getInsets(ime()));
+        assertEquals(after.getInsets(ime()),
+                callback.imeAnimSteps.get(callback.imeAnimSteps.size() - 1).insets
+                        .getInsets(ime()));
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
new file mode 100644
index 0000000..404fd70
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTestBase.java
@@ -0,0 +1,320 @@
+/*
+ * 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.server.wm;
+
+import static android.graphics.Insets.NONE;
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
+import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+
+import android.os.Bundle;
+import android.util.ArraySet;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
+import android.server.wm.WindowInsetsAnimationTestBase.AnimCallback.AnimationStep;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.junit.Assert;
+import org.mockito.InOrder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Base class for tests in {@link WindowInsetsAnimation} and {@link WindowInsetsAnimation.Callback}.
+ */
+public class WindowInsetsAnimationTestBase extends WindowManagerTestBase {
+
+    protected TestActivity mActivity;
+    protected View mRootView;
+
+    protected void commonAnimationAssertions(TestActivity activity, WindowInsets before,
+            boolean show, int types) {
+
+        AnimCallback callback = activity.mCallback;
+
+        InOrder inOrder = inOrder(activity.mCallback, activity.mListener);
+
+        WindowInsets after = activity.mLastWindowInsets;
+        inOrder.verify(callback).onPrepare(eq(callback.lastAnimation));
+        inOrder.verify(activity.mListener).onApplyWindowInsets(any(), any());
+
+        inOrder.verify(callback).onStart(eq(callback.lastAnimation), argThat(
+                argument -> argument.getLowerBound().equals(NONE)
+                        && argument.getUpperBound().equals(show
+                        ? after.getInsets(types)
+                        : before.getInsets(types))));
+
+        inOrder.verify(callback, atLeast(2)).onProgress(any(), argThat(
+                argument -> argument.size() == 1 && argument.get(0) == callback.lastAnimation));
+        inOrder.verify(callback).onEnd(eq(callback.lastAnimation));
+
+        if ((types & systemBars()) != 0) {
+            assertTrue((callback.lastAnimation.getTypeMask() & systemBars()) != 0);
+        }
+        if ((types & ime()) != 0) {
+            assertTrue((callback.lastAnimation.getTypeMask() & ime()) != 0);
+        }
+        assertTrue(callback.lastAnimation.getDurationMillis() > 0);
+        assertNotNull(callback.lastAnimation.getInterpolator());
+        assertBeforeAfterState(callback.animationSteps, before, after);
+        assertAnimationSteps(callback.animationSteps, show /* increasing */);
+    }
+
+    private void assertBeforeAfterState(ArrayList<AnimationStep> steps, WindowInsets before,
+            WindowInsets after) {
+        assertEquals(before, steps.get(0).insets);
+        assertEquals(after, steps.get(steps.size() - 1).insets);
+    }
+
+    protected void assertAnimationSteps(ArrayList<AnimationStep> steps, boolean showAnimation) {
+        assertTrue(steps.size() >= 2);
+        assertEquals(0f, steps.get(0).fraction, 0f);
+        assertEquals(0f, steps.get(0).interpolatedFraction, 0f);
+        assertEquals(1f, steps.get(steps.size() - 1).fraction, 0f);
+        assertEquals(1f, steps.get(steps.size() - 1).interpolatedFraction, 0f);
+        if (showAnimation) {
+            assertEquals(1f, steps.get(steps.size() - 1).alpha, 0f);
+        } else {
+            assertEquals(1f, steps.get(0).alpha, 0f);
+        }
+
+        assertListElements(steps, step -> step.fraction,
+                (current, next) -> next >= current);
+        assertListElements(steps, step -> step.interpolatedFraction,
+                (current, next) -> next >= current);
+        assertListElements(steps, step -> step.alpha, alpha -> alpha >= 0f);
+        assertListElements(steps, step -> step.insets, compareInsets(systemBars(), showAnimation));
+    }
+
+    private BiPredicate<WindowInsets, WindowInsets> compareInsets(int types,
+            boolean showAnimation) {
+        if (showAnimation) {
+            return (current, next) ->
+                    next.getInsets(types).left >= current.getInsets(types).left
+                            && next.getInsets(types).top >= current.getInsets(types).top
+                            && next.getInsets(types).right >= current.getInsets(types).right
+                            && next.getInsets(types).bottom >= current.getInsets(types).bottom;
+        } else {
+            return (current, next) ->
+                    next.getInsets(types).left <= current.getInsets(types).left
+                            && next.getInsets(types).top <= current.getInsets(types).top
+                            && next.getInsets(types).right <= current.getInsets(types).right
+                            && next.getInsets(types).bottom <= current.getInsets(types).bottom;
+        }
+    }
+
+    private <T, V> void assertListElements(ArrayList<T> list, Function<T, V> getter,
+            Predicate<V> predicate) {
+        for (int i = 0; i <= list.size() - 1; i++) {
+            V value = getter.apply(list.get(i));
+            assertTrue("Predicate.test failed i=" + i + " value="
+                    + value, predicate.test(value));
+        }
+    }
+
+    private <T, V> void assertListElements(ArrayList<T> list, Function<T, V> getter,
+            BiPredicate<V, V> comparator) {
+        for (int i = 0; i <= list.size() - 2; i++) {
+            V current = getter.apply(list.get(i));
+            V next = getter.apply(list.get(i + 1));
+            assertTrue(comparator.test(current, next));
+        }
+    }
+
+    public static class AnimCallback extends WindowInsetsAnimation.Callback {
+
+        public static class AnimationStep {
+
+            AnimationStep(WindowInsets insets, float fraction, float interpolatedFraction,
+                    float alpha) {
+                this.insets = insets;
+                this.fraction = fraction;
+                this.interpolatedFraction = interpolatedFraction;
+                this.alpha = alpha;
+            }
+
+            WindowInsets insets;
+            float fraction;
+            float interpolatedFraction;
+            float alpha;
+        }
+
+        WindowInsetsAnimation lastAnimation;
+        volatile boolean animationDone;
+        final ArrayList<AnimationStep> animationSteps = new ArrayList<>();
+
+        public AnimCallback(int dispatchMode) {
+            super(dispatchMode);
+        }
+
+        @Override
+        public void onPrepare(WindowInsetsAnimation animation) {
+            animationSteps.clear();
+            lastAnimation = animation;
+        }
+
+        @Override
+        public WindowInsetsAnimation.Bounds onStart(
+                WindowInsetsAnimation animation, WindowInsetsAnimation.Bounds bounds) {
+            return bounds;
+        }
+
+        @Override
+        public WindowInsets onProgress(WindowInsets insets,
+                List<WindowInsetsAnimation> runningAnimations) {
+            animationSteps.add(new AnimationStep(insets, lastAnimation.getFraction(),
+                    lastAnimation.getInterpolatedFraction(), lastAnimation.getAlpha()));
+            return WindowInsets.CONSUMED;
+        }
+
+        @Override
+        public void onEnd(WindowInsetsAnimation animation) {
+            animationDone = true;
+        }
+    }
+
+    protected static class MultiAnimCallback extends WindowInsetsAnimation.Callback {
+
+        WindowInsetsAnimation statusBarAnim;
+        WindowInsetsAnimation navBarAnim;
+        WindowInsetsAnimation imeAnim;
+        volatile boolean animationDone;
+        final ArrayList<AnimationStep> statusAnimSteps = new ArrayList<>();
+        final ArrayList<AnimationStep> navAnimSteps = new ArrayList<>();
+        final ArrayList<AnimationStep> imeAnimSteps = new ArrayList<>();
+        Runnable startRunnable;
+        final ArraySet<WindowInsetsAnimation> runningAnims = new ArraySet<>();
+
+        public MultiAnimCallback() {
+            super(DISPATCH_MODE_STOP);
+        }
+
+        @Override
+        public void onPrepare(WindowInsetsAnimation animation) {
+            if ((animation.getTypeMask() & statusBars()) != 0) {
+                statusBarAnim = animation;
+            }
+            if ((animation.getTypeMask() & navigationBars()) != 0) {
+                navBarAnim = animation;
+            }
+            if ((animation.getTypeMask() & ime()) != 0) {
+                imeAnim = animation;
+            }
+        }
+
+        @Override
+        public WindowInsetsAnimation.Bounds onStart(
+                WindowInsetsAnimation animation, WindowInsetsAnimation.Bounds bounds) {
+            if (startRunnable != null) {
+                startRunnable.run();
+            }
+            runningAnims.add(animation);
+            return bounds;
+        }
+
+        @Override
+        public WindowInsets onProgress(WindowInsets insets,
+                List<WindowInsetsAnimation> runningAnimations) {
+            if (statusBarAnim != null) {
+                statusAnimSteps.add(new AnimationStep(insets, statusBarAnim.getFraction(),
+                        statusBarAnim.getInterpolatedFraction(), statusBarAnim.getAlpha()));
+            }
+            if (navBarAnim != null) {
+                navAnimSteps.add(new AnimationStep(insets, navBarAnim.getFraction(),
+                        navBarAnim.getInterpolatedFraction(), navBarAnim.getAlpha()));
+            }
+            if (imeAnim != null) {
+                imeAnimSteps.add(new AnimationStep(insets, imeAnim.getFraction(),
+                        imeAnim.getInterpolatedFraction(), imeAnim.getAlpha()));
+            }
+
+            assertEquals(runningAnims.size(), runningAnimations.size());
+            for (int i = runningAnimations.size() - 1; i >= 0; i--) {
+                Assert.assertNotEquals(-1,
+                        runningAnims.indexOf(runningAnimations.get(i)));
+            }
+
+            return WindowInsets.CONSUMED;
+        }
+
+        @Override
+        public void onEnd(WindowInsetsAnimation animation) {
+            runningAnims.remove(animation);
+            if (runningAnims.isEmpty()) {
+                animationDone = true;
+            }
+        }
+    }
+
+    public static class TestActivity extends FocusableActivity {
+
+        AnimCallback mCallback =
+                spy(new AnimCallback(WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP));
+        WindowInsets mLastWindowInsets;
+
+        View.OnApplyWindowInsetsListener mListener;
+        LinearLayout mView;
+        View mChild;
+        EditText mEditor;
+
+        public class InsetsListener implements View.OnApplyWindowInsetsListener {
+
+            @Override
+            public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+                mLastWindowInsets = insets;
+                return WindowInsets.CONSUMED;
+            }
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mListener = spy(new InsetsListener());
+            mView = new LinearLayout(this);
+            mView.setWindowInsetsAnimationCallback(mCallback);
+            mView.setOnApplyWindowInsetsListener(mListener);
+            mChild = new TextView(this);
+            mEditor = new EditText(this);
+            mView.addView(mChild);
+
+            getWindow().setDecorFitsSystemWindows(false);
+            getWindow().getAttributes().layoutInDisplayCutoutMode =
+                    LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+            setContentView(mView);
+            mEditor.requestFocus();
+        }
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
index 86fc5ee..e3a5328 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationTests.java
@@ -17,54 +17,37 @@
 package android.server.wm;
 
 import static android.graphics.Insets.NONE;
-import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
 import static android.view.WindowInsets.Type.systemBars;
 import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.CALLS_REAL_METHODS;
-import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.withSettings;
 
-import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.WindowInsetsAnimationTests.AnimCallback.AnimationStep;
-import android.util.ArraySet;
-import android.view.View;
-import android.view.View.OnApplyWindowInsetsListener;
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimation.Bounds;
 import android.view.WindowInsetsAnimation.Callback;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InOrder;
 
-import java.util.ArrayList;
 import java.util.List;
-import java.util.function.BiPredicate;
-import java.util.function.Function;
-import java.util.function.Predicate;
 
 import androidx.test.filters.FlakyTest;
 
@@ -75,13 +58,10 @@
  *     atest CtsWindowManagerDeviceTestCases:WindowInsetsAnimationTests
  */
 @Presubmit
-public class WindowInsetsAnimationTests extends WindowManagerTestBase {
-
-    TestActivity mActivity;
-    View mRootView;
+public class WindowInsetsAnimationTests extends WindowInsetsAnimationTestBase {
 
     @Before
-    public void setUp() throws Exception {
+    public void setup() throws Exception {
         super.setUp();
         mActivity = startActivity(TestActivity.class);
         mRootView = mActivity.getWindow().getDecorView();
@@ -118,26 +98,6 @@
     }
 
     @Test
-    public void testImeAnimationCallbacksShowAndHide() {
-        WindowInsets before = mActivity.mLastWindowInsets;
-        getInstrumentation().runOnMainSync(
-                () -> mRootView.getWindowInsetsController().show(ime()));
-
-        waitForOrFail("Waiting until animation done", () -> mActivity.mCallback.animationDone);
-        commonAnimationAssertions(mActivity, before, true /* show */, ime());
-        mActivity.mCallback.animationDone = false;
-
-        before = mActivity.mLastWindowInsets;
-
-        getInstrumentation().runOnMainSync(
-                () -> mRootView.getWindowInsetsController().hide(ime()));
-
-        waitForOrFail("Waiting until animation done", () -> mActivity.mCallback.animationDone);
-
-        commonAnimationAssertions(mActivity, before, false /* show */, ime());
-    }
-
-    @Test
     @FlakyTest(detail = "Promote once confirmed non-flaky")
     public void testAnimationCallbacks_overlapping() {
         WindowInsets before = mActivity.mLastWindowInsets;
@@ -199,67 +159,6 @@
     }
 
     @Test
-    @FlakyTest(detail = "Promote once confirmed non-flaky")
-    public void testAnimationCallbacks_overlapping_opposite() {
-        WindowInsets before = mActivity.mLastWindowInsets;
-
-        MultiAnimCallback callbackInner = new MultiAnimCallback();
-        MultiAnimCallback callback = mock(MultiAnimCallback.class,
-                withSettings()
-                        .spiedInstance(callbackInner)
-                        .defaultAnswer(CALLS_REAL_METHODS)
-                        .verboseLogging());
-        mActivity.mView.setWindowInsetsAnimationCallback(callback);
-
-        getInstrumentation().runOnMainSync(
-                () -> mRootView.getWindowInsetsController().hide(navigationBars()));
-        getInstrumentation().runOnMainSync(
-                () -> mRootView.getWindowInsetsController().show(ime()));
-
-        waitForOrFail("Waiting until animation done", () -> callback.animationDone);
-
-        WindowInsets after = mActivity.mLastWindowInsets;
-
-        InOrder inOrder = inOrder(callback, mActivity.mListener);
-
-        inOrder.verify(callback).onPrepare(eq(callback.navBarAnim));
-
-        inOrder.verify(mActivity.mListener).onApplyWindowInsets(any(), argThat(
-                argument -> NONE.equals(argument.getInsets(navigationBars()))
-                        && NONE.equals(argument.getInsets(ime()))));
-
-        inOrder.verify(callback).onStart(eq(callback.navBarAnim), argThat(
-                argument -> argument.getLowerBound().equals(NONE)
-                        && argument.getUpperBound().equals(before.getInsets(navigationBars()))));
-
-        inOrder.verify(callback).onPrepare(eq(callback.imeAnim));
-        inOrder.verify(mActivity.mListener).onApplyWindowInsets(
-                any(), eq(mActivity.mLastWindowInsets));
-
-        inOrder.verify(callback).onStart(eq(callback.imeAnim), argThat(
-                argument -> argument.getLowerBound().equals(NONE)
-                        && !argument.getUpperBound().equals(NONE)));
-
-        inOrder.verify(callback).onEnd(eq(callback.navBarAnim));
-        inOrder.verify(callback).onEnd(eq(callback.imeAnim));
-
-        assertAnimationSteps(callback.navAnimSteps, false /* showAnimation */);
-        assertAnimationSteps(callback.imeAnimSteps, false /* showAnimation */);
-
-        assertEquals(before.getInsets(navigationBars()),
-                callback.navAnimSteps.get(0).insets.getInsets(navigationBars()));
-        assertEquals(after.getInsets(navigationBars()),
-                callback.navAnimSteps.get(callback.navAnimSteps.size() - 1).insets
-                        .getInsets(navigationBars()));
-
-        assertEquals(before.getInsets(ime()),
-                callback.imeAnimSteps.get(0).insets.getInsets(ime()));
-        assertEquals(after.getInsets(ime()),
-                callback.imeAnimSteps.get(callback.imeAnimSteps.size() - 1).insets
-                        .getInsets(ime()));
-    }
-
-    @Test
     public void testAnimationCallbacks_consumedByDecor() {
         getInstrumentation().runOnMainSync(() -> {
             mActivity.getWindow().setDecorFitsSystemWindows(true);
@@ -326,256 +225,5 @@
                 insets -> NONE.equals(insets.getInsets(navigationBars()))), any());
     }
 
-    private void commonAnimationAssertions(TestActivity activity, WindowInsets before,
-            boolean show, int types) {
 
-        AnimCallback callback = activity.mCallback;
-
-        InOrder inOrder = inOrder(activity.mCallback, activity.mListener);
-
-        WindowInsets after = activity.mLastWindowInsets;
-        inOrder.verify(callback).onPrepare(eq(callback.lastAnimation));
-        inOrder.verify(activity.mListener).onApplyWindowInsets(any(), any());
-
-        inOrder.verify(callback).onStart(eq(callback.lastAnimation), argThat(
-                argument -> argument.getLowerBound().equals(NONE)
-                        && argument.getUpperBound().equals(show
-                                ? after.getInsets(types)
-                                : before.getInsets(types))));
-
-        inOrder.verify(callback, atLeast(2)).onProgress(any(), argThat(
-                argument -> argument.size() == 1 && argument.get(0) == callback.lastAnimation));
-        inOrder.verify(callback).onEnd(eq(callback.lastAnimation));
-
-        if ((types & systemBars()) != 0) {
-            assertTrue((callback.lastAnimation.getTypeMask() & systemBars()) != 0);
-        }
-        if ((types & ime()) != 0) {
-            assertTrue((callback.lastAnimation.getTypeMask() & ime()) != 0);
-        }
-        assertTrue(callback.lastAnimation.getDurationMillis() > 0);
-        assertNotNull(callback.lastAnimation.getInterpolator());
-        assertBeforeAfterState(callback.animationSteps, before, after);
-        assertAnimationSteps(callback.animationSteps, show /* increasing */);
-    }
-
-    private void assertBeforeAfterState(ArrayList<AnimationStep> steps, WindowInsets before,
-            WindowInsets after) {
-        assertEquals(before, steps.get(0).insets);
-        assertEquals(after, steps.get(steps.size() - 1).insets);
-    }
-
-    private void assertAnimationSteps(ArrayList<AnimationStep> steps, boolean showAnimation) {
-        assertTrue(steps.size() >= 2);
-        assertEquals(0f, steps.get(0).fraction, 0f);
-        assertEquals(0f, steps.get(0).interpolatedFraction, 0f);
-        assertEquals(1f, steps.get(steps.size() - 1).fraction, 0f);
-        assertEquals(1f, steps.get(steps.size() - 1).interpolatedFraction, 0f);
-        if (showAnimation) {
-            assertEquals(1f, steps.get(steps.size() - 1).alpha, 0f);
-        } else {
-            assertEquals(1f, steps.get(0).alpha, 0f);
-        }
-
-        assertListElements(steps, step -> step.fraction,
-                (current, next) -> next >= current);
-        assertListElements(steps, step -> step.interpolatedFraction,
-                (current, next) -> next >= current);
-        assertListElements(steps, step -> step.alpha, alpha -> alpha >= 0f);
-        assertListElements(steps, step -> step.insets, compareInsets(systemBars(), showAnimation));
-    }
-
-    private BiPredicate<WindowInsets, WindowInsets> compareInsets(int types,
-            boolean showAnimation) {
-        if (showAnimation) {
-            return (current, next) ->
-                    next.getInsets(types).left >= current.getInsets(types).left
-                            && next.getInsets(types).top >= current.getInsets(types).top
-                            && next.getInsets(types).right >= current.getInsets(types).right
-                            && next.getInsets(types).bottom >= current.getInsets(types).bottom;
-        } else {
-            return (current, next) ->
-                    next.getInsets(types).left <= current.getInsets(types).left
-                            && next.getInsets(types).top <= current.getInsets(types).top
-                            && next.getInsets(types).right <= current.getInsets(types).right
-                            && next.getInsets(types).bottom <= current.getInsets(types).bottom;
-        }
-    }
-
-    private <T, V> void assertListElements(ArrayList<T> list, Function<T, V> getter,
-            Predicate<V> predicate) {
-        for (int i = 0; i <= list.size() - 1; i++) {
-            V value = getter.apply(list.get(i));
-            assertTrue("Predicate.test failed i=" + i + " value=" + value, predicate.test(value));
-        }
-    }
-
-    private <T, V> void assertListElements(ArrayList<T> list, Function<T, V> getter,
-            BiPredicate<V, V> comparator) {
-        for (int i = 0; i <= list.size() - 2; i++) {
-            V current = getter.apply(list.get(i));
-            V next = getter.apply(list.get(i + 1));
-            assertTrue(comparator.test(current, next));
-        }
-    }
-
-    public static class AnimCallback extends WindowInsetsAnimation.Callback {
-
-        public static class AnimationStep {
-
-            AnimationStep(WindowInsets insets, float fraction, float interpolatedFraction,
-                    float alpha) {
-                this.insets = insets;
-                this.fraction = fraction;
-                this.interpolatedFraction = interpolatedFraction;
-                this.alpha = alpha;
-            }
-
-            WindowInsets insets;
-            float fraction;
-            float interpolatedFraction;
-            float alpha;
-        }
-
-        WindowInsetsAnimation lastAnimation;
-        volatile boolean animationDone;
-        final ArrayList<AnimationStep> animationSteps = new ArrayList<>();
-
-        public AnimCallback(int dispatchMode) {
-            super(dispatchMode);
-        }
-
-        @Override
-        public void onPrepare(WindowInsetsAnimation animation) {
-            animationSteps.clear();
-            lastAnimation = animation;
-        }
-
-        @Override
-        public Bounds onStart(WindowInsetsAnimation animation, Bounds bounds) {
-            return bounds;
-        }
-
-        @Override
-        public WindowInsets onProgress(WindowInsets insets,
-                List<WindowInsetsAnimation> runningAnimations) {
-            animationSteps.add(new AnimationStep(insets, lastAnimation.getFraction(),
-                    lastAnimation.getInterpolatedFraction(), lastAnimation.getAlpha()));
-            return WindowInsets.CONSUMED;
-        }
-
-        @Override
-        public void onEnd(WindowInsetsAnimation animation) {
-            animationDone = true;
-        }
-    }
-
-    public static class MultiAnimCallback extends WindowInsetsAnimation.Callback {
-
-        WindowInsetsAnimation statusBarAnim;
-        WindowInsetsAnimation navBarAnim;
-        WindowInsetsAnimation imeAnim;
-        volatile boolean animationDone;
-        final ArrayList<AnimationStep> statusAnimSteps = new ArrayList<>();
-        final ArrayList<AnimationStep> navAnimSteps = new ArrayList<>();
-        final ArrayList<AnimationStep> imeAnimSteps = new ArrayList<>();
-        Runnable startRunnable;
-        final ArraySet<WindowInsetsAnimation> runningAnims = new ArraySet<>();
-
-        public MultiAnimCallback() {
-            super(DISPATCH_MODE_STOP);
-        }
-
-        @Override
-        public void onPrepare(WindowInsetsAnimation animation) {
-            if ((animation.getTypeMask() & statusBars()) != 0) {
-                statusBarAnim = animation;
-            }
-            if ((animation.getTypeMask() & navigationBars()) != 0) {
-                navBarAnim = animation;
-            }
-            if ((animation.getTypeMask() & ime()) != 0) {
-                imeAnim = animation;
-            }
-        }
-
-        @Override
-        public Bounds onStart(WindowInsetsAnimation animation, Bounds bounds) {
-            if (startRunnable != null) {
-                startRunnable.run();
-            }
-            runningAnims.add(animation);
-            return bounds;
-        }
-
-        @Override
-        public WindowInsets onProgress(WindowInsets insets,
-                List<WindowInsetsAnimation> runningAnimations) {
-            if (statusBarAnim != null) {
-                statusAnimSteps.add(new AnimationStep(insets, statusBarAnim.getFraction(),
-                        statusBarAnim.getInterpolatedFraction(), statusBarAnim.getAlpha()));
-            }
-            if (navBarAnim != null) {
-                navAnimSteps.add(new AnimationStep(insets, navBarAnim.getFraction(),
-                        navBarAnim.getInterpolatedFraction(), navBarAnim.getAlpha()));
-            }
-            if (imeAnim != null) {
-                imeAnimSteps.add(new AnimationStep(insets, imeAnim.getFraction(),
-                        imeAnim.getInterpolatedFraction(), imeAnim.getAlpha()));
-            }
-
-            assertEquals(runningAnims.size(), runningAnimations.size());
-            for (int i = runningAnimations.size() - 1; i >= 0; i--) {
-                Assert.assertNotEquals(-1, runningAnims.indexOf(runningAnimations.get(i)));
-            }
-
-            return WindowInsets.CONSUMED;
-        }
-
-        @Override
-        public void onEnd(WindowInsetsAnimation animation) {
-            runningAnims.remove(animation);
-            if (runningAnims.isEmpty()) {
-                animationDone = true;
-            }
-        }
-    }
-
-    public static class TestActivity extends FocusableActivity {
-
-        AnimCallback mCallback = spy(new AnimCallback(Callback.DISPATCH_MODE_STOP));
-        WindowInsets mLastWindowInsets;
-
-        OnApplyWindowInsetsListener mListener;
-        LinearLayout mView;
-        View mChild;
-        EditText mEditor;
-
-        public class InsetsListener implements OnApplyWindowInsetsListener {
-
-            @Override
-            public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
-                mLastWindowInsets = insets;
-                return WindowInsets.CONSUMED;
-            }
-        }
-
-        @Override
-        protected void onCreate(Bundle savedInstanceState) {
-            super.onCreate(savedInstanceState);
-            mListener = spy(new InsetsListener());
-            mView = new LinearLayout(this);
-            mView.setWindowInsetsAnimationCallback(mCallback);
-            mView.setOnApplyWindowInsetsListener(mListener);
-            mChild = new TextView(this);
-            mEditor = new EditText(this);
-            mView.addView(mChild);
-
-            getWindow().setDecorFitsSystemWindows(false);
-            getWindow().getAttributes().layoutInDisplayCutoutMode =
-                    LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-            setContentView(mView);
-            mEditor.requestFocus();
-        }
-    }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 3baae0b..f05bf53 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -18,8 +18,8 @@
 
 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;
 import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
@@ -43,10 +43,8 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowInsets;
-import android.view.WindowInsets.Type;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowManager;
 import android.widget.EditText;
@@ -71,7 +69,6 @@
  * Build/Install/Run:
  *     atest CtsWindowManagerDeviceTestCases:WindowInsetsControllerTests
  */
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @Presubmit
 public class WindowInsetsControllerTests extends WindowManagerTestBase {
 
@@ -86,8 +83,8 @@
         final TestActivity activity = startActivity(TestActivity.class);
         final View rootView = activity.getWindow().getDecorView();
 
-        testHideInternal(rootView, Type.statusBars());
-        testHideInternal(rootView, Type.navigationBars());
+        testHideInternal(rootView, statusBars());
+        testHideInternal(rootView, navigationBars());
     }
 
     private void testHideInternal(View rootView, int types) {
@@ -104,8 +101,8 @@
         final TestActivity activity = startActivity(TestActivity.class);
         final View rootView = activity.getWindow().getDecorView();
 
-        testShowInternal(rootView, Type.statusBars());
-        testShowInternal(rootView, Type.navigationBars());
+        testShowInternal(rootView, statusBars());
+        testShowInternal(rootView, navigationBars());
     }
 
     private void testShowInternal(View rootView, int types) {
@@ -136,12 +133,13 @@
     }
 
     @Test
+    @FlakyTest(detail = "~1% flaky")
     public void testSetSystemBarsBehavior_showBarsByTouch() throws InterruptedException {
         final TestActivity activity = startActivity(TestActivity.class);
         final View rootView = activity.getWindow().getDecorView();
 
         // The show-by-touch behavior will only be applied while navigation bars get hidden.
-        final int types = Type.navigationBars();
+        final int types = navigationBars();
         assumeTrue(rootView.getRootWindowInsets().isVisible(types));
 
         rootView.getWindowInsetsController().setSystemBarsBehavior(BEHAVIOR_SHOW_BARS_BY_TOUCH);
@@ -159,7 +157,7 @@
         final View rootView = activity.getWindow().getDecorView();
 
         // Assume we have the bars and they can be visible.
-        final int types = Type.statusBars();
+        final int types = statusBars();
         assumeTrue(rootView.getRootWindowInsets().isVisible(types));
 
         rootView.getWindowInsetsController().setSystemBarsBehavior(BEHAVIOR_SHOW_BARS_BY_SWIPE);
@@ -171,8 +169,7 @@
         PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
 
         // Swiping from top of display can show bars.
-        dragOnDisplay(rootView.getWidth() / 2f, 0 /* downY */,
-                rootView.getWidth() / 2f, rootView.getHeight() / 2f);
+        dragFromTopToCenter(rootView);
         PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
     }
 
@@ -182,7 +179,7 @@
         final View rootView = activity.getWindow().getDecorView();
 
         // Assume we have the bars and they can be visible.
-        final int types = Type.statusBars();
+        final int types = statusBars();
         assumeTrue(rootView.getRootWindowInsets().isVisible(types));
 
         rootView.getWindowInsetsController().setSystemBarsBehavior(
@@ -195,8 +192,7 @@
         PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
 
         // Swiping from top of display can show transient bars, but apps cannot detect that.
-        dragOnDisplay(rootView.getWidth() / 2f, 0 /* downY */,
-                rootView.getWidth() / 2f, rootView.getHeight() /2f);
+        dragFromTopToCenter(rootView);
         PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
     }
 
@@ -268,6 +264,124 @@
     }
 
     @Test
+    public void testSetSystemUiVisibilityAfterCleared_showBarsByTouch() throws Exception {
+        final TestActivity activity = startActivity(TestActivity.class);
+        final View rootView = activity.getWindow().getDecorView();
+
+        // The show-by-touch behavior will only be applied while navigation bars get hidden.
+        final int types = navigationBars();
+        assumeTrue(rootView.getRootWindowInsets().isVisible(types));
+
+        // If we don't have any of the immersive flags, the default behavior will be show-bars-by-
+        // touch.
+        final int targetFlag = SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+
+        // Use flags to hide navigation bar.
+        ANIMATION_CALLBACK.reset();
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setWindowInsetsAnimationCallback(ANIMATION_CALLBACK);
+            rootView.setSystemUiVisibility(targetFlag);
+        });
+        ANIMATION_CALLBACK.waitForFinishing(TIMEOUT);
+        PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
+
+        // Touching on display can show bars.
+        tapOnDisplay(rootView.getWidth() / 2f, rootView.getHeight() / 2f);
+        PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+
+        // Use flags to hide navigation bar again.
+        ANIMATION_CALLBACK.reset();
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setWindowInsetsAnimationCallback(ANIMATION_CALLBACK);
+            rootView.setSystemUiVisibility(targetFlag);
+        });
+        ANIMATION_CALLBACK.waitForFinishing(TIMEOUT);
+        PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
+
+        // Touching on display can show bars.
+        tapOnDisplay(rootView.getWidth() / 2f, rootView.getHeight() / 2f);
+        PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityAfterCleared_showBarsBySwipe() throws Exception {
+        final TestActivity activity = startActivity(TestActivity.class);
+        final View rootView = activity.getWindow().getDecorView();
+
+        // Assume we have the bars and they can be visible.
+        final int types = statusBars();
+        assumeTrue(rootView.getRootWindowInsets().isVisible(types));
+
+        final int targetFlags = SYSTEM_UI_FLAG_IMMERSIVE | SYSTEM_UI_FLAG_FULLSCREEN;
+
+        // Use flags to hide status bar.
+        ANIMATION_CALLBACK.reset();
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setWindowInsetsAnimationCallback(ANIMATION_CALLBACK);
+            rootView.setSystemUiVisibility(targetFlags);
+        });
+        ANIMATION_CALLBACK.waitForFinishing(TIMEOUT);
+        PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
+
+        // Swiping from top of display can show bars.
+        dragFromTopToCenter(rootView);
+        PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+
+        // Use flags to hide status bar again.
+        ANIMATION_CALLBACK.reset();
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setWindowInsetsAnimationCallback(ANIMATION_CALLBACK);
+            rootView.setSystemUiVisibility(targetFlags);
+        });
+        ANIMATION_CALLBACK.waitForFinishing(TIMEOUT);
+        PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
+
+        // Swiping from top of display can show bars.
+        dragFromTopToCenter(rootView);
+        PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityAfterCleared_showBarsByApp() throws Exception {
+        final TestActivity activity = startActivity(TestActivity.class);
+        final View rootView = activity.getWindow().getDecorView();
+
+        // Assume we have the bars and they can be visible.
+        final int types = statusBars();
+        assumeTrue(rootView.getRootWindowInsets().isVisible(types));
+
+        // Use the flag to hide status bar.
+        ANIMATION_CALLBACK.reset();
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setWindowInsetsAnimationCallback(ANIMATION_CALLBACK);
+            rootView.setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN);
+        });
+        ANIMATION_CALLBACK.waitForFinishing(TIMEOUT);
+        PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
+
+        // Clearing the flag can show status bar.
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setSystemUiVisibility(0);
+        });
+        PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+
+        // Use the flag to hide status bar again.
+        ANIMATION_CALLBACK.reset();
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setWindowInsetsAnimationCallback(ANIMATION_CALLBACK);
+            rootView.setSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN);
+        });
+        ANIMATION_CALLBACK.waitForFinishing(TIMEOUT);
+        PollingCheck.waitFor(TIMEOUT, () -> !rootView.getRootWindowInsets().isVisible(types));
+
+        // Clearing the flag can show status bar.
+        getInstrumentation().runOnMainSync(() -> {
+            rootView.setSystemUiVisibility(0);
+        });
+        PollingCheck.waitFor(TIMEOUT, () -> rootView.getRootWindowInsets().isVisible(types));
+    }
+
+    @Test
     public void testHideOnCreate() throws Exception {
         final TestHideOnCreateActivity activity = startActivity(TestHideOnCreateActivity.class);
         final View rootView = activity.getWindow().getDecorView();
@@ -330,7 +444,7 @@
         final View childWindow = new View(activity);
         getInstrumentation().runOnMainSync(() -> {
             activity.getWindowManager().addView(childWindow,
-                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+                    new WindowManager.LayoutParams(TYPE_APPLICATION));
             mErrorCollector.checkThat(childWindow.getWindowInsetsController(), is(notNullValue()));
         });
         getInstrumentation().waitForIdleSync();
@@ -354,6 +468,11 @@
         dragOnDisplay(x, y, x, y);
     }
 
+    private void dragFromTopToCenter(View view) {
+        dragOnDisplay(view.getWidth() / 2f, 0 /* downY */,
+                view.getWidth() / 2f, view.getHeight() / 2f);
+    }
+
     private void dragOnDisplay(float downX, float downY, float upX, float upY) {
         final long downTime = SystemClock.elapsedRealtime();
 
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 8a6ba7c..1f1d4e8 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
@@ -222,6 +222,7 @@
     protected final Context mContext = getInstrumentation().getContext();
     protected final ActivityManager mAm = mContext.getSystemService(ActivityManager.class);
     protected final ActivityTaskManager mAtm = mContext.getSystemService(ActivityTaskManager.class);
+    protected final DisplayManager mDm = mContext.getSystemService(DisplayManager.class);
 
     /** The tracker to manage objects (especially {@link AutoCloseable}) in a test method. */
     protected final ObjectTracker mObjectTracker = new ObjectTracker();
@@ -1862,6 +1863,7 @@
 
     static class ActivityLifecycleCounts {
         private final int[] mCounts = new int[ActivityCallback.SIZE];
+        private final int[] mFirstIndexes = new int[ActivityCallback.SIZE];
         private final int[] mLastIndexes = new int[ActivityCallback.SIZE];
         private ComponentName mActivityName;
 
@@ -1878,11 +1880,15 @@
             // 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(() -> {
+                Arrays.fill(mFirstIndexes, -1);
                 for (int i = 0; i < callbacks.size(); i++) {
                     final ActivityCallback callback = callbacks.get(i);
                     final int ordinal = callback.ordinal();
                     mCounts[ordinal]++;
                     mLastIndexes[ordinal] = i;
+                    if (mFirstIndexes[ordinal] == -1) {
+                        mFirstIndexes[ordinal] = i;
+                    }
                 }
             });
         }
@@ -1891,6 +1897,10 @@
             return mCounts[callback.ordinal()];
         }
 
+        int getFirstIndex(ActivityCallback callback) {
+            return mFirstIndexes[callback.ordinal()];
+        }
+
         int getLastIndex(ActivityCallback callback) {
             return mLastIndexes[callback.ordinal()];
         }
@@ -2310,4 +2320,8 @@
      */
     public static class SideActivity extends Activity {
     }
+
+    /** Activity that can handle all config changes. */
+    public static class ConfigChangeHandlingActivity extends CommandSession.BasicTestActivity {
+    }
 }
diff --git a/tests/inputmethod/mockime/Android.bp b/tests/inputmethod/mockime/Android.bp
index f4faf83..c73f870 100644
--- a/tests/inputmethod/mockime/Android.bp
+++ b/tests/inputmethod/mockime/Android.bp
@@ -24,6 +24,7 @@
     libs: ["junit"],
     static_libs: [
         "androidx.annotation_annotation",
+        "androidx.autofill_autofill",
         "compatibility-device-util-axt",
     ],
 }
diff --git a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
index a3f6118..f6bf355 100644
--- a/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
+++ b/tests/inputmethod/mockime/src/com/android/cts/mockime/MockIme.java
@@ -71,6 +71,9 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
+import androidx.autofill.inline.UiVersions;
+import androidx.autofill.inline.UiVersions.StylesBuilder;
+import androidx.autofill.inline.v1.InlineSuggestionUi;
 
 import java.util.ArrayList;
 import java.util.concurrent.ExecutorService;
@@ -724,12 +727,15 @@
     @MainThread
     @Override
     public InlineSuggestionsRequest onCreateInlineSuggestionsRequest(Bundle uiExtras) {
+        StylesBuilder stylesBuilder = UiVersions.newStylesBuilder();
+        stylesBuilder.addStyle(InlineSuggestionUi.newStyleBuilder().build());
+        Bundle styles = stylesBuilder.build();
         return getTracer().onCreateInlineSuggestionsRequest(() -> {
             final ArrayList<InlinePresentationSpec> presentationSpecs = new ArrayList<>();
             presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
-                    new Size(400, 100)).build());
+                    new Size(400, 100)).setStyle(styles).build());
             presentationSpecs.add(new InlinePresentationSpec.Builder(new Size(100, 100),
-                    new Size(400, 100)).build());
+                    new Size(400, 100)).setStyle(styles).build());
 
             return new InlineSuggestionsRequest.Builder(presentationSpecs)
                     .setMaxSuggestionCount(6)
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionBlockingMethodTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionBlockingMethodTest.java
index dc335ce..a412e7a 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionBlockingMethodTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputConnectionBlockingMethodTest.java
@@ -41,6 +41,7 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionWrapper;
 import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.cts.util.EndToEndImeTestBase;
 import android.view.inputmethod.cts.util.TestActivity;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -62,6 +63,7 @@
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Function;
 
 /**
@@ -69,7 +71,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class InputConnectionBlockingMethodTest {
+public class InputConnectionBlockingMethodTest extends EndToEndImeTestBase {
     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
     private static final long LONG_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
     private static final long IMMEDIATE_TIMEOUT_NANO = TimeUnit.MILLISECONDS.toNanos(200);
@@ -184,35 +186,42 @@
                      InstrumentationRegistry.getInstrumentation().getContext(),
                      InstrumentationRegistry.getInstrumentation().getUiAutomation(),
                      new ImeSettings.Builder())) {
-            final ImeEventStream stream = imeSession.openEventStream();
+            final AtomicBoolean isTestRunning = new AtomicBoolean(true);
+            try {
+                final ImeEventStream stream = imeSession.openEventStream();
 
-            final String marker = getTestMarker();
-            TestActivity.startSync(activity-> {
-                final LinearLayout layout = new LinearLayout(activity);
-                layout.setOrientation(LinearLayout.VERTICAL);
-                final EditText editText = new EditText(activity) {
-                    @Override
-                    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-                        return inputConnectionWrapperProvider.apply(
-                                super.onCreateInputConnection(outAttrs));
-                    }
-                };
-                editText.setPrivateImeOptions(marker);
-                editText.setHint("editText");
-                editText.requestFocus();
+                final String marker = getTestMarker();
+                TestActivity.startSync(activity -> {
+                    final LinearLayout layout = new LinearLayout(activity);
+                    layout.setOrientation(LinearLayout.VERTICAL);
+                    final EditText editText = new EditText(activity) {
+                        @Override
+                        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+                            final InputConnection ic = super.onCreateInputConnection(outAttrs);
+                            // Fall back to the original InputConnection once the test is done.
+                            return isTestRunning.get()
+                                    ? inputConnectionWrapperProvider.apply(ic) : ic;
+                        }
+                    };
+                    editText.setPrivateImeOptions(marker);
+                    editText.setHint("editText");
+                    editText.requestFocus();
 
-                layout.addView(editText);
-                activity.getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
-                return layout;
-            });
+                    layout.addView(editText);
+                    activity.getWindow().setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+                    return layout;
+                });
 
-            // Wait until the MockIme gets bound to the TestActivity.
-            expectBindInput(stream, Process.myPid(), TIMEOUT);
+                // Wait until the MockIme gets bound to the TestActivity.
+                expectBindInput(stream, Process.myPid(), TIMEOUT);
 
-            // Wait until "onStartInput" gets called for the EditText.
-            expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
+                // Wait until "onStartInput" gets called for the EditText.
+                expectEvent(stream, editorMatcher("onStartInput", marker), TIMEOUT);
 
-            testProcedure.run(imeSession, stream);
+                testProcedure.run(imeSession, stream);
+            } finally {
+                isTestRunning.set(false);
+            }
         }
     }
 
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodStartInputLifecycleTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodStartInputLifecycleTest.java
index 1dd20d0..23f32ce 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodStartInputLifecycleTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InputMethodStartInputLifecycleTest.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.cts.util.DisableScreenDozeRule;
+import android.view.inputmethod.cts.util.EndToEndImeTestBase;
 import android.view.inputmethod.cts.util.TestActivity;
 import android.view.inputmethod.cts.util.TestUtils;
 import android.view.inputmethod.cts.util.UnlockScreenRule;
@@ -46,6 +47,7 @@
 
 import com.android.compatibility.common.util.CtsTouchUtils;
 import com.android.cts.mockime.ImeCommand;
+import com.android.cts.mockime.ImeEvent;
 import com.android.cts.mockime.ImeEventStream;
 import com.android.cts.mockime.ImeSettings;
 import com.android.cts.mockime.MockImeSession;
@@ -57,10 +59,11 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
 
 @MediumTest
 @RunWith(AndroidJUnit4.class)
-public class InputMethodStartInputLifecycleTest {
+public class InputMethodStartInputLifecycleTest extends EndToEndImeTestBase {
     @Rule
     public final DisableScreenDozeRule mDisableScreenDozeRule = new DisableScreenDozeRule();
     @Rule
@@ -115,8 +118,7 @@
             TestUtils.turnScreenOff();
             TestUtils.waitOnMainUntil(() -> screenStateCallbackRef.get() == SCREEN_STATE_OFF
                             && editText.getWindowVisibility() != VISIBLE, TIMEOUT);
-            assertTrue(TestUtils.getOnMainSync(
-                    () -> !imManager.isActive(editText) && !imManager.isAcceptingText()));
+            expectEvent(stream, onFinishInputMatcher(), TIMEOUT);
             final ImeCommand commit = imeSession.callCommitText("Hi!", 1);
             expectCommand(stream, commit, TIMEOUT);
             TestUtils.waitOnMainUntil(() -> !TextUtils.equals(editText.getText(), "Hi!"), TIMEOUT,
@@ -137,4 +139,8 @@
                     "InputMethodService#commitText should work after screen on");
         }
     }
+
+    private static Predicate<ImeEvent> onFinishInputMatcher() {
+        return event -> TextUtils.equals("onFinishInput", event.getEventName());
+    }
 }
diff --git a/tests/media/jni/NativeCodecDecoderTest.cpp b/tests/media/jni/NativeCodecDecoderTest.cpp
index d5eb85b..8dace62 100644
--- a/tests/media/jni/NativeCodecDecoderTest.cpp
+++ b/tests/media/jni/NativeCodecDecoderTest.cpp
@@ -341,8 +341,6 @@
             CHECK_ERR(hasSeenError(), log, "has seen error", isPass);
             CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
             CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
-            CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
-                      isPass);
             CHECK_ERR(loopCounter != 0 && (!ref->equals(test)), log, "output is flaky", isPass);
             CHECK_ERR(
                     loopCounter == 0 && mIsAudio && (!ref->isPtsStrictlyIncreasing(mPrevOutputPts)),
@@ -462,8 +460,6 @@
         CHECK_ERR(hasSeenError(), log, "has seen error", isPass);
         CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
         CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
-        CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
-                  isPass);
         CHECK_ERR((!ref->equals(test)), log, "output is flaky", isPass);
         if (!isPass) continue;
 
@@ -483,8 +479,6 @@
         CHECK_ERR(hasSeenError(), log, "has seen error", isPass);
         CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
         CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
-        CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log, "input cnt != output cnt",
-                  isPass);
         CHECK_ERR((!ref->equals(test)), log, "output is flaky", isPass);
         if (validateFormat) {
             if (mIsCodecInAsyncMode ? !mAsyncHandle.hasOutputFormatChanged()
@@ -611,8 +605,6 @@
                 CHECK_ERR(hasSeenError(), log, "has seen error", isPass);
                 CHECK_ERR((0 == mInputCount), log, "queued 0 inputs", isPass);
                 CHECK_ERR((0 == mOutputCount), log, "received 0 outputs", isPass);
-                CHECK_ERR((!mIsAudio && mInputCount != mOutputCount), log,
-                          "input cnt != output cnt", isPass);
                 CHECK_ERR(loopCounter != 0 && (!ref->equals(test)), log, "output is flaky", isPass);
                 CHECK_ERR(loopCounter == 0 && mIsAudio &&
                           (!ref->isPtsStrictlyIncreasing(mPrevOutputPts)),
diff --git a/tests/media/jni/NativeCodecTestBase.h b/tests/media/jni/NativeCodecTestBase.h
index 65f4111..b730fb0 100644
--- a/tests/media/jni/NativeCodecTestBase.h
+++ b/tests/media/jni/NativeCodecTestBase.h
@@ -92,7 +92,12 @@
     uint32_t adler32(const uint8_t* input, int offset, int len);
 
   public:
-    void saveInPTS(int64_t pts) { inpPtsArray.push_back(pts); }
+    void saveInPTS(int64_t pts) {
+        // Add only Unique timeStamp, discarding any duplicate frame / non-display frame
+        if(0 == std::count(inpPtsArray.begin(), inpPtsArray.end(), pts)) {
+            inpPtsArray.push_back(pts);
+        }
+    }
     void saveOutPTS(int64_t pts) { outPtsArray.push_back(pts); }
     bool isPtsStrictlyIncreasing(int64_t lastPts);
     bool isOutPtsListIdenticalToInpPtsList(bool requireSorting);
diff --git a/tests/media/jni/NativeMuxerTest.cpp b/tests/media/jni/NativeMuxerTest.cpp
index 9e759bc..b4e7858 100644
--- a/tests/media/jni/NativeMuxerTest.cpp
+++ b/tests/media/jni/NativeMuxerTest.cpp
@@ -66,14 +66,14 @@
 
     bool combineMedias(AMediaMuxer* muxer, MuxerNativeTestHelper* that, const int* repeater);
 
-    bool equals(MuxerNativeTestHelper* that);
+    bool isSubsetOf(MuxerNativeTestHelper* that);
 
     void offsetTimeStamp(int trackID, long tsOffset, int sampleOffset);
 
   private:
     void splitMediaToMuxerParameters();
 
-    static const int STTS_TOLERANCE = 100;
+    static const int STTS_TOLERANCE_US = 100;
     const char* mSrcPath;
     const char* mMime;
     int mTrackCount;
@@ -263,7 +263,7 @@
 
 // returns true if 'this' stream is a subset of 'o'. That is all tracks in current media
 // stream are present in ref media stream
-bool MuxerNativeTestHelper::equals(MuxerNativeTestHelper* that) {
+bool MuxerNativeTestHelper::isSubsetOf(MuxerNativeTestHelper* that) {
     if (this == that) return true;
     if (that == nullptr) return false;
 
@@ -279,31 +279,27 @@
             if (thisMime != nullptr && thatMime != nullptr && !strcmp(thisMime, thatMime)) {
                 if (!isCSDIdentical(thisFormat, thatFormat)) continue;
                 if (mBufferInfo[i].size() == that->mBufferInfo[j].size()) {
-                    int flagsDiff = 0, sizeDiff = 0, tsDiff = 0, buffDiff = 0;
-                    for (int k = 0; k < mBufferInfo[i].size(); k++) {
+                    int tolerance =
+                            strncmp(thisMime, "video/", strlen("video/")) ? 0 : STTS_TOLERANCE_US;
+                    int k = 0;
+                    for (; k < mBufferInfo[i].size(); k++) {
                         AMediaCodecBufferInfo* thisInfo = mBufferInfo[i][k];
                         AMediaCodecBufferInfo* thatInfo = that->mBufferInfo[j][k];
                         if (thisInfo->flags != thatInfo->flags) {
-                            flagsDiff++;
+                            break;
                         }
                         if (thisInfo->size != thatInfo->size) {
-                            sizeDiff++;
+                            break;
                         } else if (memcmp(mBuffer + thisInfo->offset,
                                           that->mBuffer + thatInfo->offset, thisInfo->size)) {
-                            buffDiff++;
+                            break;
                         }
                         if (abs(thisInfo->presentationTimeUs - thatInfo->presentationTimeUs) >
-                            STTS_TOLERANCE) {
-                            tsDiff++;
+                            tolerance) {
+                            break;
                         }
                     }
-                    if (flagsDiff == 0 && sizeDiff == 0 && tsDiff == 0 && buffDiff == 0)
-                        break;
-                    else {
-                        ALOGV("For mime %s, Total Samples %d, flagsDiff %d, sizeDiff %d, tsDiff "
-                              "%d, buffDiff %d", thisMime, (int)mBufferInfo[i].size(), flagsDiff,
-                              sizeDiff, tsDiff, buffDiff);
-                    }
+                    if (k == mBufferInfo[i].size()) break;
                 }
             }
         }
@@ -524,7 +520,7 @@
             fclose(rfp);
             if (muxStatus) {
                 auto* refInfo = new MuxerNativeTestHelper(crefPath);
-                if (!mediaInfoA->equals(refInfo) || !mediaInfoB->equals(refInfo)) {
+                if (!mediaInfoA->isSubsetOf(refInfo) || !mediaInfoB->isSubsetOf(refInfo)) {
                     isPass = false;
                     ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing src A and src B "
                           "failed", csrcPathA, csrcPathB, jformat);
@@ -540,7 +536,7 @@
                             fclose(ofp);
                             if (status) {
                                 auto* dstInfo = new MuxerNativeTestHelper(cdstPath);
-                                if (!dstInfo->equals(refInfo)) {
+                                if (!dstInfo->isSubsetOf(refInfo)) {
                                     isPass = false;
                                     ALOGE("testMultiTrack: inputs: %s %s, fmt: %d, error ! muxing "
                                           "src A: %d, src B: %d failed", csrcPathA, csrcPathB,
@@ -614,7 +610,7 @@
                 AMediaMuxer_delete(muxer);
                 fclose(ofp);
                 auto* outInfo = new MuxerNativeTestHelper(cdstPath);
-                isPass = mediaInfo->equals(outInfo);
+                isPass = mediaInfo->isSubsetOf(outInfo);
                 if (!isPass) {
                     ALOGE("Validation failed after adding timestamp offset to track %d", trackID);
                 }
@@ -668,7 +664,7 @@
                 fclose(ofp);
                 if (muxStatus) {
                     auto* outInfo = new MuxerNativeTestHelper(cdstPath, cmime);
-                    result = mediaInfo->equals(outInfo);
+                    result = mediaInfo->isSubsetOf(outInfo);
                     delete outInfo;
                 }
                 if ((muxStatus && !result) ||
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderExtTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderExtTest.java
new file mode 100644
index 0000000..e57b3e7
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderExtTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.mediav2.cts;
+
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(Parameterized.class)
+public class CodecDecoderExtTest extends CodecDecoderTestBase {
+    private static final String LOG_TAG = CodecDecoderExtTest.class.getSimpleName();
+
+    private final String mRefFile;
+
+    public CodecDecoderExtTest(String mime, String testFile, String refFile) {
+        super(mime, testFile);
+        mRefFile = refFile;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0})")
+    public static Collection<Object[]> input() {
+        return Arrays.asList(new Object[][]{
+                {MediaFormat.MIMETYPE_VIDEO_VP9,
+                        //show and no-show frames are sent as separate inputs
+                        "bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.webm",
+                        //show and no-show frames are sent as one input
+                        "bbb_340x280_768kbps_30fps_vp9.webm"},
+                {MediaFormat.MIMETYPE_VIDEO_VP9,
+                        //show and no-show frames are sent as separate inputs
+                        "bbb_520x390_1mbps_30fps_split_non_display_frame_vp9.webm",
+                        //show and no-show frames are sent as one input
+                        "bbb_520x390_1mbps_30fps_vp9.webm"},
+        });
+    }
+
+    /**
+     * Test decodes and compares decoded output of two files.
+     */
+    @LargeTest
+    @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
+    public void testDecodeAndValidate() throws IOException, InterruptedException {
+        ArrayList<String> listOfDecoders = selectCodecs(mMime, null, null, false);
+        if (listOfDecoders.isEmpty()) {
+            fail("no suitable codecs found for mime: " + mMime);
+        }
+        final int mode = MediaExtractor.SEEK_TO_CLOSEST_SYNC;
+        for (String decoder : listOfDecoders) {
+            decodeToMemory(mTestFile, decoder, 0, mode, Integer.MAX_VALUE);
+            OutputManager test = mOutputBuff;
+            String log = String.format("codec: %s, test file: %s, ref file: %s:: ", decoder,
+                    mTestFile, mRefFile);
+            assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
+            assertTrue(log + "no input sent", 0 != mInputCount);
+            assertTrue(log + "output received", 0 != mOutputCount);
+            if (mIsAudio) {
+                assertTrue("reference output pts is not strictly increasing",
+                        test.isPtsStrictlyIncreasing(mPrevOutputPts));
+            } else {
+                assertTrue("input pts list and output pts list are not identical",
+                        test.isOutPtsListIdenticalToInpPtsList(false));
+            }
+            decodeToMemory(mRefFile, decoder, 0, mode, Integer.MAX_VALUE);
+            OutputManager ref = mOutputBuff;
+            assertTrue(log + "decoder outputs are not identical", ref.equals(test));
+        }
+    }
+}
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
index 5d1bc41..58d83c9 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderSurfaceTest.java
@@ -21,7 +21,6 @@
 import android.media.MediaFormat;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.Pair;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.ViewGroup;
@@ -36,7 +35,6 @@
 import org.junit.runners.Parameterized;
 
 import java.io.IOException;
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -44,31 +42,19 @@
 import java.util.List;
 import java.util.Set;
 
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 @RunWith(Parameterized.class)
-public class CodecDecoderSurfaceTest extends CodecTestBase {
+public class CodecDecoderSurfaceTest extends CodecDecoderTestBase {
     private static final String LOG_TAG = CodecDecoderSurfaceTest.class.getSimpleName();
 
-    private final String mMime;
-    private final String mTestFile;
     private final String mReconfigFile;
-
-    private final ArrayList<ByteBuffer> mCsdBuffers;
-    private int mCurrCsdIdx;
-
-    private MediaExtractor mExtractor;
     private SurfaceView mSurfaceView;
 
     public CodecDecoderSurfaceTest(String mime, String testFile, String reconfigFile) {
-        mMime = mime;
-        mTestFile = testFile;
+        super(mime, testFile);
         mReconfigFile = reconfigFile;
-        mCsdBuffers = new ArrayList<>();
-        mAsyncHandle = new CodecAsyncHandler();
-        mIsAudio = mMime.startsWith("audio/");
     }
 
     private void setScreenParams(int width, int height, boolean noStretch) {
@@ -92,85 +78,6 @@
         mActivityRule.getActivity().runOnUiThread(() -> mSurfaceView.setLayoutParams(lp));
     }
 
-    private MediaFormat setUpSource(String srcFile) throws IOException {
-        mExtractor = new MediaExtractor();
-        mExtractor.setDataSource(mInpPrefix + srcFile);
-        for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
-            MediaFormat format = mExtractor.getTrackFormat(trackID);
-            if (mMime.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))) {
-                mExtractor.selectTrack(trackID);
-                if (!mIsAudio) {
-                    // COLOR_FormatYUV420Flexible by default should be supported by all components
-                    // This call shouldn't effect configure() call for any codec
-                    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
-                }
-                return format;
-            }
-        }
-        fail("No track with mime: " + mMime + " found in file: " + srcFile);
-        return null;
-    }
-
-    private void enqueueCodecConfig(int bufferIndex) {
-        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-        ByteBuffer csdBuffer = mCsdBuffers.get(mCurrCsdIdx);
-        inputBuffer.put((ByteBuffer) csdBuffer.rewind());
-        mCodec.queueInputBuffer(bufferIndex, 0, csdBuffer.limit(), 0,
-                MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "queued csd: id: " + bufferIndex + " size: " + csdBuffer.limit());
-        }
-    }
-
-    private void queueCodecConfig() throws InterruptedException {
-        if (mIsCodecInAsyncMode) {
-            for (mCurrCsdIdx = 0; !mAsyncHandle.hasSeenError() && mCurrCsdIdx < mCsdBuffers.size();
-                 mCurrCsdIdx++) {
-                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getInput();
-                if (element != null) {
-                    enqueueCodecConfig(element.first);
-                }
-            }
-        } else {
-            for (mCurrCsdIdx = 0; mCurrCsdIdx < mCsdBuffers.size(); mCurrCsdIdx++) {
-                enqueueCodecConfig(mCodec.dequeueInputBuffer(-1));
-            }
-        }
-    }
-
-    void enqueueInput(int bufferIndex) {
-        if (mExtractor.getSampleSize() < 0) {
-            enqueueEOS(bufferIndex);
-        } else {
-            ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-            mExtractor.readSampleData(inputBuffer, 0);
-            int size = (int) mExtractor.getSampleSize();
-            long pts = mExtractor.getSampleTime();
-            int extractorFlags = mExtractor.getSampleFlags();
-            int codecFlags = 0;
-            if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
-                codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
-            }
-            if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
-                codecFlags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
-            }
-            if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
-                codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                mSawInputEOS = true;
-            }
-            if (ENABLE_LOGS) {
-                Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
-                        " flags: " + codecFlags);
-            }
-            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
-            if (size > 0 && (codecFlags & (MediaCodec.BUFFER_FLAG_CODEC_CONFIG |
-                    MediaCodec.BUFFER_FLAG_PARTIAL_FRAME)) == 0) {
-                mOutputBuff.saveInPTS(pts);
-                mInputCount++;
-            }
-        }
-    }
-
     void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
             mSawOutputEOS = true;
@@ -261,6 +168,9 @@
                         "bbb_520x390_1mbps_30fps_vp8.webm"},
                 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_340x280_768kbps_30fps_vp9.webm",
                         "bbb_520x390_1mbps_30fps_vp9.webm"},
+                {MediaFormat.MIMETYPE_VIDEO_VP9,
+                        "bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.webm",
+                        "bbb_520x390_1mbps_30fps_split_non_display_frame_vp9.webm"},
                 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_340x280_768kbps_30fps_av1.mp4",
                         "bbb_520x390_1mbps_30fps_av1.mp4"},
         });
@@ -309,8 +219,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                assertTrue(log + "input count != output count, act/exp: " + mOutputCount + " / " +
-                        mInputCount, mInputCount == mOutputCount);
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
             }
             mCodec.release();
@@ -389,8 +297,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                assertTrue(log + "input count != output count, act/exp: " + mOutputCount + " / "
-                        + mInputCount, mInputCount == mOutputCount);
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
 
                 /* test flush in eos state */
@@ -407,8 +313,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                assertTrue(log + "input count != output count, act/exp: " + mOutputCount + " / "
-                        + mInputCount, mInputCount == mOutputCount);
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
             }
             mCodec.release();
@@ -481,10 +385,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
 
                 /* test reconfigure codec at eos state */
@@ -501,10 +401,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
                 mExtractor.release();
 
@@ -526,10 +422,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", configRef.equals(test));
                 mExtractor.release();
             }
diff --git a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
index ca05d0e..1daf63f 100644
--- a/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecDecoderTest.java
@@ -16,14 +16,11 @@
 
 package android.mediav2.cts;
 
-import android.media.Image;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
-import android.os.PersistableBundle;
 import android.util.Log;
-import android.util.Pair;
 import android.view.Surface;
 
 import androidx.test.filters.LargeTest;
@@ -48,7 +45,6 @@
 import java.util.List;
 import java.util.Set;
 
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -62,30 +58,19 @@
  * of these tests are not to cover CDD requirements but to test components and their plugins
  */
 @RunWith(Parameterized.class)
-public class CodecDecoderTest extends CodecTestBase {
+public class CodecDecoderTest extends CodecDecoderTestBase {
     private static final String LOG_TAG = CodecDecoderTest.class.getSimpleName();
 
-    private final String mMime;
-    private final String mTestFile;
     private final String mRefFile;
     private final String mReconfigFile;
     private final float mRmsError;
 
-    private ArrayList<ByteBuffer> mCsdBuffers;
-    private int mCurrCsdIdx;
-
-    private MediaExtractor mExtractor;
-
     public CodecDecoderTest(String mime, String testFile, String refFile, String reconfigFile,
             float rmsError) {
-        mMime = mime;
-        mTestFile = testFile;
+        super(mime, testFile);
         mRefFile = refFile;
         mReconfigFile = reconfigFile;
         mRmsError = rmsError;
-        mAsyncHandle = new CodecAsyncHandler();
-        mCsdBuffers = new ArrayList<>();
-        mIsAudio = mMime.startsWith("audio/");
     }
 
     private short[] setUpAudioReference() throws IOException {
@@ -106,164 +91,6 @@
         return refData;
     }
 
-    private MediaFormat setUpSource(String srcFile) throws IOException {
-        mExtractor = new MediaExtractor();
-        mExtractor.setDataSource(mInpPrefix + srcFile);
-        for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
-            MediaFormat format = mExtractor.getTrackFormat(trackID);
-            if (mMime.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))) {
-                mExtractor.selectTrack(trackID);
-                if (!mIsAudio) {
-                    // COLOR_FormatYUV420Flexible by default should be supported by all components
-                    // This call shouldn't effect configure() call for any codec
-                    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
-                }
-                return format;
-            }
-        }
-        fail("No track with mime: " + mMime + " found in file: " + srcFile);
-        return null;
-    }
-
-    private boolean hasCSD(MediaFormat format) {
-        return format.containsKey("csd-0");
-    }
-
-    private void enqueueCodecConfig(int bufferIndex) {
-        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-        ByteBuffer csdBuffer = mCsdBuffers.get(mCurrCsdIdx);
-        inputBuffer.put((ByteBuffer) csdBuffer.rewind());
-        mCodec.queueInputBuffer(bufferIndex, 0, csdBuffer.limit(), 0,
-                MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "queued csd: id: " + bufferIndex + " size: " + csdBuffer.limit());
-        }
-    }
-
-    void enqueueInput(int bufferIndex) {
-        if (mExtractor.getSampleSize() < 0) {
-            enqueueEOS(bufferIndex);
-        } else {
-            ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-            mExtractor.readSampleData(inputBuffer, 0);
-            int size = (int) mExtractor.getSampleSize();
-            long pts = mExtractor.getSampleTime();
-            int extractorFlags = mExtractor.getSampleFlags();
-            int codecFlags = 0;
-            if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
-                codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
-            }
-            if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
-                codecFlags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
-            }
-            if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
-                codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                mSawInputEOS = true;
-            }
-            if (ENABLE_LOGS) {
-                Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
-                        " flags: " + codecFlags);
-            }
-            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
-            if (size > 0 && (codecFlags & (MediaCodec.BUFFER_FLAG_CODEC_CONFIG |
-                    MediaCodec.BUFFER_FLAG_PARTIAL_FRAME)) == 0) {
-                mOutputBuff.saveInPTS(pts);
-                mInputCount++;
-            }
-        }
-    }
-
-    private void enqueueInput(int bufferIndex, ByteBuffer buffer, MediaCodec.BufferInfo info) {
-        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-        inputBuffer.put((ByteBuffer) buffer.rewind());
-        int flags = 0;
-        if ((info.flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
-            flags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
-        }
-        if ((info.flags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
-            flags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
-        }
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "input: id: " + bufferIndex + " flags: " + info.flags + " size: " +
-                    info.size + " timestamp: " + info.presentationTimeUs);
-        }
-        mCodec.queueInputBuffer(bufferIndex, info.offset, info.size, info.presentationTimeUs,
-                flags);
-        if (info.size > 0 && ((flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) &&
-                ((flags & MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) == 0)) {
-            mOutputBuff.saveInPTS(info.presentationTimeUs);
-            mInputCount++;
-        }
-    }
-
-    void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
-        if (info.size > 0 && mSaveToMem) {
-            if (mIsAudio) {
-                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
-                mOutputBuff.saveToMemory(buf, info);
-            } else {
-                // tests both getOutputImage and getOutputBuffer. Can do time division
-                // multiplexing but lets allow it for now
-                Image img = mCodec.getOutputImage(bufferIndex);
-                assertTrue(img != null);
-                mOutputBuff.checksum(img);
-
-                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
-                mOutputBuff.checksum(buf, info.size);
-            }
-        }
-        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-            mSawOutputEOS = true;
-        }
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
-                    info.size + " timestamp: " + info.presentationTimeUs);
-        }
-        if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
-            mOutputBuff.saveOutPTS(info.presentationTimeUs);
-            mOutputCount++;
-        }
-        mCodec.releaseOutputBuffer(bufferIndex, false);
-    }
-
-    private void doWork(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list)
-            throws InterruptedException {
-        int frameCount = 0;
-        if (mIsCodecInAsyncMode) {
-            // output processing after queuing EOS is done in waitForAllOutputs()
-            while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < list.size()) {
-                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
-                if (element != null) {
-                    int bufferID = element.first;
-                    MediaCodec.BufferInfo info = element.second;
-                    if (info != null) {
-                        dequeueOutput(bufferID, info);
-                    } else {
-                        enqueueInput(bufferID, buffer, list.get(frameCount));
-                        frameCount++;
-                    }
-                }
-            }
-        } else {
-            MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
-            // output processing after queuing EOS is done in waitForAllOutputs()
-            while (!mSawInputEOS && frameCount < list.size()) {
-                int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
-                if (outputBufferId >= 0) {
-                    dequeueOutput(outputBufferId, outInfo);
-                } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
-                    mOutFormat = mCodec.getOutputFormat();
-                    mSignalledOutFormatChanged = true;
-                }
-                int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
-                if (inputBufferId != -1) {
-                    enqueueInput(inputBufferId, buffer, list.get(frameCount));
-                    frameCount++;
-                }
-            }
-        }
-    }
-
     private ArrayList<MediaCodec.BufferInfo> createSubFrames(ByteBuffer buffer, int sfCount) {
         int size = (int) mExtractor.getSampleSize();
         if (size < 0) return null;
@@ -290,48 +117,6 @@
         return list;
     }
 
-    private void queueCodecConfig() throws InterruptedException {
-        if (mIsCodecInAsyncMode) {
-            for (mCurrCsdIdx = 0; !mAsyncHandle.hasSeenError() && mCurrCsdIdx < mCsdBuffers.size();
-                 mCurrCsdIdx++) {
-                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getInput();
-                if (element != null) {
-                    enqueueCodecConfig(element.first);
-                }
-            }
-        } else {
-            for (mCurrCsdIdx = 0; mCurrCsdIdx < mCsdBuffers.size(); mCurrCsdIdx++) {
-                enqueueCodecConfig(mCodec.dequeueInputBuffer(-1));
-            }
-        }
-    }
-
-    private void decodeToMemory(String file, String decoder, long pts, int mode, int frameLimit)
-            throws IOException, InterruptedException {
-        mSaveToMem = true;
-        mOutputBuff = new OutputManager();
-        mCodec = MediaCodec.createByCodecName(decoder);
-        MediaFormat format = setUpSource(file);
-        configureCodec(format, false, true, false);
-        mCodec.start();
-        mExtractor.seekTo(pts, mode);
-        doWork(frameLimit);
-        queueEOS();
-        waitForAllOutputs();
-        mCodec.stop();
-        mCodec.release();
-        mExtractor.release();
-        mSaveToMem = false;
-    }
-
-    @Override
-    PersistableBundle validateMetrics(String decoder, MediaFormat format) {
-        PersistableBundle metrics = super.validateMetrics(decoder, format);
-        assertTrue(metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE).equals(mMime));
-        assertTrue(metrics.getInt(MediaCodec.MetricsConstants.ENCODER) == 0);
-        return metrics;
-    }
-
     @Parameterized.Parameters(name = "{index}({0})")
     public static Collection<Object[]> input() {
         Set<String> list = new HashSet<>();
@@ -417,6 +202,9 @@
                         "bbb_520x390_1mbps_30fps_vp8.webm", -1.0f},
                 {MediaFormat.MIMETYPE_VIDEO_VP9, "bbb_340x280_768kbps_30fps_vp9.webm", null,
                         "bbb_520x390_1mbps_30fps_vp9.webm", -1.0f},
+                {MediaFormat.MIMETYPE_VIDEO_VP9,
+                        "bbb_340x280_768kbps_30fps_split_non_display_frame_vp9.webm", null,
+                        "bbb_520x390_1mbps_30fps_split_non_display_frame_vp9.webm", -1.0f},
                 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_340x280_768kbps_30fps_av1.mp4", null,
                         "bbb_520x390_1mbps_30fps_av1.mp4", -1.0f},
         });
@@ -481,10 +269,6 @@
                     assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                     assertTrue(log + "no input sent", 0 != mInputCount);
                     assertTrue(log + "output received", 0 != mOutputCount);
-                    if (!mIsAudio) {
-                        assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                                " / " + mInputCount, mInputCount == mOutputCount);
-                    }
                     if (loopCounter != 0) {
                         assertTrue(log + "decoder output is flaky", ref.equals(test));
                     } else {
@@ -620,10 +404,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
 
                 /* test flush in eos state */
@@ -640,10 +420,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
                 if (validateFormat) {
                     assertTrue(log + "not received format change",
@@ -767,10 +543,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
                 if (validateFormat) {
                     assertTrue(log + "not received format change",
@@ -796,10 +568,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", ref.equals(test));
                 if (validateFormat) {
                     assertTrue(log + "not received format change",
@@ -836,10 +604,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is flaky", configRef.equals(test));
                 if (validateFormat) {
                     assertTrue(log + "not received format change",
@@ -980,11 +744,6 @@
                         assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                         assertTrue(log + "no input sent", 0 != mInputCount);
                         assertTrue(log + "output received", 0 != mOutputCount);
-                        if (!mIsAudio) {
-                            assertTrue(
-                                    log + "input count != output count, act/exp: " + mOutputCount +
-                                            " / " + mInputCount, mInputCount == mOutputCount);
-                        }
                         if (loopCounter != 0) {
                             assertTrue(log + "decoder output is flaky", ref.equals(test));
                         } else {
@@ -1079,10 +838,6 @@
                 assertTrue(log + " unexpected error", !mAsyncHandle.hasSeenError());
                 assertTrue(log + "no input sent", 0 != mInputCount);
                 assertTrue(log + "output received", 0 != mOutputCount);
-                if (!mIsAudio) {
-                    assertTrue(log + "input count != output count, act/exp: " + mOutputCount +
-                            " / " + mInputCount, mInputCount == mOutputCount);
-                }
                 assertTrue(log + "decoder output is not consistent with ref", ref.equals(test));
             }
             mCodec.release();
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
index d6caa62..180e063 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
@@ -338,15 +338,21 @@
     }
 
     private void queueEOS() throws InterruptedException {
-        if (!mSawDecInputEOS) {
-            if (mIsCodecInAsyncMode) {
-                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getInput();
+        if (mIsCodecInAsyncMode) {
+            while (!mAsyncHandleDecoder.hasSeenError() && !mSawDecInputEOS) {
+                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandleDecoder.getWork();
                 if (element != null) {
-                    enqueueDecoderEOS(element.first);
+                    int bufferID = element.first;
+                    MediaCodec.BufferInfo info = element.second;
+                    if (info != null) {
+                        dequeueDecoderOutput(bufferID, info);
+                    } else {
+                        enqueueDecoderEOS(element.first);
+                    }
                 }
-            } else {
-                enqueueDecoderEOS(mDecoder.dequeueInputBuffer(-1));
             }
+        } else if (!mSawDecInputEOS) {
+            enqueueDecoderEOS(mDecoder.dequeueInputBuffer(-1));
         }
         if (mIsCodecInAsyncMode) {
             while (!hasSeenError() && !mSawDecOutputEOS) {
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
index 6a4c7d9..79d8f20 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
@@ -60,53 +60,27 @@
  * of these tests are not to cover CDD requirements but to test components and their plugins
  */
 @RunWith(Parameterized.class)
-public class CodecEncoderTest extends CodecTestBase {
+public class CodecEncoderTest extends CodecEncoderTestBase {
     private static final String LOG_TAG = CodecEncoderTest.class.getSimpleName();
-    // files are in WorkDir.getMediaDirString();
-    private static final String mInputAudioFile = "bbb_2ch_44kHz_s16le.raw";
-    private static final String mInputVideoFile = "bbb_cif_yuv420p_30fps.yuv";
-    private final int INP_FRM_WIDTH = 352;
-    private final int INP_FRM_HEIGHT = 288;
-
-    private final String mMime;
     private final int[] mBitrates;
     private final int[] mEncParamList1;
     private final int[] mEncParamList2;
-    private final String mInputFile;
     private ArrayList<MediaFormat> mFormats;
-    private byte[] mInputData;
-    private int mNumBytesSubmitted;
-    private long mInputOffsetPts;
     private int mNumSyncFramesReceived;
     private ArrayList<Integer> mSyncFramesPos;
 
-    private int mWidth, mHeight;
-    private int mChannels;
-    private int mSampleRate;
-    private int mFrameRate;
-    private int mMaxBFrames;
-
     public CodecEncoderTest(String mime, int[] bitrates, int[] encoderInfo1, int[] encoderInfo2) {
-        mMime = mime;
-        mFrameRate = 30;
-        if (mime.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4)) mFrameRate = 12;
-        else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_H263)) mFrameRate = 12;
-        mMaxBFrames = 0;
+        super(mime);
         mBitrates = bitrates;
         mEncParamList1 = encoderInfo1;
         mEncParamList2 = encoderInfo2;
         mFormats = new ArrayList<>();
         mSyncFramesPos = new ArrayList<>();
-        mAsyncHandle = new CodecAsyncHandler();
-        mIsAudio = mMime.startsWith("audio/");
-        mInputFile = mIsAudio ? mInputAudioFile : mInputVideoFile;
     }
 
     @Override
     void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
         super.resetContext(isAsync, signalEOSWithLastFrame);
-        mNumBytesSubmitted = 0;
-        mInputOffsetPts = 0;
         mNumSyncFramesReceived = 0;
         mSyncFramesPos.clear();
     }
@@ -114,184 +88,16 @@
     @Override
     void flushCodec() {
         super.flushCodec();
-        if (mIsAudio) {
-            mInputOffsetPts =
-                    (mNumBytesSubmitted + 1024) * 1000000L / (2 * mChannels * mSampleRate);
-        } else {
-            mInputOffsetPts = (mInputCount + 5) * 1000000L / mFrameRate;
-        }
-        mPrevOutputPts = mInputOffsetPts - 1;
-        mNumBytesSubmitted = 0;
         mNumSyncFramesReceived = 0;
         mSyncFramesPos.clear();
     }
 
-    private void setUpSource(String srcFile) throws IOException {
-        String inpPath = mInpPrefix + srcFile;
-        try (FileInputStream fInp = new FileInputStream(inpPath)) {
-            int size = (int) new File(inpPath).length();
-            mInputData = new byte[size];
-            fInp.read(mInputData, 0, size);
-        }
-    }
-
-    void fillImage(Image image) {
-        Assert.assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
-        int imageWidth = image.getWidth();
-        int imageHeight = image.getHeight();
-        Image.Plane[] planes = image.getPlanes();
-        int offset = mNumBytesSubmitted;
-        for (int i = 0; i < planes.length; ++i) {
-            ByteBuffer buf = planes[i].getBuffer();
-            int width = imageWidth;
-            int height = imageHeight;
-            int tileWidth = INP_FRM_WIDTH;
-            int tileHeight = INP_FRM_HEIGHT;
-            int rowStride = planes[i].getRowStride();
-            int pixelStride = planes[i].getPixelStride();
-            if (i != 0) {
-                width = imageWidth / 2;
-                height = imageHeight / 2;
-                tileWidth = INP_FRM_WIDTH / 2;
-                tileHeight = INP_FRM_HEIGHT / 2;
-            }
-            if (pixelStride == 1) {
-                if (width == rowStride && width == tileWidth && height == tileHeight) {
-                    buf.put(mInputData, offset, width * height);
-                } else {
-                    for (int z = 0; z < height; z += tileHeight) {
-                        int rowsToCopy = Math.min(height - z, tileHeight);
-                        for (int y = 0; y < rowsToCopy; y++) {
-                            for (int x = 0; x < width; x += tileWidth) {
-                                int colsToCopy = Math.min(width - x, tileWidth);
-                                buf.position((z + y) * rowStride + x);
-                                buf.put(mInputData, offset + y * tileWidth, colsToCopy);
-                            }
-                        }
-                    }
-                }
-            } else {
-                // do it pixel-by-pixel
-                for (int z = 0; z < height; z += tileHeight) {
-                    int rowsToCopy = Math.min(height - z, tileHeight);
-                    for (int y = 0; y < rowsToCopy; y++) {
-                        int lineOffset = (z + y) * rowStride;
-                        for (int x = 0; x < width; x += tileWidth) {
-                            int colsToCopy = Math.min(width - x, tileWidth);
-                            for (int w = 0; w < colsToCopy; w++) {
-                                buf.position(lineOffset + (x + w) * pixelStride);
-                                buf.put(mInputData[offset + y * tileWidth + w]);
-                            }
-                        }
-                    }
-                }
-            }
-            offset += tileWidth * tileHeight;
-        }
-    }
-
-    void fillByteBuffer(ByteBuffer inputBuffer) {
-        int offset = 0, frmOffset = mNumBytesSubmitted;
-        for (int plane = 0; plane < 3; plane++) {
-            int width = mWidth;
-            int height = mHeight;
-            int tileWidth = INP_FRM_WIDTH;
-            int tileHeight = INP_FRM_HEIGHT;
-            if (plane != 0) {
-                width = mWidth / 2;
-                height = mHeight / 2;
-                tileWidth = INP_FRM_WIDTH / 2;
-                tileHeight = INP_FRM_HEIGHT / 2;
-            }
-            for (int k = 0; k < height; k += tileHeight) {
-                int rowsToCopy = Math.min(height - k, tileHeight);
-                for (int j = 0; j < rowsToCopy; j++) {
-                    for (int i = 0; i < width; i += tileWidth) {
-                        int colsToCopy = Math.min(width - i, tileWidth);
-                        inputBuffer.position(offset + (k + j) * width + i);
-                        inputBuffer.put(mInputData, frmOffset + j * tileWidth, colsToCopy);
-                    }
-                }
-            }
-            offset += width * height;
-            frmOffset += tileWidth * tileHeight;
-        }
-    }
-
-    void enqueueInput(int bufferIndex) {
-        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-        if (mNumBytesSubmitted >= mInputData.length) {
-            enqueueEOS(bufferIndex);
-        } else {
-            int size;
-            int flags = 0;
-            long pts = mInputOffsetPts;
-            if (mIsAudio) {
-                pts += mNumBytesSubmitted * 1000000L / (2 * mChannels * mSampleRate);
-                size = Math.min(inputBuffer.capacity(), mInputData.length - mNumBytesSubmitted);
-                inputBuffer.put(mInputData, mNumBytesSubmitted, size);
-                if (mNumBytesSubmitted + size >= mInputData.length && mSignalEOSWithLastFrame) {
-                    flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                    mSawInputEOS = true;
-                }
-                mNumBytesSubmitted += size;
-            } else {
-                pts += mInputCount * 1000000L / mFrameRate;
-                size = mWidth * mHeight * 3 / 2;
-                int frmSize = INP_FRM_WIDTH * INP_FRM_HEIGHT * 3 / 2;
-                if (mNumBytesSubmitted + frmSize > mInputData.length) {
-                    fail("received partial frame to encode");
-                } else {
-                    Image img = mCodec.getInputImage(bufferIndex);
-                    if (img != null) {
-                        fillImage(img);
-                    } else {
-                        if (mWidth == INP_FRM_WIDTH && mHeight == INP_FRM_HEIGHT) {
-                            inputBuffer.put(mInputData, mNumBytesSubmitted, size);
-                        } else {
-                            fillByteBuffer(inputBuffer);
-                        }
-                    }
-                }
-                if (mNumBytesSubmitted + frmSize >= mInputData.length && mSignalEOSWithLastFrame) {
-                    flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                    mSawInputEOS = true;
-                }
-                mNumBytesSubmitted += frmSize;
-            }
-            if (ENABLE_LOGS) {
-                Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
-                        " flags: " + flags);
-            }
-            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
-            mOutputBuff.saveInPTS(pts);
-            mInputCount++;
-        }
-    }
-
     void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
-                    info.size + " timestamp: " + info.presentationTimeUs);
-        }
-        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-            mSawOutputEOS = true;
-        }
-        if (info.size > 0) {
-            if (mSaveToMem) {
-                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
-                mOutputBuff.saveToMemory(buf, info);
-            }
-            if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
-                mOutputBuff.saveOutPTS(info.presentationTimeUs);
-                mOutputCount++;
-            }
-            if ((info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
+        if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
                 mNumSyncFramesReceived += 1;
                 mSyncFramesPos.add(mOutputCount);
             }
-        }
-        mCodec.releaseOutputBuffer(bufferIndex, false);
+        super.dequeueOutput(bufferIndex, info);
     }
 
     private void encodeToMemory(String file, String encoder, int frameLimit, MediaFormat format)
@@ -340,14 +146,6 @@
         return colorFormat;
     }
 
-    @Override
-    PersistableBundle validateMetrics(String codec, MediaFormat format) {
-        PersistableBundle metrics = super.validateMetrics(codec, format);
-        assertTrue(metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE).equals(mMime));
-        assertTrue(metrics.getInt(MediaCodec.MetricsConstants.ENCODER) == 1);
-        return metrics;
-    }
-
     private void forceSyncFrame() {
         final Bundle syncFrame = new Bundle();
         syncFrame.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
diff --git a/tests/media/src/android/mediav2/cts/CodecTestBase.java b/tests/media/src/android/mediav2/cts/CodecTestBase.java
index 3e09a8d..1086981 100644
--- a/tests/media/src/android/mediav2/cts/CodecTestBase.java
+++ b/tests/media/src/android/mediav2/cts/CodecTestBase.java
@@ -22,6 +22,7 @@
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
+import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.os.Build;
 import android.os.PersistableBundle;
@@ -32,6 +33,10 @@
 import androidx.annotation.NonNull;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -47,6 +52,7 @@
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.zip.CRC32;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -212,7 +218,10 @@
     }
 
     void saveInPTS(long pts) {
-        inpPtsList.add(pts);
+        // Add only Unique timeStamp, discarding any duplicate frame / non-display frame
+        if (!inpPtsList.contains(pts)) {
+            inpPtsList.add(pts);
+        }
     }
 
     void saveOutPTS(long pts) {
@@ -680,15 +689,21 @@
     }
 
     void queueEOS() throws InterruptedException {
-        if (!mSawInputEOS) {
-            if (mIsCodecInAsyncMode) {
-                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getInput();
+        if (mIsCodecInAsyncMode) {
+            while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
+                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
                 if (element != null) {
-                    enqueueEOS(element.first);
+                    int bufferID = element.first;
+                    MediaCodec.BufferInfo info = element.second;
+                    if (info != null) {
+                        dequeueOutput(bufferID, info);
+                    } else {
+                        enqueueEOS(element.first);
+                    }
                 }
-            } else {
-                enqueueEOS(mCodec.dequeueInputBuffer(-1));
             }
+        } else if (!mSawInputEOS) {
+            enqueueEOS(mCodec.dequeueInputBuffer(-1));
         }
     }
 
@@ -810,3 +825,454 @@
         return metrics;
     }
 }
+
+class CodecDecoderTestBase extends CodecTestBase {
+    private static final String LOG_TAG = CodecDecoderTestBase.class.getSimpleName();
+
+    String mMime;
+    String mTestFile;
+
+    ArrayList<ByteBuffer> mCsdBuffers;
+    private int mCurrCsdIdx;
+
+    MediaExtractor mExtractor;
+
+    CodecDecoderTestBase(String mime, String testFile) {
+        mMime = mime;
+        mTestFile = testFile;
+        mAsyncHandle = new CodecAsyncHandler();
+        mCsdBuffers = new ArrayList<>();
+        mIsAudio = mMime.startsWith("audio/");
+    }
+
+    MediaFormat setUpSource(String srcFile) throws IOException {
+        mExtractor = new MediaExtractor();
+        mExtractor.setDataSource(mInpPrefix + srcFile);
+        for (int trackID = 0; trackID < mExtractor.getTrackCount(); trackID++) {
+            MediaFormat format = mExtractor.getTrackFormat(trackID);
+            if (mMime.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))) {
+                mExtractor.selectTrack(trackID);
+                if (!mIsAudio) {
+                    // COLOR_FormatYUV420Flexible by default should be supported by all components
+                    // This call shouldn't effect configure() call for any codec
+                    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible);
+                }
+                return format;
+            }
+        }
+        fail("No track with mime: " + mMime + " found in file: " + srcFile);
+        return null;
+    }
+
+    boolean hasCSD(MediaFormat format) {
+        return format.containsKey("csd-0");
+    }
+
+    void enqueueCodecConfig(int bufferIndex) {
+        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+        ByteBuffer csdBuffer = mCsdBuffers.get(mCurrCsdIdx);
+        inputBuffer.put((ByteBuffer) csdBuffer.rewind());
+        mCodec.queueInputBuffer(bufferIndex, 0, csdBuffer.limit(), 0,
+                MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
+        if (ENABLE_LOGS) {
+            Log.v(LOG_TAG, "queued csd: id: " + bufferIndex + " size: " + csdBuffer.limit());
+        }
+    }
+
+    void enqueueInput(int bufferIndex) {
+        if (mExtractor.getSampleSize() < 0) {
+            enqueueEOS(bufferIndex);
+        } else {
+            ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+            mExtractor.readSampleData(inputBuffer, 0);
+            int size = (int) mExtractor.getSampleSize();
+            long pts = mExtractor.getSampleTime();
+            int extractorFlags = mExtractor.getSampleFlags();
+            int codecFlags = 0;
+            if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+                codecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+            }
+            if ((extractorFlags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
+                codecFlags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
+            }
+            if (!mExtractor.advance() && mSignalEOSWithLastFrame) {
+                codecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                mSawInputEOS = true;
+            }
+            if (ENABLE_LOGS) {
+                Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
+                        " flags: " + codecFlags);
+            }
+            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, codecFlags);
+            if (size > 0 && (codecFlags & (MediaCodec.BUFFER_FLAG_CODEC_CONFIG |
+                    MediaCodec.BUFFER_FLAG_PARTIAL_FRAME)) == 0) {
+                mOutputBuff.saveInPTS(pts);
+                mInputCount++;
+            }
+        }
+    }
+
+    void enqueueInput(int bufferIndex, ByteBuffer buffer, MediaCodec.BufferInfo info) {
+        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+        inputBuffer.put((ByteBuffer) buffer.rewind());
+        int flags = 0;
+        if ((info.flags & MediaExtractor.SAMPLE_FLAG_SYNC) != 0) {
+            flags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
+        }
+        if ((info.flags & MediaExtractor.SAMPLE_FLAG_PARTIAL_FRAME) != 0) {
+            flags |= MediaCodec.BUFFER_FLAG_PARTIAL_FRAME;
+        }
+        if (ENABLE_LOGS) {
+            Log.v(LOG_TAG, "input: id: " + bufferIndex + " flags: " + info.flags + " size: " +
+                    info.size + " timestamp: " + info.presentationTimeUs);
+        }
+        mCodec.queueInputBuffer(bufferIndex, info.offset, info.size, info.presentationTimeUs,
+                flags);
+        if (info.size > 0 && ((flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) &&
+                ((flags & MediaCodec.BUFFER_FLAG_PARTIAL_FRAME) == 0)) {
+            mOutputBuff.saveInPTS(info.presentationTimeUs);
+            mInputCount++;
+        }
+    }
+
+    void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+        if (info.size > 0 && mSaveToMem) {
+            if (mIsAudio) {
+                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
+                mOutputBuff.saveToMemory(buf, info);
+            } else {
+                // tests both getOutputImage and getOutputBuffer. Can do time division
+                // multiplexing but lets allow it for now
+                Image img = mCodec.getOutputImage(bufferIndex);
+                assertTrue(img != null);
+                mOutputBuff.checksum(img);
+
+                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
+                mOutputBuff.checksum(buf, info.size);
+            }
+        }
+        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+            mSawOutputEOS = true;
+        }
+        if (ENABLE_LOGS) {
+            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
+                    info.size + " timestamp: " + info.presentationTimeUs);
+        }
+        if (info.size > 0 && (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+            mOutputBuff.saveOutPTS(info.presentationTimeUs);
+            mOutputCount++;
+        }
+        mCodec.releaseOutputBuffer(bufferIndex, false);
+    }
+
+    void doWork(ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> list)
+            throws InterruptedException {
+        int frameCount = 0;
+        if (mIsCodecInAsyncMode) {
+            // output processing after queuing EOS is done in waitForAllOutputs()
+            while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < list.size()) {
+                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
+                if (element != null) {
+                    int bufferID = element.first;
+                    MediaCodec.BufferInfo info = element.second;
+                    if (info != null) {
+                        dequeueOutput(bufferID, info);
+                    } else {
+                        enqueueInput(bufferID, buffer, list.get(frameCount));
+                        frameCount++;
+                    }
+                }
+            }
+        } else {
+            MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
+            // output processing after queuing EOS is done in waitForAllOutputs()
+            while (!mSawInputEOS && frameCount < list.size()) {
+                int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
+                if (outputBufferId >= 0) {
+                    dequeueOutput(outputBufferId, outInfo);
+                } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                    mOutFormat = mCodec.getOutputFormat();
+                    mSignalledOutFormatChanged = true;
+                }
+                int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
+                if (inputBufferId != -1) {
+                    enqueueInput(inputBufferId, buffer, list.get(frameCount));
+                    frameCount++;
+                }
+            }
+        }
+    }
+
+    void queueCodecConfig() throws InterruptedException {
+        if (mIsCodecInAsyncMode) {
+            for (mCurrCsdIdx = 0; !mAsyncHandle.hasSeenError() && mCurrCsdIdx < mCsdBuffers.size();
+                 mCurrCsdIdx++) {
+                Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getInput();
+                if (element != null) {
+                    enqueueCodecConfig(element.first);
+                }
+            }
+        } else {
+            for (mCurrCsdIdx = 0; mCurrCsdIdx < mCsdBuffers.size(); mCurrCsdIdx++) {
+                enqueueCodecConfig(mCodec.dequeueInputBuffer(-1));
+            }
+        }
+    }
+
+    void decodeToMemory(String file, String decoder, long pts, int mode, int frameLimit)
+            throws IOException, InterruptedException {
+        mSaveToMem = true;
+        mOutputBuff = new OutputManager();
+        mCodec = MediaCodec.createByCodecName(decoder);
+        MediaFormat format = setUpSource(file);
+        configureCodec(format, false, true, false);
+        mCodec.start();
+        mExtractor.seekTo(pts, mode);
+        doWork(frameLimit);
+        queueEOS();
+        waitForAllOutputs();
+        mCodec.stop();
+        mCodec.release();
+        mExtractor.release();
+        mSaveToMem = false;
+    }
+
+    @Override
+    PersistableBundle validateMetrics(String decoder, MediaFormat format) {
+        PersistableBundle metrics = super.validateMetrics(decoder, format);
+        assertTrue(metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE).equals(mMime));
+        assertTrue(metrics.getInt(MediaCodec.MetricsConstants.ENCODER) == 0);
+        return metrics;
+    }
+}
+
+class CodecEncoderTestBase extends CodecTestBase {
+    private static final String LOG_TAG = CodecEncoderTestBase.class.getSimpleName();
+
+    // files are in WorkDir.getMediaDirString();
+    private static final String mInputAudioFile = "bbb_2ch_44kHz_s16le.raw";
+    private static final String mInputVideoFile = "bbb_cif_yuv420p_30fps.yuv";
+    private final int INP_FRM_WIDTH = 352;
+    private final int INP_FRM_HEIGHT = 288;
+
+    final String mMime;
+    final String mInputFile;
+    byte[] mInputData;
+    int mNumBytesSubmitted;
+    long mInputOffsetPts;
+
+    int mWidth, mHeight;
+    int mFrameRate;
+    int mMaxBFrames;
+    int mChannels;
+    int mSampleRate;
+
+    CodecEncoderTestBase(String mime) {
+        mMime = mime;
+        mWidth = INP_FRM_WIDTH;
+        mHeight = INP_FRM_HEIGHT;
+        mChannels = 1;
+        mSampleRate = 8000;
+        mFrameRate = 30;
+        mMaxBFrames = 0;
+        if (mime.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4)) mFrameRate = 12;
+        else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_H263)) mFrameRate = 12;
+        mAsyncHandle = new CodecAsyncHandler();
+        mIsAudio = mMime.startsWith("audio/");
+        mInputFile = mIsAudio ? mInputAudioFile : mInputVideoFile;
+    }
+
+    @Override
+    void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
+        super.resetContext(isAsync, signalEOSWithLastFrame);
+        mNumBytesSubmitted = 0;
+        mInputOffsetPts = 0;
+    }
+
+    @Override
+    void flushCodec() {
+        super.flushCodec();
+        if (mIsAudio) {
+            mInputOffsetPts =
+                    (mNumBytesSubmitted + 1024) * 1000000L / (2 * mChannels * mSampleRate);
+        } else {
+            mInputOffsetPts = (mInputCount + 5) * 1000000L / mFrameRate;
+        }
+        mPrevOutputPts = mInputOffsetPts - 1;
+        mNumBytesSubmitted = 0;
+    }
+
+    void setUpSource(String srcFile) throws IOException {
+        String inpPath = mInpPrefix + srcFile;
+        try (FileInputStream fInp = new FileInputStream(inpPath)) {
+            int size = (int) new File(inpPath).length();
+            mInputData = new byte[size];
+            fInp.read(mInputData, 0, size);
+        }
+    }
+
+    void fillImage(Image image) {
+        Assert.assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
+        int imageWidth = image.getWidth();
+        int imageHeight = image.getHeight();
+        Image.Plane[] planes = image.getPlanes();
+        int offset = mNumBytesSubmitted;
+        for (int i = 0; i < planes.length; ++i) {
+            ByteBuffer buf = planes[i].getBuffer();
+            int width = imageWidth;
+            int height = imageHeight;
+            int tileWidth = INP_FRM_WIDTH;
+            int tileHeight = INP_FRM_HEIGHT;
+            int rowStride = planes[i].getRowStride();
+            int pixelStride = planes[i].getPixelStride();
+            if (i != 0) {
+                width = imageWidth / 2;
+                height = imageHeight / 2;
+                tileWidth = INP_FRM_WIDTH / 2;
+                tileHeight = INP_FRM_HEIGHT / 2;
+            }
+            if (pixelStride == 1) {
+                if (width == rowStride && width == tileWidth && height == tileHeight) {
+                    buf.put(mInputData, offset, width * height);
+                } else {
+                    for (int z = 0; z < height; z += tileHeight) {
+                        int rowsToCopy = Math.min(height - z, tileHeight);
+                        for (int y = 0; y < rowsToCopy; y++) {
+                            for (int x = 0; x < width; x += tileWidth) {
+                                int colsToCopy = Math.min(width - x, tileWidth);
+                                buf.position((z + y) * rowStride + x);
+                                buf.put(mInputData, offset + y * tileWidth, colsToCopy);
+                            }
+                        }
+                    }
+                }
+            } else {
+                // do it pixel-by-pixel
+                for (int z = 0; z < height; z += tileHeight) {
+                    int rowsToCopy = Math.min(height - z, tileHeight);
+                    for (int y = 0; y < rowsToCopy; y++) {
+                        int lineOffset = (z + y) * rowStride;
+                        for (int x = 0; x < width; x += tileWidth) {
+                            int colsToCopy = Math.min(width - x, tileWidth);
+                            for (int w = 0; w < colsToCopy; w++) {
+                                buf.position(lineOffset + (x + w) * pixelStride);
+                                buf.put(mInputData[offset + y * tileWidth + w]);
+                            }
+                        }
+                    }
+                }
+            }
+            offset += tileWidth * tileHeight;
+        }
+    }
+
+    void fillByteBuffer(ByteBuffer inputBuffer) {
+        int offset = 0, frmOffset = mNumBytesSubmitted;
+        for (int plane = 0; plane < 3; plane++) {
+            int width = mWidth;
+            int height = mHeight;
+            int tileWidth = INP_FRM_WIDTH;
+            int tileHeight = INP_FRM_HEIGHT;
+            if (plane != 0) {
+                width = mWidth / 2;
+                height = mHeight / 2;
+                tileWidth = INP_FRM_WIDTH / 2;
+                tileHeight = INP_FRM_HEIGHT / 2;
+            }
+            for (int k = 0; k < height; k += tileHeight) {
+                int rowsToCopy = Math.min(height - k, tileHeight);
+                for (int j = 0; j < rowsToCopy; j++) {
+                    for (int i = 0; i < width; i += tileWidth) {
+                        int colsToCopy = Math.min(width - i, tileWidth);
+                        inputBuffer.position(offset + (k + j) * width + i);
+                        inputBuffer.put(mInputData, frmOffset + j * tileWidth, colsToCopy);
+                    }
+                }
+            }
+            offset += width * height;
+            frmOffset += tileWidth * tileHeight;
+        }
+    }
+
+    void enqueueInput(int bufferIndex) {
+        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
+        if (mNumBytesSubmitted >= mInputData.length) {
+            enqueueEOS(bufferIndex);
+        } else {
+            int size;
+            int flags = 0;
+            long pts = mInputOffsetPts;
+            if (mIsAudio) {
+                pts += mNumBytesSubmitted * 1000000L / (2 * mChannels * mSampleRate);
+                size = Math.min(inputBuffer.capacity(), mInputData.length - mNumBytesSubmitted);
+                inputBuffer.put(mInputData, mNumBytesSubmitted, size);
+                if (mNumBytesSubmitted + size >= mInputData.length && mSignalEOSWithLastFrame) {
+                    flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                    mSawInputEOS = true;
+                }
+                mNumBytesSubmitted += size;
+            } else {
+                pts += mInputCount * 1000000L / mFrameRate;
+                size = mWidth * mHeight * 3 / 2;
+                int frmSize = INP_FRM_WIDTH * INP_FRM_HEIGHT * 3 / 2;
+                if (mNumBytesSubmitted + frmSize > mInputData.length) {
+                    fail("received partial frame to encode");
+                } else {
+                    Image img = mCodec.getInputImage(bufferIndex);
+                    if (img != null) {
+                        fillImage(img);
+                    } else {
+                        if (mWidth == INP_FRM_WIDTH && mHeight == INP_FRM_HEIGHT) {
+                            inputBuffer.put(mInputData, mNumBytesSubmitted, size);
+                        } else {
+                            fillByteBuffer(inputBuffer);
+                        }
+                    }
+                }
+                if (mNumBytesSubmitted + frmSize >= mInputData.length && mSignalEOSWithLastFrame) {
+                    flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                    mSawInputEOS = true;
+                }
+                mNumBytesSubmitted += frmSize;
+            }
+            if (ENABLE_LOGS) {
+                Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
+                        " flags: " + flags);
+            }
+            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
+            mOutputBuff.saveInPTS(pts);
+            mInputCount++;
+        }
+    }
+
+    void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
+        if (ENABLE_LOGS) {
+            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
+                    info.size + " timestamp: " + info.presentationTimeUs);
+        }
+        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+            mSawOutputEOS = true;
+        }
+        if (info.size > 0) {
+            if (mSaveToMem) {
+                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
+                mOutputBuff.saveToMemory(buf, info);
+            }
+            if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+                mOutputBuff.saveOutPTS(info.presentationTimeUs);
+                mOutputCount++;
+            }
+        }
+        mCodec.releaseOutputBuffer(bufferIndex, false);
+    }
+
+    @Override
+    PersistableBundle validateMetrics(String codec, MediaFormat format) {
+        PersistableBundle metrics = super.validateMetrics(codec, format);
+        assertTrue(metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE).equals(mMime));
+        assertTrue(metrics.getInt(MediaCodec.MetricsConstants.ENCODER) == 1);
+        return metrics;
+    }
+}
+
+
diff --git a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
index 9438dcb..bbfa5aa 100644
--- a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
@@ -18,9 +18,7 @@
 
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
-import android.media.MediaCodecList;
 import android.media.MediaFormat;
-import android.os.Build;
 import android.util.Log;
 import android.util.Pair;
 
@@ -39,46 +37,36 @@
 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 /**
  * Validate profile and level configuration for listed encoder components
  */
 @RunWith(Parameterized.class)
-public class EncoderProfileLevelTest extends CodecTestBase {
+public class EncoderProfileLevelTest extends CodecEncoderTestBase {
     private static final String LOG_TAG = EncoderProfileLevelTest.class.getSimpleName();
     private static final HashMap<String, int[]> mProfileMap = new HashMap<>();
     private static final HashMap<String, Pair<int[], Integer>> mProfileLevelCdd = new HashMap<>();
 
-    private final String mMime;
     private MediaFormat mConfigFormat;
-    private int mNumBytesSubmitted;
-
-    private int mHeight;
-    private int mWidth;
-    private int mChannels;
-    private int mRate;
 
     public EncoderProfileLevelTest(String mime, int bitrate, int encoderInfo1, int encoderInfo2,
             int frameRate) {
-        mMime = mime;
-        mAsyncHandle = new CodecAsyncHandler();
+        super(mime);
         mConfigFormat = new MediaFormat();
-        mIsAudio = mMime.startsWith("audio/");
         mConfigFormat.setString(MediaFormat.KEY_MIME, mMime);
         mConfigFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
         if (mIsAudio) {
-            mRate = encoderInfo1;
+            mSampleRate = encoderInfo1;
             mChannels = encoderInfo2;
-            mConfigFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, mRate);
+            mConfigFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRate);
             mConfigFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, mChannels);
         } else {
             mWidth = encoderInfo1;
             mHeight = encoderInfo2;
-            mRate = frameRate;
+            mFrameRate = frameRate;
             mConfigFormat.setInteger(MediaFormat.KEY_WIDTH, mWidth);
             mConfigFormat.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
-            mConfigFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mRate);
+            mConfigFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
             mConfigFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
             mConfigFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
                     MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
@@ -204,41 +192,7 @@
                 {MediaFormat.MIMETYPE_VIDEO_VP8, 512000, 176, 144, 20},
                 {MediaFormat.MIMETYPE_VIDEO_VP8, 512000, 480, 360, 20},
         });
-
-        ArrayList<String> mimes = new ArrayList<>();
-        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
-        MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
-        for (MediaCodecInfo codecInfo : codecInfos) {
-            if (!codecInfo.isEncoder()) continue;
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
-            String[] types = codecInfo.getSupportedTypes();
-            for (String type : types) {
-                if (!mimes.contains(type)) mimes.add(type);
-            }
-        }
-        for (String mime : cddRequiredMimeList) {
-            if (!mimes.contains(mime)) {
-                fail("media codec encoder list doesn't contain " + mime +
-                        " as required by cdd");
-            }
-        }
-        final List<Object[]> argsList = new ArrayList<>();
-        for (String mime : mimes) {
-            boolean miss = true;
-            for (int i = 0; i < exhaustiveArgsList.size(); i++) {
-                if (mime.equals(exhaustiveArgsList.get(i)[0])) {
-                    argsList.add(exhaustiveArgsList.get(i));
-                    miss = false;
-                }
-            }
-            if (miss) {
-                if (cddRequiredMimeList.contains(mime)) {
-                    fail("no test vectors available for " + mime);
-                }
-                Log.w(LOG_TAG, "no test vectors available for " + mime);
-            }
-        }
-        return argsList;
+        return prepareParamList(cddRequiredMimeList, exhaustiveArgsList, true);
     }
 
     static {
@@ -653,45 +607,6 @@
     }
 
     @Override
-    void enqueueInput(int bufferIndex) {
-        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-        int size;
-        int flags = 0;
-        long pts;
-        if (mIsAudio) {
-            pts = mNumBytesSubmitted * 1000000L / (2 * mChannels * mRate);
-            size = inputBuffer.capacity();
-            byte[] data = new byte[size];
-            inputBuffer.put(data);
-            mNumBytesSubmitted += size;
-        } else {
-            pts = mInputCount * 1000000L / mRate;
-            size = mWidth * mHeight * 3 / 2;
-            byte[] data = new byte[size];
-            inputBuffer.put(data);
-            mNumBytesSubmitted += size;
-        }
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts +
-                    " flags: " + flags);
-        }
-        mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
-        mInputCount++;
-    }
-
-    @Override
-    void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: " +
-                    info.size + " timestamp: " + info.presentationTimeUs);
-        }
-        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-            mSawOutputEOS = true;
-        }
-        mCodec.releaseOutputBuffer(bufferIndex, false);
-    }
-
-    @Override
     boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) {
         if (!super.isFormatSimilar(inpFormat, outFormat)) {
             Log.e(LOG_TAG, "Basic channel-rate/resolution comparisons failed");
@@ -778,6 +693,7 @@
         boolean[] boolStates = {true, false};
         MediaFormat format = mConfigFormat;
         mOutputBuff = new OutputManager();
+        setUpSource(mInputFile);
         int supportedCddCount = listOfEncoders.size() * (cddSupportedMime ? profileCdd.length : 1);
         for (String encoder : listOfEncoders) {
             mCodec = MediaCodec.createByCodecName(encoder);
diff --git a/tests/media/src/android/mediav2/cts/MuxerTest.java b/tests/media/src/android/mediav2/cts/MuxerTest.java
index d954f01..e57b1ee 100644
--- a/tests/media/src/android/mediav2/cts/MuxerTest.java
+++ b/tests/media/src/android/mediav2/cts/MuxerTest.java
@@ -46,6 +46,7 @@
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -57,7 +58,9 @@
 class MuxerTestHelper {
     private static final String LOG_TAG = MuxerTestHelper.class.getSimpleName();
     private static final boolean ENABLE_LOGS = false;
-    static final int STTS_TOLERANCE = 100;
+    // Stts values within 0.1ms(100us) difference are fudged to save too
+    // many stts entries in MPEG4Writer.
+    static final int STTS_TOLERANCE_US = 100;
     private String mSrcPath;
     private String mMime;
     private int mTrackCount;
@@ -69,6 +72,7 @@
     private int mFrameLimit;
     // combineMedias() uses local version of this variable
     private HashMap<Integer, Integer> mOutIndexMap = new HashMap<>();
+    private boolean mRemoveCSD;
 
     private void splitMediaToMuxerParameters() throws IOException {
         // Set up MediaExtractor to read from the source.
@@ -80,6 +84,16 @@
         for (int trackID = 0; trackID < extractor.getTrackCount(); trackID++) {
             extractor.selectTrack(trackID);
             MediaFormat format = extractor.getTrackFormat(trackID);
+            if (mRemoveCSD) {
+                for (int i = 0; ; ++i) {
+                    String csdKey = "csd-" + i;
+                    if (format.containsKey(csdKey)) {
+                        format.removeKey(csdKey);
+                    } else {
+                        break;
+                    }
+                }
+            }
             if (mMime == null) {
                 mTrackCount++;
                 mFormat.add(format);
@@ -219,24 +233,29 @@
         muxer.stop();
     }
 
-    MuxerTestHelper(String srcPath, String mime, int frameLimit) throws IOException {
+    MuxerTestHelper(String srcPath, String mime, int frameLimit, boolean aRemoveCSD) throws IOException {
         mSrcPath = srcPath;
         mMime = mime;
         if (frameLimit < 0) frameLimit = Integer.MAX_VALUE;
         mFrameLimit = frameLimit;
+        mRemoveCSD = aRemoveCSD;
         splitMediaToMuxerParameters();
     }
 
     MuxerTestHelper(String srcPath, String mime) throws IOException {
-        this(srcPath, mime, -1);
+        this(srcPath, mime, -1, false);
     }
 
     MuxerTestHelper(String srcPath, int frameLimit) throws IOException {
-        this(srcPath, null, frameLimit);
+        this(srcPath, null, frameLimit, false);
+    }
+
+    MuxerTestHelper(String srcPath, boolean aRemoveCSD) throws IOException {
+        this(srcPath, null, -1, aRemoveCSD);
     }
 
     MuxerTestHelper(String srcPath) throws IOException {
-        this(srcPath, null, -1);
+        this(srcPath, null, -1, false);
     }
 
     int getTrackCount() {
@@ -253,10 +272,9 @@
         }
     }
 
-    @Override
     // returns true if 'this' stream is a subset of 'o'. That is all tracks in current media
     // stream are present in ref media stream
-    public boolean equals(Object o) {
+    boolean isSubsetOf(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         MuxerTestHelper that = (MuxerTestHelper) o;
@@ -273,43 +291,37 @@
                 if (thisMime != null && thisMime.equals(thatMime)) {
                     if (!ExtractorTest.isCSDIdentical(thisFormat, thatFormat)) continue;
                     if (mBufferInfo.get(i).size() == that.mBufferInfo.get(j).size()) {
-                        int flagsDiff = 0, sizeDiff = 0, tsDiff = 0, buffDiff = 0;
-                        for (int k = 0; k < mBufferInfo.get(i).size(); k++) {
+                        long tolerance = thisMime.startsWith("video/") ? STTS_TOLERANCE_US : 0;
+                        int k = 0;
+                        for (; k < mBufferInfo.get(i).size(); k++) {
                             MediaCodec.BufferInfo thisInfo = mBufferInfo.get(i).get(k);
                             MediaCodec.BufferInfo thatInfo = that.mBufferInfo.get(j).get(k);
                             if (thisInfo.flags != thatInfo.flags) {
-                                flagsDiff++;
+                                break;
                             }
                             if (thisInfo.size != thatInfo.size) {
-                                sizeDiff++;
+                                break;
                             } else {
                                 mBuff.position(thisInfo.offset);
                                 mBuff.get(refBuffer, 0, thisInfo.size);
                                 that.mBuff.position(thatInfo.offset);
                                 that.mBuff.get(testBuffer, 0, thatInfo.size);
-                                for (int count = 0; count < thisInfo.size; count++) {
+                                int count = 0;
+                                for (; count < thisInfo.size; count++) {
                                     if (refBuffer[count] != testBuffer[count]) {
-                                        buffDiff++;
                                         break;
                                     }
                                 }
+                                if (count != thisInfo.size) break;
                             }
                             if (Math.abs(
                                     thisInfo.presentationTimeUs - thatInfo.presentationTimeUs) >
-                                    STTS_TOLERANCE) {
-                                tsDiff++;
+                                    tolerance) {
+                                break;
                             }
                         }
-                        if (flagsDiff != 0 || sizeDiff != 0 || tsDiff != 0 || buffDiff != 0) {
-                            if (ENABLE_LOGS) {
-                                Log.d(LOG_TAG, "For track: " + thisMime +
-                                        " Total Samples: " + mBufferInfo.get(i).size() +
-                                        " flagsDiff: " + flagsDiff +
-                                        " sizeDiff: " + sizeDiff +
-                                        " tsDiff: " + tsDiff +
-                                        " buffDiff: " + buffDiff);
-                            }
-                        } else break;
+                        // all samples are identical. successful match found. move to next track
+                        if (k == mBufferInfo.get(i).size()) break;
                     } else {
                         if (ENABLE_LOGS) {
                             Log.d(LOG_TAG, "Mime matched but sample count different." +
@@ -742,7 +754,7 @@
             try {
                 mediaInfoA.combineMedias(muxer, mediaInfoB, new int[]{1, 1});
                 refInfo = new MuxerTestHelper(mRefPath);
-                if (!mediaInfoA.equals(refInfo) || !mediaInfoB.equals(refInfo)) {
+                if (!mediaInfoA.isSubsetOf(refInfo) || !mediaInfoB.isSubsetOf(refInfo)) {
                     fail(msg + "error ! muxing src A and src B failed");
                 }
             } catch (Exception e) {
@@ -761,7 +773,7 @@
                 try {
                     mediaInfoA.combineMedias(muxer, mediaInfoB, numTrack);
                     MuxerTestHelper outInfo = new MuxerTestHelper(mOutPath);
-                    if (!outInfo.equals(refInfo)) {
+                    if (!outInfo.isSubsetOf(refInfo)) {
                         fail(msg + " error ! muxing src A: " + numTrack[0] + " src B: " +
                                 numTrack[1] + "failed");
                     }
@@ -856,7 +868,7 @@
                     mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
             Assume.assumeTrue("TODO(b/146421018)",
                     mOutFormat != MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
-            assertTrue(OFFSET_TS > MuxerTestHelper.STTS_TOLERANCE);
+            assertTrue(OFFSET_TS > MuxerTestHelper.STTS_TOLERANCE_US);
             MuxerTestHelper mediaInfo = new MuxerTestHelper(mInpPath);
             for (int trackID = 0; trackID < mediaInfo.getTrackCount(); trackID++) {
                 for (int i = 0; i < mOffsetIndices.length; i++) {
@@ -866,7 +878,7 @@
                 mediaInfo.muxMedia(muxer);
                 muxer.release();
                 MuxerTestHelper outInfo = new MuxerTestHelper(mOutPath);
-                if (!outInfo.equals(mediaInfo)) {
+                if (!outInfo.isSubsetOf(mediaInfo)) {
                     String msg = String.format(
                             "testOffsetPresentationTime: inp: %s, fmt: %d, trackID %d", mSrcFile,
                             mOutFormat, trackID);
@@ -954,6 +966,14 @@
             return result;
         }
 
+        private boolean doesCodecRequireCSD(String aMime) {
+            return (aMime == MediaFormat.MIMETYPE_VIDEO_AVC ||
+                    aMime == MediaFormat.MIMETYPE_VIDEO_HEVC ||
+                    aMime == MediaFormat.MIMETYPE_VIDEO_MPEG4 ||
+                    aMime == MediaFormat.MIMETYPE_AUDIO_AAC);
+
+        }
+
         private native boolean nativeTestSimpleMux(String srcPath, String outPath, String mime,
                 String selector);
 
@@ -1010,7 +1030,7 @@
                 try {
                     mediaInfo.muxMedia(muxer);
                     MuxerTestHelper outInfo = new MuxerTestHelper(mOutPath);
-                    if (!mediaInfo.equals(outInfo)) {
+                    if (!mediaInfo.isSubsetOf(outInfo)) {
                         fail(msg + "error! output != clone(input)");
                     }
                 } catch (Exception e) {
@@ -1023,6 +1043,39 @@
             }
         }
 
+        /* Does MediaMuxer throw IllegalStateException on missing codec specific data when required.
+         * Check if relevant exception is thrown for AAC, AVC, HEVC, and MPEG4
+         * codecs that require CSD in MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4.
+         * TODO(b/156767190): Need to evaluate what all codecs need CSD and also what all formats
+         * can contain these codecs, and add test cases accordingly.
+         * TODO(b/156767190): Add similar tests in the native side/NDK as well.
+         * TODO(b/156767190): Make a separate class, like TestNoCSDMux, instead of being part of
+         * TestSimpleMux?
+         */
+        @Test
+        public void testNoCSDMux() throws IOException {
+            Assume.assumeTrue(doesCodecRequireCSD(mMime));
+            MuxerTestHelper mediaInfo = new MuxerTestHelper(mInpPath, true);
+            for (int format = MUXER_OUTPUT_FIRST; format <= MUXER_OUTPUT_LAST; format++) {
+                // TODO(b/156767190)
+                if(format != MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) continue;
+                MediaMuxer muxer = new MediaMuxer(mOutPath, format);
+                Exception expected = null;
+                String msg = String.format("testNoCSDMux: inp: %s, mime %s, fmt: %s", mSrcFile,
+                                            mMime, formatStringPair.get(format));
+                try {
+                    mediaInfo.muxMedia(muxer);
+                } catch (IllegalStateException e) {
+                    expected = e;
+                } catch (Exception e) {
+                    fail(msg + ", unexpected exception:" + e.getMessage());
+                } finally {
+                    assertNotNull(msg, expected);
+                    muxer.release();
+                }
+            }
+        }
+
         @Test
         public void testSimpleMuxNative() {
             Assume.assumeTrue("TODO(b/146421018)",
diff --git a/tests/providerui/AndroidManifest.xml b/tests/providerui/AndroidManifest.xml
index b967cff..2f1f791 100644
--- a/tests/providerui/AndroidManifest.xml
+++ b/tests/providerui/AndroidManifest.xml
@@ -28,6 +28,20 @@
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 
+    <!--
+            final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+
+    -->
+    <queries>
+        <intent>
+            <action android:name="android.intent.action.OPEN_DOCUMENT" />
+            <category android:name="android.intent.category.OPENABLE" />
+            <data android:mimeType="*/*" />
+        </intent>
+    </queries>
+
     <application android:requestLegacyExternalStorage = "true">
         <uses-library android:name="android.test.runner"/>
         <activity android:name="android.providerui.cts.GetResultActivity" />
diff --git a/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java b/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
index 7ad9a24..b6844de 100644
--- a/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
+++ b/tests/rollback/src/com/android/cts/rollback/RollbackManagerTest.java
@@ -106,4 +106,27 @@
                 Rollback.from(TestApp.A2).to(TestApp.A1));
         assertThat(committed).causePackagesContainsExactly(TestApp.A2);
     }
+
+    @Test
+    public void testGetRollbackDataPolicy() throws Exception {
+        // TODO: To change to the following statement when
+        // PackageManager.RollbackDataPolicy.WIPE is available.
+        // final int rollBackDataPolicy = PackageManager.RollbackDataPolicy.WIPE;
+        final int rollBackDataPolicy = 1;
+
+        Install.single(TestApp.A1).commit();
+        assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+
+        // Enable rollback with rollBackDataPolicy
+        final int sessionId = Install.single(TestApp.A2).setEnableRollback(
+                rollBackDataPolicy).createSession();
+
+        try {
+            assertThat(InstallUtils.getPackageInstaller().getSessionInfo(
+                    sessionId).getRollbackDataPolicy()).isEqualTo(rollBackDataPolicy);
+        } finally {
+            // Abandon the session
+            InstallUtils.getPackageInstaller().abandonSession(sessionId);
+        }
+    }
 }
diff --git a/tests/sensor/src/android/hardware/cts/helpers/sensorverification/HingeAngleVerification.java b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/HingeAngleVerification.java
index b129e6a..13f52c3 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/sensorverification/HingeAngleVerification.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/sensorverification/HingeAngleVerification.java
@@ -49,6 +49,8 @@
 
         boolean success = true;
         StringBuilder builder = new StringBuilder("Hinge Angle | failures:");
+        Assert.assertTrue("The hinge angle sensor must output at least two sensor events",
+                mEvents.size() >= 2);
         for (int i = 0; i < mEvents.size(); i++) {
             TestSensorEvent event = mEvents.get(i);
             if (lastEvent != null && lastEvent.values[0] == event.values[0]) {
diff --git a/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java b/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
index 1ec4d91..93cf8e4 100644
--- a/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
+++ b/tests/suspendapps/tests/src/android/suspendapps/cts/DialogTests.java
@@ -53,7 +53,6 @@
 import java.util.regex.Pattern;
 
 @RunWith(AndroidJUnit4.class)
-@SystemUserOnly(reason = "b/150741315: Needs stabilization on secondary user")
 public class DialogTests {
     private static final String TEST_APP_LABEL = "Suspend Test App";
     private static final long UI_TIMEOUT_MS = 30_000;
@@ -66,10 +65,11 @@
     private UiDevice mUiDevice;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         mTestAppInterface = new TestAppInterface(mContext);
+        turnScreenOn();
     }
 
     private void turnScreenOn() throws Exception {
@@ -81,7 +81,6 @@
 
     @Test
     public void testInterceptorActivity_unsuspend() throws Exception {
-        turnScreenOn();
         final SuspendDialogInfo dialogInfo = new SuspendDialogInfo.Builder()
                 .setIcon(R.drawable.ic_settings)
                 .setTitle(R.string.dialog_title)
@@ -119,7 +118,7 @@
         // 3. Unsuspend the test app
         unsuspendButton.click();
 
-        final Intent incomingIntent = sIncomingIntent.poll(10, TimeUnit.SECONDS);
+        final Intent incomingIntent = sIncomingIntent.poll(30, TimeUnit.SECONDS);
         assertNotNull(incomingIntent);
         assertEquals(Intent.ACTION_PACKAGE_UNSUSPENDED_MANUALLY, incomingIntent.getAction());
         assertEquals("Did not receive correct unsuspended package name", TEST_APP_PACKAGE_NAME,
@@ -135,7 +134,6 @@
 
     @Test
     public void testInterceptorActivity_moreDetails() throws Exception {
-        turnScreenOn();
         final SuspendDialogInfo dialogInfo = new SuspendDialogInfo.Builder()
                 .setIcon(R.drawable.ic_settings)
                 .setTitle(R.string.dialog_title)
@@ -171,7 +169,7 @@
 
         // Tapping on the neutral button should start the correct intent.
         moreDetailsButton.click();
-        final Intent incomingIntent = sIncomingIntent.poll(10, TimeUnit.SECONDS);
+        final Intent incomingIntent = sIncomingIntent.poll(30, TimeUnit.SECONDS);
         assertNotNull(incomingIntent);
         assertEquals(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS, incomingIntent.getAction());
         assertEquals("Wrong package name sent with " + Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS,
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
index 6044820..9a08bcf 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -437,7 +437,12 @@
     @AppModeFull
     public void testAppSummary() throws Exception {
         for (int i = 0; i < mNetworkInterfacesToTest.length; ++i) {
-            if (!shouldTestThisNetworkType(i, MINUTE/2)) {
+            // Use tolerance value that large enough to make sure stats of at
+            // least one bucket is included. However, this is possible that
+            // the test will see data of different app but with the same UID
+            // that created before testing.
+            // TODO: Consider query stats before testing and use the difference to verify.
+            if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
                 continue;
             }
             setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index c27a3f8..4440010 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -1240,7 +1240,7 @@
         // Usage should be attributed to the test app package
         assertAppOrTokenUsed(TaskRootActivity.TEST_APP_PKG, true);
 
-        mUiDevice.pressHome();
+        SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
 
         setUsageSourceSetting(Integer.toString(UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY));
         launchSubActivity(TaskRootActivity.class);
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 9c1985c..fe9b79d 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -28,7 +28,6 @@
 import static android.appenumeration.cts.Constants.ACTION_START_FOR_RESULT;
 import static android.appenumeration.cts.Constants.ACTIVITY_CLASS_DUMMY_ACTIVITY;
 import static android.appenumeration.cts.Constants.ACTIVITY_CLASS_TEST;
-import static android.appenumeration.cts.Constants.ALL_QUERIES_TARGETING_R_PACKAGES;
 import static android.appenumeration.cts.Constants.EXTRA_DATA;
 import static android.appenumeration.cts.Constants.EXTRA_ERROR;
 import static android.appenumeration.cts.Constants.EXTRA_FLAGS;
@@ -95,7 +94,6 @@
 import org.hamcrest.core.IsNull;
 import org.junit.AfterClass;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
@@ -138,12 +136,6 @@
         sResponseHandler = new Handler(sResponseThread.getLooper());
     }
 
-    @Before
-    public void setupTest() {
-        if (!sGlobalFeatureEnabled) return;
-        setFeatureEnabledForAll(true);
-    }
-
     @AfterClass
     public static void tearDown() {
         if (!sGlobalFeatureEnabled) return;
@@ -177,8 +169,14 @@
     public void startExplicitly_cannotStartNonVisible() throws Exception {
         assertNotVisible(QUERIES_NOTHING, TARGET_FILTERS);
         try {
-            startExplicitIntent(QUERIES_NOTHING, TARGET_FILTERS);
-            fail("Package cannot start a package it cannot see");
+            startExplicitIntentViaComponent(QUERIES_NOTHING, TARGET_FILTERS);
+            fail("Package cannot start a package it cannot see via component name");
+        } catch (ActivityNotFoundException e) {
+            // hooray!
+        }
+        try {
+            startExplicitIntentViaPackageName(QUERIES_NOTHING, TARGET_FILTERS);
+            fail("Package cannot start a package it cannot see via package name");
         } catch (ActivityNotFoundException e) {
             // hooray!
         }
@@ -187,7 +185,8 @@
     @Test
     public void startExplicitly_canStartVisible() throws Exception {
         assertVisible(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
-        startExplicitIntent(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
+        startExplicitIntentViaComponent(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
+        startExplicitIntentViaPackageName(QUERIES_ACTIVITY_ACTION, TARGET_FILTERS);
     }
 
     @Test
@@ -203,13 +202,6 @@
     }
 
     @Test
-    public void queriesNothing_featureOff_canSeeAll() throws Exception {
-        setFeatureEnabledForAll(QUERIES_NOTHING, false);
-        assertVisible(QUERIES_NOTHING, TARGET_NO_API);
-        assertVisible(QUERIES_NOTHING, TARGET_FILTERS);
-    }
-
-    @Test
     public void queriesNothingTargetsQ_canSeeAll() throws Exception {
         assertVisible(QUERIES_NOTHING_Q, TARGET_FORCEQUERYABLE);
         assertVisible(QUERIES_NOTHING_Q, TARGET_NO_API);
@@ -438,19 +430,6 @@
         }
     }
 
-    private void setFeatureEnabledForAll(Boolean enabled) {
-        for (String pkgName : ALL_QUERIES_TARGETING_R_PACKAGES) {
-            setFeatureEnabledForAll(pkgName, enabled);
-        }
-        setFeatureEnabledForAll(QUERIES_NOTHING_Q, enabled == null ? null : false);
-    }
-
-    private void setFeatureEnabledForAll(String packageName, Boolean enabled) {
-        SystemUtil.runShellCommand(
-                "am compat " + (enabled == null ? "reset" : enabled ? "enable" : "disable")
-                        + " 135549675 " + packageName);
-    }
-
     private void assertNotVisible(String sourcePackageName, String targetPackageName)
             throws Exception {
         if (!sGlobalFeatureEnabled) return;
@@ -550,12 +529,19 @@
         return response.getStringArray(Intent.EXTRA_RETURN_RESULT);
     }
 
-    private void startExplicitIntent(String sourcePackage, String targetPackage) throws Exception {
+    private void startExplicitIntentViaComponent(String sourcePackage, String targetPackage)
+            throws Exception {
         sendCommandBlocking(sourcePackage, targetPackage,
                 new Intent().setComponent(new ComponentName(targetPackage,
                         ACTIVITY_CLASS_DUMMY_ACTIVITY)),
                 ACTION_START_DIRECTLY);
     }
+    private void startExplicitIntentViaPackageName(String sourcePackage, String targetPackage)
+            throws Exception {
+        sendCommandBlocking(sourcePackage, targetPackage,
+                new Intent().setPackage(targetPackage),
+                ACTION_START_DIRECTLY);
+    }
 
     private void startImplicitIntent(String sourcePackage) throws Exception {
         sendCommandBlocking(sourcePackage, TARGET_FILTERS, new Intent(ACTION_MANIFEST_ACTIVITY),
diff --git a/tests/tests/appop/Android.bp b/tests/tests/appop/Android.bp
index 293c62e..20ab4bf 100644
--- a/tests/tests/appop/Android.bp
+++ b/tests/tests/appop/Android.bp
@@ -40,6 +40,7 @@
     srcs: ["src/**/*.kt"],
 
     static_libs: [
+        "bluetooth-test-util-lib",
         "appops-test-util-lib",
         "AppOpsUserServiceAidl",
         "AppOpsForegroundControlServiceAidl",
diff --git a/tests/tests/appop/AndroidTest.xml b/tests/tests/appop/AndroidTest.xml
index 386feb4..29f01e0 100644
--- a/tests/tests/appop/AndroidTest.xml
+++ b/tests/tests/appop/AndroidTest.xml
@@ -23,6 +23,7 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsAppOpsTestCases.apk" />
         <option name="test-file-name" value="CtsAppThatUsesAppOps.apk" />
+        <option name="test-file-name" value="AppInBackground.apk" />
         <option name="test-file-name" value="AppThatCanBeForcedIntoForegroundStates.apk" />
     </target_preparer>
 
diff --git a/tests/tests/appop/AppInBackground/Android.bp b/tests/tests/appop/AppInBackground/Android.bp
new file mode 100644
index 0000000..b46e877
--- /dev/null
+++ b/tests/tests/appop/AppInBackground/Android.bp
@@ -0,0 +1,23 @@
+// 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.
+
+android_test_helper_app {
+    name: "AppInBackground",
+
+    test_suites: [
+        "cts",
+        "vts10",
+        "general-tests",
+    ]
+}
diff --git a/tests/tests/appop/AppInBackground/AndroidManifest.xml b/tests/tests/appop/AppInBackground/AndroidManifest.xml
new file mode 100644
index 0000000..00d9ab8
--- /dev/null
+++ b/tests/tests/appop/AppInBackground/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ 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.
+  -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.app.appops.cts.appinbackground">
+    <attribution android:tag="testAttribution" android:label="@string/dummyLabel" />
+
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+
+    <application />
+</manifest>
diff --git a/tests/tests/appop/AppInBackground/res/values/strings.xml b/tests/tests/appop/AppInBackground/res/values/strings.xml
new file mode 100644
index 0000000..c99e65f
--- /dev/null
+++ b/tests/tests/appop/AppInBackground/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ 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.
+  -->
+
+<resources>
+    <string name="dummyLabel">A feature</string>
+</resources>
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
index 103a4b2..106f111 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpEventCollectionTest.kt
@@ -34,11 +34,14 @@
 import androidx.test.rule.ActivityTestRule
 import androidx.test.uiautomator.UiDevice
 import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeNotNull
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import java.lang.Thread.sleep
 
+private const val BACKGROUND_PACKAGE = "android.app.appops.cts.appinbackground"
+
 class AppOpEventCollectionTest {
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
     private val context = instrumentation.targetContext
@@ -105,30 +108,87 @@
         val attributionOpEntry = opEntry.attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
 
         assertThat(attributionOpEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isIn(before..after)
+        assertThat(opEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isIn(before..after)
 
         // Access should should also show up in the combined state for all op-flags
         assertThat(attributionOpEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isIn(before..after)
-        assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
+        assertThat(opEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isIn(before..after)
 
         // Foreground access should should also show up in the combined state for fg and bg
         assertThat(attributionOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
         assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
+        assertThat(attributionOpEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
+        assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
 
         // The access was in foreground, hence there is no background access
-        assertThat(attributionOpEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
-        assertThat(opEntry.getLastBackgroundDuration(OP_FLAG_SELF)).isLessThan(before)
+        assertThat(attributionOpEntry.getLastAccessBackgroundTime(OP_FLAG_SELF)).isLessThan(before)
+        assertThat(opEntry.getLastAccessBackgroundTime(OP_FLAG_SELF)).isLessThan(before)
+        assertThat(attributionOpEntry.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isLessThan(before)
+        assertThat(opEntry.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isLessThan(before)
 
         // The access was for a attribution, hence there is no access for the default attribution
         if (null in opEntry.attributedOpEntries) {
             assertThat(opEntry.attributedOpEntries[null]!!
-                    .getLastAccessForegroundTime(OP_FLAG_SELF)).isLessThan(before)
+                .getLastAccessForegroundTime(OP_FLAG_SELF)).isLessThan(before)
         }
 
         // The access does not show up for other op-flags
-        assertThat(attributionOpEntry.getLastAccessForegroundTime(
-                OP_FLAGS_ALL and OP_FLAG_SELF.inv())).isLessThan(before)
-        assertThat(opEntry.getLastAccessForegroundTime(
-                OP_FLAGS_ALL and OP_FLAG_SELF.inv())).isLessThan(before)
+        assertThat(
+            attributionOpEntry.getLastAccessForegroundTime(OP_FLAGS_ALL and OP_FLAG_SELF.inv())
+        ).isLessThan(before)
+        assertThat(opEntry.getLastAccessForegroundTime(OP_FLAGS_ALL and OP_FLAG_SELF.inv()))
+            .isLessThan(before)
+    }
+
+    @AppModeFull(reason = "instant apps cannot see other packages")
+    @Test
+    fun noteInBackgroundWithAttributionAndCheckOpEntries() {
+        val uid = context.packageManager.getPackageUid(BACKGROUND_PACKAGE, 0)
+
+        val before = System.currentTimeMillis()
+        assertThat(
+            runWithShellPermissionIdentity {
+                appOpsManager.noteOp(
+                    OPSTR_WIFI_SCAN, uid, BACKGROUND_PACKAGE, TEST_ATTRIBUTION_TAG, null
+                )
+            }
+        ).isEqualTo(AppOpsManager.MODE_ALLOWED)
+        val after = System.currentTimeMillis()
+
+        val opEntry = getOpEntry(uid, BACKGROUND_PACKAGE, OPSTR_WIFI_SCAN)!!
+        val attributionOpEntry = opEntry.attributedOpEntries[TEST_ATTRIBUTION_TAG]!!
+
+        assertThat(attributionOpEntry.getLastAccessBackgroundTime(OP_FLAG_SELF)).isIn(before..after)
+        assertThat(opEntry.getLastAccessBackgroundTime(OP_FLAG_SELF)).isIn(before..after)
+
+        // Access should should also show up in the combined state for all op-flags
+        assertThat(attributionOpEntry.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isIn(before..after)
+        assertThat(opEntry.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isIn(before..after)
+
+        // Background access should should also show up in the combined state for fg and bg
+        assertThat(attributionOpEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
+        assertThat(opEntry.getLastAccessTime(OP_FLAG_SELF)).isIn(before..after)
+        assertThat(attributionOpEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
+        assertThat(opEntry.getLastAccessTime(OP_FLAGS_ALL)).isIn(before..after)
+
+        // The access was in background, hence there is no foreground access
+        assertThat(attributionOpEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isLessThan(before)
+        assertThat(opEntry.getLastAccessForegroundTime(OP_FLAG_SELF)).isLessThan(before)
+        assertThat(attributionOpEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isLessThan(before)
+        assertThat(opEntry.getLastAccessForegroundTime(OP_FLAGS_ALL)).isLessThan(before)
+
+        // The access was for a attribution, hence there is no access for the default attribution
+        if (null in opEntry.attributedOpEntries) {
+            assertThat(opEntry.attributedOpEntries[null]!!
+                .getLastAccessBackgroundTime(OP_FLAG_SELF)).isLessThan(before)
+        }
+
+        // The access does not show up for other op-flags
+        assertThat(
+            attributionOpEntry.getLastAccessBackgroundTime(OP_FLAGS_ALL and OP_FLAG_SELF.inv())
+        ).isLessThan(before)
+        assertThat(opEntry.getLastAccessBackgroundTime(OP_FLAGS_ALL and OP_FLAG_SELF.inv()))
+            .isLessThan(before)
     }
 
     @Test
@@ -191,9 +251,12 @@
     fun noteFromTwoProxiesAndVerifyProxyInfo() {
         // Find another app to blame
         val otherAppInfo = context.packageManager
-                .resolveActivity(Intent(ACTION_APPLICATION_PREFERENCES), 0)!!
-                .activityInfo.applicationInfo
-        val otherPkg = otherAppInfo.packageName
+                .resolveActivity(Intent(ACTION_APPLICATION_PREFERENCES), 0)
+                ?.activityInfo?.applicationInfo
+
+        assumeNotNull(otherAppInfo)
+
+        val otherPkg = otherAppInfo!!.packageName
         val otherUid = otherAppInfo.uid
 
         // Using the shell identity causes a trusted proxy note
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
index 5891055..4be7ac2 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
@@ -33,6 +33,8 @@
 import android.app.WallpaperManager
 import android.app.WallpaperManager.FLAG_SYSTEM
 import android.bluetooth.BluetoothManager
+import android.bluetooth.cts.BTAdapterUtils.enableAdapter as enableBTAdapter
+import android.bluetooth.cts.BTAdapterUtils.disableAdapter as disableBTAdapter
 import android.bluetooth.le.ScanCallback
 import android.content.BroadcastReceiver
 import android.content.ComponentName
@@ -402,16 +404,22 @@
         assumeTrue("Device does not support bluetooth",
                 context.packageManager.hasSystemFeature(FEATURE_BLUETOOTH))
 
-        val btManager = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
-                .getSystemService(BluetoothManager::class.java)
+        val testContext = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
+        val btAdapter = testContext.getSystemService(BluetoothManager::class.java).adapter
 
-        btManager.adapter.startDiscovery()
+        val wasEnabled = enableBTAdapter(btAdapter, testContext)
+        assumeTrue("Need to be able enable BT", wasEnabled)
         try {
-            assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
-            assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
-            assertThat(noted[0].second.map { it.methodName }).contains("getBTScanResults")
+            btAdapter.startDiscovery()
+            try {
+                assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
+                assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
+                assertThat(noted[0].second.map { it.methodName }).contains("getBTScanResults")
+            } finally {
+                btAdapter.cancelDiscovery()
+            }
         } finally {
-            btManager.adapter.cancelDiscovery()
+            disableBTAdapter(btAdapter, testContext)
         }
     }
 
@@ -423,22 +431,29 @@
         assumeTrue("Device does not support LE bluetooth",
                 context.packageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE))
 
-        val btScanner = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
-                .getSystemService(BluetoothManager::class.java).adapter.bluetoothLeScanner
+        val testContext = context.createAttributionContext(TEST_ATTRIBUTION_TAG)
+        val btAdapter = testContext.getSystemService(BluetoothManager::class.java).adapter
 
-        val scanCallback = object : ScanCallback() {}
-
-        btScanner.startScan(scanCallback)
+        val wasEnabled = enableBTAdapter(btAdapter, testContext)
+        assumeTrue("Need to be able enable BT", wasEnabled)
         try {
-            eventually {
-                assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
-                assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
-                // startScan calls into the system server which then calls back into the app to
-                // start the scan. I.e. the backtrace points back to a callback from the system
-                // server
+            val btScanner = btAdapter.bluetoothLeScanner
+            val scanCallback = object : ScanCallback() {}
+
+            btScanner.startScan(scanCallback)
+            try {
+                eventually {
+                    assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
+                    assertThat(noted[0].first.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
+                    // startScan calls into the system server which then calls back into the app to
+                    // start the scan. I.e. the backtrace points back to a callback from the system
+                    // server
+                }
+            } finally {
+                btScanner.stopScan(scanCallback)
             }
         } finally {
-            btScanner.stopScan(scanCallback)
+            disableBTAdapter(btAdapter, testContext)
         }
     }
 
diff --git a/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
index 71a4263..1d14a77 100644
--- a/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
@@ -65,13 +65,13 @@
 
                 runWithShellPermissionIdentity {
                     val message = appOpsManager.collectRuntimeAppOpAccessMessage()
-                    if (message != null && message.packageName.equals(APP_PKG)) {
+                    if (message != null && message.packageName.equals(APP_PKG) &&
+                            message.samplingStrategy !=
+                            RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM) {
                         assertThat(message.op).isEqualTo(AppOpsManager.OPSTR_READ_CONTACTS)
                         assertThat(message.uid).isEqualTo(appUid)
                         assertThat(message.attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG)
                         assertThat(message.message).isEqualTo(MESSAGE)
-                        assertThat(message.samplingStrategy)
-                                .isNotEqualTo(RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM)
                         return
                     }
                 }
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 56fce94..bb50071 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySaverTest.java
@@ -17,8 +17,11 @@
 
 import static com.android.compatibility.common.util.BatteryUtils.enableBatterySaver;
 import static com.android.compatibility.common.util.BatteryUtils.runDumpsysBatteryUnplug;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
 import static com.android.compatibility.common.util.TestUtils.waitUntil;
 
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -99,6 +102,13 @@
     /** Tests that Battery Saver exemptions activate when car mode is active. */
     @Test
     public void testCarModeExceptions() throws Exception {
+        final String nightModeText = runShellCommand("cmd uimode night");
+        final String[] nightModeSplit = nightModeText.split(":");
+        if (nightModeSplit.length != 2) {
+            fail("Failed to get initial night mode value from " + nightModeText);
+        }
+        final String initialNightMode = nightModeSplit[1].trim();
+        runShellCommand("cmd uimode night no");
         UiModeManager uiModeManager = getContext().getSystemService(UiModeManager.class);
         uiModeManager.disableCarMode(0);
 
@@ -147,6 +157,7 @@
                 powerManager.getLocationPowerSaveMode());
         } finally {
             uiModeManager.disableCarMode(0);
+            runShellCommand("cmd uimode night " + initialNightMode);
             SettingsUtils.delete(SettingsUtils.NAMESPACE_GLOBAL, "battery_saver_constants");
         }
     }
diff --git a/tests/tests/bluetooth/Android.bp b/tests/tests/bluetooth/Android.bp
index 13e9742..13ee58e 100644
--- a/tests/tests/bluetooth/Android.bp
+++ b/tests/tests/bluetooth/Android.bp
@@ -15,7 +15,10 @@
 android_test {
     name: "CtsBluetoothTestCases",
     defaults: ["cts_defaults"],
-    static_libs: ["ctstestrunner-axt"],
+    static_libs: [
+        "ctstestrunner-axt",
+        "bluetooth-test-util-lib",
+    ],
     libs: [
         "android.test.runner.stubs",
         "android.test.base.stubs",
diff --git a/tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp b/tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp
new file mode 100644
index 0000000..0257a41
--- /dev/null
+++ b/tests/tests/bluetooth/bluetoothTestUtilLib/Android.bp
@@ -0,0 +1,25 @@
+// 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.
+
+java_library {
+    name: "bluetooth-test-util-lib",
+
+    static_libs: [
+        "junit",
+    ],
+
+    srcs: ["src/**/*.java"],
+
+    sdk_version: "current",
+}
diff --git a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
new file mode 100644
index 0000000..9954f054
--- /dev/null
+++ b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
@@ -0,0 +1,161 @@
+/*
+ * 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.bluetooth.cts;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.le.ScanRecord;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Utility for controlling the Bluetooth adapter from CTS test.
+ */
+public class BTAdapterUtils {
+    private static final String TAG = "BTAdapterUtils";
+
+    // ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY +
+    //                              AdapterState.BREDR_START_TIMEOUT_DELAY
+    private static final int ADAPTER_ENABLE_TIMEOUT_MS = 8000;
+    // ADAPTER_DISABLE_TIMEOUT_MS = AdapterState.BLE_STOP_TIMEOUT_DELAY +
+    //                                  AdapterState.BREDR_STOP_TIMEOUT_DELAY
+    private static final int ADAPTER_DISABLE_TIMEOUT_MS = 5000;
+
+    private static BroadcastReceiver mAdapterIntentReceiver;
+
+    private static Condition mConditionAdapterIsEnabled;
+    private static ReentrantLock mAdapterStateEnablinglock;
+
+    private static Condition mConditionAdapterIsDisabled;
+    private static ReentrantLock mAdapterStateDisablinglock;
+    private static boolean mAdapterVarsInitialized;
+
+    private static class AdapterIntentReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+                int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
+                int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+                Log.d(TAG, "Previous state: " + previousState + " New state: " + newState);
+
+                if (newState == BluetoothAdapter.STATE_ON) {
+                    mAdapterStateEnablinglock.lock();
+                    try {
+                        Log.d(TAG, "Signaling to mConditionAdapterIsEnabled");
+                        mConditionAdapterIsEnabled.signal();
+                    } finally {
+                        mAdapterStateEnablinglock.unlock();
+                    }
+                } else if (newState == BluetoothAdapter.STATE_OFF) {
+                    mAdapterStateDisablinglock.lock();
+                    try {
+                        Log.d(TAG, "Signaling to mConditionAdapterIsDisabled");
+                        mConditionAdapterIsDisabled.signal();
+                    } finally {
+                        mAdapterStateDisablinglock.unlock();
+                    }
+                }
+            }
+        }
+    }
+
+    /** Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled. */
+    public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
+        if (!mAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.isEnabled()) return true;
+
+        Log.d(TAG, "Enabling bluetooth adapter");
+        bluetoothAdapter.enable();
+        mAdapterStateEnablinglock.lock();
+        try {
+            // Wait for the Adapter to be enabled
+            while (!bluetoothAdapter.isEnabled()) {
+                if (!mConditionAdapterIsEnabled.await(
+                        ADAPTER_ENABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    // Timeout
+                    Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter enable");
+                    break;
+                } // else spurious wakeups
+            }
+        } catch(InterruptedException e) {
+            Log.e(TAG, "enableAdapter: interrrupted");
+        } finally {
+            mAdapterStateEnablinglock.unlock();
+        }
+        return bluetoothAdapter.isEnabled();
+    }
+
+    /** Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled. */
+    public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
+        if (!mAdapterVarsInitialized) {
+            initAdapterStateVariables(context);
+        }
+
+        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) return true;
+
+        Log.d(TAG, "Disabling bluetooth adapter");
+        bluetoothAdapter.disable();
+        mAdapterStateDisablinglock.lock();
+        try {
+            // Wait for the Adapter to be disabled
+            while (bluetoothAdapter.getState() != BluetoothAdapter.STATE_OFF) {
+                if (!mConditionAdapterIsDisabled.await(
+                        ADAPTER_DISABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                    // Timeout
+                    Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter disable");
+                    break;
+                } // else spurious wakeups
+            }
+        } catch(InterruptedException e) {
+            Log.e(TAG, "enableAdapter: interrrupted");
+        } finally {
+            mAdapterStateDisablinglock.unlock();
+        }
+        return bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF;
+    }
+
+    // Initialize variables required for TestUtils#enableAdapter and TestUtils#disableAdapter
+    private static void initAdapterStateVariables(Context context) {
+        Log.d(TAG, "Initializing adapter state variables");
+        mAdapterIntentReceiver = new AdapterIntentReceiver();
+        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+        context.registerReceiver(mAdapterIntentReceiver, filter);
+
+        mAdapterStateEnablinglock = new ReentrantLock();
+        mConditionAdapterIsEnabled = mAdapterStateEnablinglock.newCondition();
+        mAdapterStateDisablinglock = new ReentrantLock();
+        mConditionAdapterIsDisabled = mAdapterStateDisablinglock.newCondition();
+
+        mAdapterVarsInitialized = true;
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
index 65be7f8..2eab364 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
@@ -141,8 +141,8 @@
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
 
         for (int i=0; i<5; i++) {
-            assertTrue(TestUtils.disableAdapter(adapter, mContext));
-            assertTrue(TestUtils.enableAdapter(adapter, mContext));
+            assertTrue(BTAdapterUtils.disableAdapter(adapter, mContext));
+            assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
         }
     }
 
@@ -152,7 +152,7 @@
             return;
         }
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(TestUtils.enableAdapter(adapter, mContext));
+        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
 
         assertTrue(BluetoothAdapter.checkBluetoothAddress(adapter.getAddress()));
     }
@@ -163,7 +163,7 @@
             return;
         }
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(TestUtils.enableAdapter(adapter, mContext));
+        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
 
         String name = adapter.getName();
         assertNotNull(name);
@@ -188,7 +188,7 @@
             return;
         }
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(TestUtils.enableAdapter(adapter, mContext));
+        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
 
         Set<BluetoothDevice> devices = adapter.getBondedDevices();
         assertNotNull(devices);
@@ -204,7 +204,7 @@
         }
         // getRemoteDevice() should work even with Bluetooth disabled
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(TestUtils.disableAdapter(adapter, mContext));
+        assertTrue(BTAdapterUtils.disableAdapter(adapter, mContext));
 
         // test bad addresses
         try {
@@ -240,7 +240,7 @@
             return;
         }
         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        assertTrue(TestUtils.enableAdapter(adapter, mContext));
+        assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
 
         BluetoothServerSocket socket = adapter.listenUsingRfcommWithServiceRecord(
                 "test", UUID.randomUUID());
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index ac5ab45..103816e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -80,7 +80,7 @@
                 Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = manager.getAdapter();
         if (!mBluetoothAdapter.isEnabled()) {
-            assertTrue(TestUtils.enableAdapter(mBluetoothAdapter, mContext));
+            assertTrue(BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext));
         }
         mScanner = mBluetoothAdapter.getBluetoothLeScanner();
         mLocationOn = TestUtils.isLocationOn(getContext());
@@ -101,7 +101,7 @@
         if (!mLocationOn) {
             TestUtils.disableLocation(getContext());
         }
-        assertTrue(TestUtils.disableAdapter(mBluetoothAdapter, mContext));
+        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
     }
 
     /**
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
index de26d4c..4e1419a 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
@@ -80,7 +80,7 @@
                 Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = manager.getAdapter();
 
-        if (!TestUtils.enableAdapter(mBluetoothAdapter, mContext)) {
+        if (!BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext)) {
             Log.e(TAG, "Unable to enable Bluetooth Adapter!");
             assertTrue(mBluetoothAdapter.isEnabled());
         }
@@ -99,7 +99,7 @@
     public void tearDown() {
         if (!mIsBleSupported) return;
 
-        if (!TestUtils.disableAdapter(mBluetoothAdapter, mContext)) {
+        if (!BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext)) {
             Log.e(TAG, "Unable to disable Bluetooth Adapter!");
             assertTrue(mBluetoothAdapter.isEnabled());
         }
@@ -224,10 +224,10 @@
         mContext.registerReceiver(mIntentReceiver, filter);
 
         Log.d(TAG, "test_getConnectionStateChangedIntent: disable adapter and wait");
-        assertTrue(TestUtils.disableAdapter(mBluetoothAdapter, mContext));
+        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
 
         Log.d(TAG, "test_getConnectionStateChangedIntent: enable adapter and wait");
-        assertTrue(TestUtils.enableAdapter(mBluetoothAdapter, mContext));
+        assertTrue(BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext));
 
         int sanityCount = WAIT_FOR_INTENT_TIMEOUT_MS;
         while ((numDevices != mIntentCallbackDeviceList.size()) && (sanityCount > 0)) {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
index 1546bd0..b9a93a1 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
@@ -39,7 +39,7 @@
         assertNotNull("BluetoothAdapter.getDefaultAdapter() returned null. "
                 + "Does this device have a Bluetooth adapter?", mAdapter);
         if (!mAdapter.isEnabled()) {
-            assertTrue(TestUtils.enableAdapter(mAdapter, mContext));
+            assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
         }
     }
 
@@ -48,7 +48,7 @@
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
-        assertTrue(TestUtils.disableAdapter(mAdapter, mContext));
+        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
         mAdapter = null;
         super.tearDown();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java b/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
index 310c836..7c4c454 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/TestUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 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.
@@ -38,127 +38,7 @@
 /**
  * Utility class for Bluetooth CTS test.
  */
-public class TestUtils {
-    private static final String TAG = "BluetoothTestUtils";
-
-    // ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY +
-    //                              AdapterState.BREDR_START_TIMEOUT_DELAY
-    private static final int ADAPTER_ENABLE_TIMEOUT_MS = 8000;
-    // ADAPTER_DISABLE_TIMEOUT_MS = AdapterState.BLE_STOP_TIMEOUT_DELAY +
-    //                                  AdapterState.BREDR_STOP_TIMEOUT_DELAY
-    private static final int ADAPTER_DISABLE_TIMEOUT_MS = 5000;
-
-    private static BroadcastReceiver mAdapterIntentReceiver;
-
-    private static Condition mConditionAdapterIsEnabled;
-    private static ReentrantLock mAdapterStateEnablinglock;
-
-    private static Condition mConditionAdapterIsDisabled;
-    private static ReentrantLock mAdapterStateDisablinglock;
-    private static boolean mAdapterVarsInitialized;
-
-    private static class AdapterIntentReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
-                int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
-                int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
-                Log.d(TAG, "Previous state: " + previousState + " New state: " + newState);
-
-                if (newState == BluetoothAdapter.STATE_ON) {
-                    mAdapterStateEnablinglock.lock();
-                    try {
-                        Log.d(TAG, "Signaling to mConditionAdapterIsEnabled");
-                        mConditionAdapterIsEnabled.signal();
-                    } finally {
-                        mAdapterStateEnablinglock.unlock();
-                    }
-                } else if (newState == BluetoothAdapter.STATE_OFF) {
-                    mAdapterStateDisablinglock.lock();
-                    try {
-                        Log.d(TAG, "Signaling to mConditionAdapterIsDisabled");
-                        mConditionAdapterIsDisabled.signal();
-                    } finally {
-                        mAdapterStateDisablinglock.unlock();
-                    }
-                }
-            }
-        }
-    }
-
-    // Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled.
-    public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
-        if (!mAdapterVarsInitialized) {
-            initAdapterStateVariables(context);
-        }
-
-        if (bluetoothAdapter.isEnabled()) return true;
-
-        Log.d(TAG, "Enabling bluetooth adapter");
-        bluetoothAdapter.enable();
-        mAdapterStateEnablinglock.lock();
-        try {
-            // Wait for the Adapter to be enabled
-            while (!bluetoothAdapter.isEnabled()) {
-                if (!mConditionAdapterIsEnabled.await(
-                        ADAPTER_ENABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                    // Timeout
-                    Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter enable");
-                    break;
-                } // else spurious wakeups
-            }
-        } catch(InterruptedException e) {
-            Log.e(TAG, "enableAdapter: interrrupted");
-        } finally {
-            mAdapterStateEnablinglock.unlock();
-        }
-        return bluetoothAdapter.isEnabled();
-    }
-
-    // Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled.
-    public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
-        if (!mAdapterVarsInitialized) {
-            initAdapterStateVariables(context);
-        }
-
-        if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) return true;
-
-        Log.d(TAG, "Disabling bluetooth adapter");
-        bluetoothAdapter.disable();
-        mAdapterStateDisablinglock.lock();
-        try {
-            // Wait for the Adapter to be disabled
-            while (bluetoothAdapter.getState() != BluetoothAdapter.STATE_OFF) {
-                if (!mConditionAdapterIsDisabled.await(
-                        ADAPTER_DISABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
-                    // Timeout
-                    Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter disable");
-                    break;
-                } // else spurious wakeups
-            }
-        } catch(InterruptedException e) {
-            Log.e(TAG, "enableAdapter: interrrupted");
-        } finally {
-            mAdapterStateDisablinglock.unlock();
-        }
-        return bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF;
-    }
-
-    // Initialize variables required for TestUtils#enableAdapter and TestUtils#disableAdapter
-    private static void initAdapterStateVariables(Context context) {
-        Log.d(TAG, "Initializing adapter state variables");
-        mAdapterIntentReceiver = new AdapterIntentReceiver();
-        IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
-        context.registerReceiver(mAdapterIntentReceiver, filter);
-
-        mAdapterStateEnablinglock = new ReentrantLock();
-        mConditionAdapterIsEnabled = mAdapterStateEnablinglock.newCondition();
-        mAdapterStateDisablinglock = new ReentrantLock();
-        mConditionAdapterIsDisabled = mAdapterStateDisablinglock.newCondition();
-
-        mAdapterVarsInitialized = true;
-    }
-
+class TestUtils {
     /**
      * Utility method to call hidden ScanRecord.parseFromBytes method.
      */
diff --git a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
index e8e08b9..a06403a 100644
--- a/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
+++ b/tests/tests/content/CtsSyncAccountAccessOtherCertTests/src/com/android/cts/content/CtsSyncAccountAccessOtherCertTestCases.java
@@ -193,7 +193,7 @@
         int height = uiDevice.getDisplayHeight();
         return uiDevice.swipe(
             width / 2 /* startX */,
-            height - 1 /* startY */,
+            height / 2 /* startY */,
             width / 2 /* endX */,
             1 /* endY */,
             50 /* numberOfSteps */);
diff --git a/tests/tests/content/src/android/content/cts/IntentFilterTest.java b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
index 096068b..757f4bd 100644
--- a/tests/tests/content/src/android/content/cts/IntentFilterTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
@@ -572,18 +572,18 @@
                 new String[]{"authority1"}, new String[]{"100"});
         checkMatches(filter,
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null, true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme1:*", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme1://*/", true),
-                MatchCondition.data(IntentFilter.MATCH_CATEGORY_PORT, "scheme1://*:100/", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme1://*:200/", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "*:foo", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "*://authority1/", true),
-                MatchCondition.data(IntentFilter.MATCH_CATEGORY_PORT, "*://authority1:100/", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "*://authority1:200/", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "*:*", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "*://*/", true),
-                MatchCondition.data(IntentFilter.MATCH_CATEGORY_PORT, "*://*:100/", true),
-                MatchCondition.data(IntentFilter.NO_MATCH_DATA, "*://*:200/", true));
+                MatchCondition.data(IntentFilter.NO_MATCH_DATA,       "scheme1:*", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "scheme1://*/", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "scheme1://*:100/", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "scheme1://*:200/", true),
+                MatchCondition.data(IntentFilter.NO_MATCH_DATA,       "*:foo", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "*://authority1/", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "*://authority1:100/", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "*://authority1:200/", true),
+                MatchCondition.data(IntentFilter.NO_MATCH_DATA,       "*:*", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "*://*/", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "*://*:100/", true),
+                MatchCondition.data(IntentFilter.MATCH_CATEGORY_HOST, "*://*:200/", true));
 
         checkMatches(filter,
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme1://*/", false),
@@ -683,6 +683,20 @@
         }
     }
 
+    public void testAppEnumerationMatchesMimeGroups() {
+        IntentFilter filter = new Match(new String[]{ACTION}, null, null, new String[]{"scheme1"},
+                new String[]{"authority1"}, null).addMimeGroups(new String[]{"test"});
+
+        // assume any mime type or no mime type matches a filter with a mimegroup defined.
+        checkMatches(filter,
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE,
+                        ACTION, null, "img/jpeg", "scheme1://authority1", true),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE,
+                        ACTION, null, null, "scheme1://authority1", true),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE,
+                        ACTION, null, "*/*", "scheme1://authority1", true));
+    }
+
     public void testMatchData() throws MalformedMimeTypeException {
         int expected = IntentFilter.MATCH_CATEGORY_EMPTY + IntentFilter.MATCH_ADJUSTMENT_NORMAL;
         assertEquals(expected, mIntentFilter.matchData(null, null, null));
@@ -881,6 +895,48 @@
                         true));
     }
 
+    public void testAppEnumerationNoHostMatchesWildcardHost() throws Exception {
+        IntentFilter filter = new Match(
+                new String[]{Intent.ACTION_VIEW},
+                new String[]{Intent.CATEGORY_BROWSABLE},
+                null,
+                new String[]{"http", "https"},
+                new String[]{"*"},
+                null /*ports*/);
+        checkMatches(filter,
+                new MatchCondition(MATCH_CATEGORY_HOST,
+                        Intent.ACTION_VIEW,
+                        new String[]{Intent.CATEGORY_BROWSABLE},
+                        null,
+                        "https://*",
+                        true));
+
+        checkMatches(filter,
+                new MatchCondition(MATCH_CATEGORY_HOST,
+                        Intent.ACTION_VIEW,
+                        new String[]{Intent.CATEGORY_BROWSABLE},
+                        null,
+                        "https://",
+                        true));
+    }
+
+    public void testAppEnumerationNoPortMatchesPortFilter() throws Exception {
+        IntentFilter filter = new Match(
+                new String[]{Intent.ACTION_VIEW},
+                new String[]{Intent.CATEGORY_BROWSABLE},
+                null,
+                new String[]{"http", "https"},
+                new String[]{"*"},
+                new String[]{"81"});
+        checkMatches(filter,
+                new MatchCondition(MATCH_CATEGORY_HOST,
+                        Intent.ACTION_VIEW,
+                        new String[]{Intent.CATEGORY_BROWSABLE},
+                        null,
+                        "https://something",
+                        true));
+    }
+
     public void testWriteToXml() throws IllegalArgumentException, IllegalStateException,
             IOException, MalformedMimeTypeException, XmlPullParserException {
         XmlSerializer xml;
@@ -1276,6 +1332,13 @@
             return this;
         }
 
+        Match addMimeGroups(String[] mimeGroups) {
+            for (int i = 0; i < mimeGroups.length; i++) {
+                addMimeGroup(mimeGroups[i]);
+            }
+            return this;
+        }
+
         Match addMimeTypes(String[] mimeTypes) {
             for (int i = 0; i < mimeTypes.length; i++) {
                 try {
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
index c6f4faf..54a5bc0 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
@@ -29,8 +29,10 @@
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.AppModeFull;
 import android.service.dataloader.DataLoaderService;
+import android.text.TextUtils;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
@@ -140,15 +142,38 @@
         assertEquals(binder, service.onBind(new Intent()));
     }
 
+    @LargeTest
     @Test
     public void testInstallSysTrace() throws Exception {
+        // Async atrace dump uses less resources but requires periodic pulls.
+        // Overall timeout of 30secs in 100ms intervals should be enough.
+        final int atraceDumpIterations = 300;
+        final int atraceDumpDelayMs = 100;
+
         final String expected = "|page_read:";
         final ByteArrayOutputStream result = new ByteArrayOutputStream();
-        final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand("atrace adb");
         final Thread readFromProcess = new Thread(() -> {
-            try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
-                final String found = waitForSubstring(inputStream, expected);
-                result.write(found.getBytes());
+            try {
+                executeShellCommand("atrace --async_start -b 1024 -c adb");
+                try {
+                    for (int i = 0; i < atraceDumpIterations; ++i) {
+                        final ParcelFileDescriptor stdout = getUiAutomation().executeShellCommand(
+                                "atrace --async_dump");
+                        try (InputStream inputStream =
+                                     new ParcelFileDescriptor.AutoCloseInputStream(
+                                stdout)) {
+                            final String found = waitForSubstring(inputStream, expected);
+                            if (!TextUtils.isEmpty(found)) {
+                                result.write(found.getBytes());
+                                return;
+                            }
+                            Thread.currentThread().sleep(atraceDumpDelayMs);
+                        } catch (InterruptedException ignored) {
+                        }
+                    }
+                } finally {
+                    executeShellCommand("atrace --async_stop");
+                }
             } catch (IOException ignored) {
             }
         });
@@ -158,7 +183,7 @@
         assertTrue(isAppInstalled(TEST_APP_PACKAGE));
 
         readFromProcess.join();
-        assertNotEquals("", result.toString());
+        assertNotEquals(0, result.size());
     }
 
     private boolean isAppInstalled(String packageName) throws IOException {
diff --git a/tests/tests/display/AndroidManifest.xml b/tests/tests/display/AndroidManifest.xml
index 41d1688..38e5b3f 100644
--- a/tests/tests/display/AndroidManifest.xml
+++ b/tests/tests/display/AndroidManifest.xml
@@ -26,6 +26,8 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <!-- For testing pushing brightness curves. -->
     <uses-permission android:name="android.permission.CONFIGURE_DISPLAY_BRIGHTNESS" />
+    <!-- For querying to see if packages exist with the brightness permissions. -->
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/display/OWNERS b/tests/tests/display/OWNERS
index 6b9f7be..041736b 100644
--- a/tests/tests/display/OWNERS
+++ b/tests/tests/display/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 46788
-michaelwr@google.com
\ No newline at end of file
+michaelwr@google.com
+santoscordon@google.com
diff --git a/tests/tests/display/src/android/display/cts/BrightnessTest.java b/tests/tests/display/src/android/display/cts/BrightnessTest.java
index 7b207b9..7bbe88d 100644
--- a/tests/tests/display/src/android/display/cts/BrightnessTest.java
+++ b/tests/tests/display/src/android/display/cts/BrightnessTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.Manifest;
 import android.app.UiAutomation;
@@ -88,10 +89,9 @@
 
     @Test
     public void testBrightnessSliderTracking() throws InterruptedException {
-        if (numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) == 0) {
-            // Don't run as there is no app that has permission to access slider usage.
-            return;
-        }
+        // Don't run as there is no app that has permission to access slider usage.
+        assumeTrue(
+                numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
 
         int previousBrightness = getSystemSetting(Settings.System.SCREEN_BRIGHTNESS);
         int previousBrightnessMode =
@@ -139,10 +139,10 @@
 
     @Test
     public void testNoTrackingForManualBrightness() throws InterruptedException {
-        if (numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) == 0) {
-            // Don't run as there is no app that has permission to access slider usage.
-            return;
-        }
+        // Don't run as there is no app that has permission to access slider usage.
+        assumeTrue(
+                numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
+
         int previousBrightness = getSystemSetting(Settings.System.SCREEN_BRIGHTNESS);
         int previousBrightnessMode =
                 getSystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE);
@@ -171,6 +171,52 @@
     }
 
     @Test
+    public void testNoColorSampleData() throws InterruptedException {
+          // Don't run as there is no app that has permission to access slider usage.
+        assumeTrue(
+                numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
+
+        // Don't run as there is no app that has permission to push curves.
+        assumeTrue(numberOfSystemAppsWithPermission(
+                Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) > 0);
+
+        int previousBrightness = getSystemSetting(Settings.System.SCREEN_BRIGHTNESS);
+        int previousBrightnessMode =
+                getSystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE);
+        try {
+            setSystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE,
+                    Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+            int mode = getSystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE);
+            assertEquals(Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC, mode);
+
+            grantPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE);
+            grantPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS);
+
+            // Set brightness config to not sample color.
+            BrightnessConfiguration config =
+                    new BrightnessConfiguration.Builder(
+                            new float[]{0.0f, 1000.0f},new float[]{20.0f, 500.0f})
+                            .setShouldCollectColorSamples(false).build();
+            mDisplayManager.setBrightnessConfiguration(config);
+
+            // Setup and generate one slider event.
+            recordSliderEvents();
+            waitForFirstSliderEvent();
+            setSystemSetting(Settings.System.SCREEN_BRIGHTNESS, 20);
+            List<BrightnessChangeEvent> newEvents = getNewEvents(1);
+
+            // No color samples.
+            assertEquals(0, newEvents.get(0).colorSampleDuration);
+            assertNull(newEvents.get(0).colorValueBuckets);
+
+            // No test for sampling color as support is optional.
+        } finally {
+            setSystemSetting(Settings.System.SCREEN_BRIGHTNESS, previousBrightness);
+            setSystemSetting(Settings.System.SCREEN_BRIGHTNESS_MODE, previousBrightnessMode);
+        }
+    }
+
+    @Test
     public void testSliderUsagePermission() {
         revokePermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE);
 
@@ -203,14 +249,14 @@
 
     @Test
     public void testSetGetSimpleCurve() {
-        if (numberOfSystemAppsWithPermission(
-                    Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) == 0) {
-            // Don't run as there is no app that has permission to push curves.
-            return;
-        }
+        // Don't run as there is no app that has permission to push curves.
+        assumeTrue(numberOfSystemAppsWithPermission(
+                Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) > 0);
 
         grantPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS);
 
+        BrightnessConfiguration defaultConfig = mDisplayManager.getDefaultBrightnessConfiguration();
+
         BrightnessConfiguration config =
                 new BrightnessConfiguration.Builder(
                         new float[]{0.0f, 1000.0f},new float[]{20.0f, 500.0f})
@@ -218,16 +264,28 @@
                                 BrightnessCorrection.createScaleAndTranslateLog(0.80f, 0.2f))
                         .addCorrectionByPackageName("some.package.name",
                                 BrightnessCorrection.createScaleAndTranslateLog(0.70f, 0.1f))
+                        .setShortTermModelTimeoutMillis(
+                                defaultConfig.getShortTermModelTimeoutMillis() + 1000L)
+                        .setShortTermModelLowerLuxMultiplier(
+                                defaultConfig.getShortTermModelLowerLuxMultiplier() + 0.2f)
+                        .setShortTermModelUpperLuxMultiplier(
+                                defaultConfig.getShortTermModelUpperLuxMultiplier() + 0.3f)
                         .setDescription("some test").build();
         mDisplayManager.setBrightnessConfiguration(config);
         BrightnessConfiguration returnedConfig = mDisplayManager.getBrightnessConfiguration();
         assertEquals(config, returnedConfig);
-        assertEquals(config.getCorrectionByCategory(ApplicationInfo.CATEGORY_IMAGE),
+        assertEquals(returnedConfig.getCorrectionByCategory(ApplicationInfo.CATEGORY_IMAGE),
                 BrightnessCorrection.createScaleAndTranslateLog(0.80f, 0.2f));
-        assertEquals(config.getCorrectionByPackageName("some.package.name"),
+        assertEquals(returnedConfig.getCorrectionByPackageName("some.package.name"),
                 BrightnessCorrection.createScaleAndTranslateLog(0.70f, 0.1f));
-        assertNull(config.getCorrectionByCategory(ApplicationInfo.CATEGORY_GAME));
-        assertNull(config.getCorrectionByPackageName("someother.package.name"));
+        assertNull(returnedConfig.getCorrectionByCategory(ApplicationInfo.CATEGORY_GAME));
+        assertNull(returnedConfig.getCorrectionByPackageName("someother.package.name"));
+        assertEquals(defaultConfig.getShortTermModelTimeoutMillis() + 1000L,
+                returnedConfig.getShortTermModelTimeoutMillis());
+        assertEquals(defaultConfig.getShortTermModelLowerLuxMultiplier() + 0.2f,
+                returnedConfig.getShortTermModelLowerLuxMultiplier(), 0.001f);
+        assertEquals(defaultConfig.getShortTermModelUpperLuxMultiplier() + 0.3f,
+                returnedConfig.getShortTermModelUpperLuxMultiplier(), 0.001f);
 
         // After clearing the curve we should get back the default curve.
         mDisplayManager.setBrightnessConfiguration(null);
@@ -237,10 +295,9 @@
 
     @Test
     public void testGetDefaultCurve()  {
-        if (numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) == 0) {
-            // Don't run as there is no app that has permission to push curves.
-            return;
-        }
+        // Don't run as there is no app that has permission to push curves.
+        assumeTrue(numberOfSystemAppsWithPermission(
+                Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) > 0);
 
         grantPermission(Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS);
 
@@ -256,20 +313,24 @@
         assertEquals(0.0, curve.first[0], 0.1);
         assertMonotonic(curve.first, true /*strictly increasing*/, "lux");
         assertMonotonic(curve.second, false /*strictly increasing*/, "nits");
+        assertTrue(defaultConfig.getShortTermModelLowerLuxMultiplier() > 0.0f);
+        assertTrue(defaultConfig.getShortTermModelLowerLuxMultiplier() < 10.0f);
+        assertTrue(defaultConfig.getShortTermModelUpperLuxMultiplier() > 0.0f);
+        assertTrue(defaultConfig.getShortTermModelUpperLuxMultiplier() < 10.0f);
+        assertTrue(defaultConfig.getShortTermModelTimeoutMillis() > 0L);
+        assertTrue(defaultConfig.getShortTermModelTimeoutMillis() < 24 * 60 * 60 * 1000L);
+        assertFalse(defaultConfig.shouldCollectColorSamples());
     }
 
 
     @Test
     public void testSliderEventsReflectCurves() throws InterruptedException {
-        if (numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) == 0) {
-            // Don't run as there is no app that has permission to access slider usage.
-            return;
-        }
-        if (numberOfSystemAppsWithPermission(
-                    Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) == 0) {
-            // Don't run as there is no app that has permission to push curves.
-            return;
-        }
+        // Don't run as there is no app that has permission to access slider usage.
+        assumeTrue(
+                numberOfSystemAppsWithPermission(Manifest.permission.BRIGHTNESS_SLIDER_USAGE) > 0);
+        // Don't run as there is no app that has permission to push curves.
+        assumeTrue(numberOfSystemAppsWithPermission(
+                Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) > 0);
 
         BrightnessConfiguration config =
                 new BrightnessConfiguration.Builder(
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 1ded288..aeb5ce0 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -39,7 +39,6 @@
 import android.os.ParcelFileDescriptor;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
-import android.test.InstrumentationTestCase;
 import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Display.HdrCapabilities;
@@ -98,16 +97,18 @@
 
     @Rule
     public ActivityTestRule<DisplayTestActivity> mDisplayTestActivity =
-            new ActivityTestRule<>(DisplayTestActivity.class,
-                    false /* initialTouchMode */, false /* launchActivity */);
+            new ActivityTestRule<>(
+                    DisplayTestActivity.class,
+                    false /* initialTouchMode */,
+                    false /* launchActivity */);
 
     @Before
     public void setUp() throws Exception {
         mScreenOnActivity = launchScreenOnActivity();
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
-        mDisplayManager = (DisplayManager)mContext.getSystemService(Context.DISPLAY_SERVICE);
-        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-        mUiModeManager = (UiModeManager)mContext.getSystemService(Context.UI_MODE_SERVICE);
+        mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
         mDefaultDisplay = mDisplayManager.getDisplay(DEFAULT_DISPLAY);
         mSupportedWideGamuts = mDefaultDisplay.getSupportedWideColorGamut();
     }
@@ -208,6 +209,8 @@
         assertFalse(cap.getDesiredMaxLuminance() < -1.0f);
         assertFalse(cap.getDesiredMinLuminance() < -1.0f);
         assertFalse(cap.getDesiredMaxAverageLuminance() < -1.0f);
+        assertTrue(cap.getDesiredMinLuminance() <= cap.getDesiredMaxAverageLuminance());
+        assertTrue(cap.getDesiredMaxAverageLuminance() <= cap.getDesiredMaxLuminance());
         if (hdrTypes.length > 0) {
             assertTrue(display.isHdr());
         } else {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index ed1d0c9..d8fad93 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -2344,16 +2344,16 @@
 
     private Object[] parametersForTestNdkInfo() {
         return new Object[] {
-            new Object[] { Config.ALPHA_8,   8 /* ANDROID_BITMAP_FORMAT_A_8 */ },
-            new Object[] { Config.ARGB_8888, 1 /* ANDROID_BITMAP_FORMAT_RGBA_8888 */ },
-            new Object[] { Config.RGB_565,   4 /* ANDROID_BITMAP_FORMAT_RGB_565 */ },
-            new Object[] { Config.RGBA_F16,  9 /* ANDROID_BITMAP_FORMAT_RGBA_F16*/ },
+            new Object[] { Config.ALPHA_8,   ANDROID_BITMAP_FORMAT_A_8  },
+            new Object[] { Config.ARGB_8888, ANDROID_BITMAP_FORMAT_RGBA_8888 },
+            new Object[] { Config.RGB_565,   ANDROID_BITMAP_FORMAT_RGB_565 },
+            new Object[] { Config.RGBA_F16,  ANDROID_BITMAP_FORMAT_RGBA_F16 },
         };
     }
 
     @Test
     @Parameters(method = "parametersForTestNdkInfo")
-    public void testNdkInfo(Config config, int androidBitmapFormat) {
+    public void testNdkInfo(Config config, final int expectedFormat) {
         // Arbitrary width and height.
         final int width = 13;
         final int height = 7;
@@ -2362,17 +2362,27 @@
             for (boolean premultiplied : trueFalse) {
                 Bitmap bm = Bitmap.createBitmap(width, height, config, hasAlpha);
                 bm.setPremultiplied(premultiplied);
-                nTestInfo(bm, androidBitmapFormat, width, height, bm.hasAlpha(),
+                nTestInfo(bm, expectedFormat, width, height, bm.hasAlpha(),
                         bm.isPremultiplied(), false);
-                bm = bm.copy(Bitmap.Config.HARDWARE, false);
+                Bitmap hwBitmap = bm.copy(Bitmap.Config.HARDWARE, false);
                 if (config == Bitmap.Config.ALPHA_8) {
                     // ALPHA_8 is not supported in HARDWARE. b/141480329
-                    assertNull(bm);
+                    assertNull(hwBitmap);
                 } else {
-                    assertNotNull(bm);
-                    nTestInfo(bm, androidBitmapFormat, width, height, bm.hasAlpha(),
-                            bm.isPremultiplied(), true);
+                    assertNotNull(hwBitmap);
+
+                    // Some devices do not support F16 + HARDWARE. These fall back to 8888, and can
+                    // be identified by their use of SRGB instead of EXTENDED_SRGB.
+                    int tempExpectedFormat = expectedFormat;
+                    if (config == Config.RGBA_F16 && hwBitmap.getColorSpace() == ColorSpace.get(
+                            ColorSpace.Named.SRGB)) {
+                        tempExpectedFormat = ANDROID_BITMAP_FORMAT_RGBA_8888;
+                    }
+                    nTestInfo(hwBitmap, tempExpectedFormat, width, height, hwBitmap.hasAlpha(),
+                            hwBitmap.isPremultiplied(), true);
+                    hwBitmap.recycle();
                 }
+                bm.recycle();
             }
         }
     }
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index 7a00734..e316b4d 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -32,6 +32,7 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
 
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -47,8 +48,8 @@
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" android:required="false" />
 
-        <activity android:name="android.media.cts.AudioPlaybackCaptureActivity"
-            android:label="AudioPlaybackCaptureActivity"
+        <activity android:name="android.media.cts.MediaProjectionActivity"
+            android:label="MediaProjectionActivity"
             android:screenOrientation="locked"/>
         <activity android:name="android.media.cts.AudioManagerStub"
             android:label="AudioManagerStub"/>
diff --git a/tests/tests/media/AndroidTest.xml b/tests/tests/media/AndroidTest.xml
index 70def5b..a04bcfc 100644
--- a/tests/tests/media/AndroidTest.xml
+++ b/tests/tests/media/AndroidTest.xml
@@ -31,6 +31,10 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMediaTestCases.apk" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <!-- MediaProjectionTest needs this one to not be granted, SuiteApkInstaller grants all of them by default.-->
+        <option name="run-command" value="pm revoke android.media.cts android.permission.SYSTEM_ALERT_WINDOW"/>
+    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
         <option name="target" value="device" />
         <option name="config-filename" value="CtsMediaTestCases" />
diff --git a/tests/tests/media/src/android/media/cts/AudioHelper.java b/tests/tests/media/src/android/media/cts/AudioHelper.java
index a0f8e47..695fb9d 100644
--- a/tests/tests/media/src/android/media/cts/AudioHelper.java
+++ b/tests/tests/media/src/android/media/cts/AudioHelper.java
@@ -261,8 +261,9 @@
         private static final double TEST_STD_JITTER_MS_WARN = 1.;    // CDD requirement warning
 
         // CDD 5.6 100ms track startup latency
-        private final double TEST_STARTUP_TIME_MS_ALLOWED; // CDD requirement error
-        private static final double TEST_STARTUP_TIME_MS_WARN = 100.;    // CDD requirement warning
+        private static final double TEST_STARTUP_TIME_MS_ALLOWED = 500.; // error
+        private final double TEST_STARTUP_TIME_MS_WARN;                  // warning
+        private static final double TEST_STARTUP_TIME_MS_INFO = 100.;    // informational
 
         private static final int MILLIS_PER_SECOND = 1000;
         private static final long NANOS_PER_MILLISECOND = 1000000;
@@ -286,8 +287,8 @@
                 boolean isProAudioDevice) {
             mTag = tag;  // Log accepts null
             mSampleRate = sampleRate;
-            // For pro audio, allow slightly higher than MUST value to account for variability.
-            TEST_STARTUP_TIME_MS_ALLOWED = isProAudioDevice ? 300. /* MUST is 200. */ : 500.;
+            // Warning if higher than MUST value for pro audio.  Zero means ignore.
+            TEST_STARTUP_TIME_MS_WARN = isProAudioDevice ? 200. : 0.;
         }
 
         public int getJitterCount() { return mJitterCount; }
@@ -357,13 +358,16 @@
             final double stdJitterMs = getStdJitterMs();
 
             // Check startup time
-            if (startupTimeMs > TEST_STARTUP_TIME_MS_WARN) {
+            assertTrue("expect startupTimeMs " + startupTimeMs
+                            + " <= " + TEST_STARTUP_TIME_MS_ALLOWED,
+                    startupTimeMs <= TEST_STARTUP_TIME_MS_ALLOWED);
+            if (TEST_STARTUP_TIME_MS_WARN > 0 && startupTimeMs > TEST_STARTUP_TIME_MS_WARN) {
                 Log.w(mTag, "CDD warning: startup time " + startupTimeMs
                         + " > " + TEST_STARTUP_TIME_MS_WARN);
+            } else if (startupTimeMs > TEST_STARTUP_TIME_MS_INFO) {
+                Log.i(mTag, "CDD informational: startup time " + startupTimeMs
+                        + " > " + TEST_STARTUP_TIME_MS_INFO);
             }
-            assertTrue("expect startupTimeMs " + startupTimeMs
-                            + " < " + TEST_STARTUP_TIME_MS_ALLOWED,
-                    startupTimeMs < TEST_STARTUP_TIME_MS_ALLOWED);
 
             // Check maximum jitter
             assertTrue("expect maxAbsJitterMs(" + mMaxAbsJitterMs + ") < "
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
index 7b00c9a..b67ec58 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
@@ -60,7 +60,7 @@
  * Test audio playback capture through MediaProjection.
  *
  * The tests do the following:
- *   - retrieve a MediaProjection through AudioPlaybackCaptureActivity
+ *   - retrieve a MediaProjection through MediaProjectionActivity
  *   - play some audio
  *   - use that MediaProjection to record the audio playing
  *   - check that some audio was recorded.
@@ -77,11 +77,11 @@
     private AudioManager mAudioManager;
     private boolean mPlaybackBeforeCapture;
     private int mUid; //< UID of this test
-    private AudioPlaybackCaptureActivity mActivity;
+    private MediaProjectionActivity mActivity;
     private MediaProjection mMediaProjection;
     @Rule
-    public ActivityTestRule<AudioPlaybackCaptureActivity> mActivityRule =
-                new ActivityTestRule<>(AudioPlaybackCaptureActivity.class);
+    public ActivityTestRule<MediaProjectionActivity> mActivityRule =
+                new ActivityTestRule<>(MediaProjectionActivity.class);
 
     private static class APCTestConfig {
         public @AttributeUsage int[] matchingUsages;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java b/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
index 0327e2b..7f60d5f 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
@@ -24,9 +24,12 @@
 import android.media.MediaCodec.CodecException;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
+import android.media.MediaCrypto;
+import android.media.MediaDrm;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.cts.R;
+import android.net.Uri;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
@@ -40,9 +43,11 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;;
+import java.util.UUID;;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -52,9 +57,6 @@
 /**
  * MediaCodec tests with CONFIGURE_FLAG_USE_BLOCK_MODEL.
  */
-@Presubmit
-@SmallTest
-@RequiresDevice
 public class MediaCodecBlockModelTest extends AndroidTestCase {
     private static final String TAG = "MediaCodecBlockModelTest";
     private static final boolean VERBOSE = false;           // lots of logging
@@ -72,12 +74,15 @@
 
     // The test should fail if the codec never produces output frames for the truncated input.
     // Time out processing, as we have no way to query whether the decoder will produce output.
-    private static final int TIMEOUT_MS = 2000;
+    private static final int TIMEOUT_MS = 60000;  // 1 minute
 
     /**
      * Tests whether decoding a short group-of-pictures succeeds. The test queues a few video frames
      * then signals end-of-stream. The test fails if the decoder doesn't output the queued frames.
      */
+    @Presubmit
+    @SmallTest
+    @RequiresDevice
     public void testDecodeShortVideo() throws InterruptedException {
         runThread(() -> runDecodeShortVideo(
                 INPUT_RESOURCE_ID,
@@ -90,9 +95,24 @@
     }
 
     /**
+     * Tests whether decoding a short encrypted group-of-pictures succeeds.
+     * The test queues a few encrypted video frames
+     * then signals end-of-stream. The test fails if the decoder doesn't output the queued frames.
+     */
+    public void testDecodeShortEncryptedVideo() throws InterruptedException {
+        runThread(() -> runDecodeShortEncryptedVideo(
+                true /* obtainBlockForEachBuffer */));
+        runThread(() -> runDecodeShortEncryptedVideo(
+                false /* obtainBlockForEachBuffer */));
+    }
+
+    /**
      * Tests whether decoding a short audio succeeds. The test queues a few audio frames
      * then signals end-of-stream. The test fails if the decoder doesn't output the queued frames.
      */
+    @Presubmit
+    @SmallTest
+    @RequiresDevice
     public void testDecodeShortAudio() throws InterruptedException {
         runThread(() -> runDecodeShortAudio(
                 INPUT_RESOURCE_ID,
@@ -108,6 +128,9 @@
      * Tests whether encoding a short audio succeeds. The test queues a few audio frames
      * then signals end-of-stream. The test fails if the encoder doesn't output the queued frames.
      */
+    @Presubmit
+    @SmallTest
+    @RequiresDevice
     public void testEncodeShortAudio() throws InterruptedException {
         runThread(() -> runEncodeShortAudio());
     }
@@ -116,18 +139,28 @@
      * Tests whether encoding a short video succeeds. The test queues a few video frames
      * then signals end-of-stream. The test fails if the encoder doesn't output the queued frames.
      */
+    @Presubmit
+    @SmallTest
+    @RequiresDevice
     public void testEncodeShortVideo() throws InterruptedException {
         runThread(() -> runEncodeShortVideo());
     }
 
+    /**
+     * Test whether format change happens as expected in block model mode.
+     */
+    @Presubmit
+    @SmallTest
+    @RequiresDevice
     public void testFormatChange() throws InterruptedException {
         List<FormatChangeEvent> events = new ArrayList<>();
         runThread(() -> runDecodeShortVideo(
-                INPUT_RESOURCE_ID,
+                getMediaExtractorForMimeType(INPUT_RESOURCE_ID, "video/"),
                 LAST_BUFFER_TIMESTAMP_US,
                 true /* obtainBlockForEachBuffer */,
                 MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 320, 240),
-                events));
+                events,
+                null /* sessionId */));
         int width = 320;
         int height = 240;
         for (FormatChangeEvent event : events) {
@@ -173,15 +206,60 @@
     }
 
     private static class ExtractorInputSlotListener implements InputSlotListener {
-        public ExtractorInputSlotListener(
+        public static class Builder {
+            public Builder setExtractor(MediaExtractor extractor) {
+                mExtractor = extractor;
+                return this;
+            }
+
+            public Builder setLastBufferTimestampUs(Long timestampUs) {
+                mLastBufferTimestampUs = timestampUs;
+                return this;
+            }
+
+            public Builder setObtainBlockForEachBuffer(boolean enabled) {
+                mObtainBlockForEachBuffer = enabled;
+                return this;
+            }
+
+            public Builder setTimestampQueue(List<Long> list) {
+                mTimestampList = list;
+                return this;
+            }
+
+            public Builder setContentEncrypted(boolean encrypted) {
+                mContentEncrypted = encrypted;
+                return this;
+            }
+
+            public ExtractorInputSlotListener build() {
+                if (mExtractor == null) {
+                    throw new IllegalStateException("Extractor must be set");
+                }
+                return new ExtractorInputSlotListener(
+                        mExtractor, mLastBufferTimestampUs,
+                        mObtainBlockForEachBuffer, mTimestampList,
+                        mContentEncrypted);
+            }
+
+            private MediaExtractor mExtractor = null;
+            private Long mLastBufferTimestampUs = null;
+            private boolean mObtainBlockForEachBuffer = false;
+            private List<Long> mTimestampList = null;
+            private boolean mContentEncrypted = false;
+        }
+
+        private ExtractorInputSlotListener(
                 MediaExtractor extractor,
-                long lastBufferTimestampUs,
+                Long lastBufferTimestampUs,
                 boolean obtainBlockForEachBuffer,
-                LinkedBlockingQueue<Long> timestampQueue) {
+                List<Long> timestampList,
+                boolean contentEncrypted) {
             mExtractor = extractor;
             mLastBufferTimestampUs = lastBufferTimestampUs;
             mObtainBlockForEachBuffer = obtainBlockForEachBuffer;
-            mTimestampQueue = timestampQueue;
+            mTimestampList = timestampList;
+            mContentEncrypted = contentEncrypted;
         }
 
         @Override
@@ -192,6 +270,9 @@
             }
             long size = mExtractor.getSampleSize();
             String[] codecNames = new String[]{ codec.getName() };
+            if (mContentEncrypted) {
+                codecNames[0] = codecNames[0] + ".secure";
+            }
             if (mObtainBlockForEachBuffer) {
                 input.block.recycle();
                 input.block = MediaCodec.LinearBlock.obtain(Math.toIntExact(size), codecNames);
@@ -220,11 +301,21 @@
             }
             long timestampUs = mExtractor.getSampleTime();
             int written = mExtractor.readSampleData(input.buffer, input.offset);
+            boolean encrypted =
+                    (mExtractor.getSampleFlags() & MediaExtractor.SAMPLE_FLAG_ENCRYPTED) != 0;
+            if (encrypted) {
+                mExtractor.getSampleCryptoInfo(mCryptoInfo);
+            }
             mExtractor.advance();
             mSignaledEos = mExtractor.getSampleTrackIndex() == -1
-                    || timestampUs >= mLastBufferTimestampUs;
+                    || (mLastBufferTimestampUs != null && timestampUs >= mLastBufferTimestampUs);
             MediaCodec.QueueRequest request = codec.getQueueRequest(index);
-            request.setLinearBlock(input.block, input.offset, written);
+            if (encrypted) {
+                request.setEncryptedLinearBlock(
+                        input.block, input.offset, written, mCryptoInfo);
+            } else {
+                request.setLinearBlock(input.block, input.offset, written);
+            }
             request.setPresentationTimeUs(timestampUs);
             request.setFlags(mSignaledEos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
             if (mSetParams) {
@@ -237,17 +328,19 @@
             }
             request.queue();
             input.offset += written;
-            if (mTimestampQueue != null) {
-                mTimestampQueue.offer(timestampUs);
+            if (mTimestampList != null) {
+                mTimestampList.add(timestampUs);
             }
         }
 
         private final MediaExtractor mExtractor;
-        private final long mLastBufferTimestampUs;
+        private final Long mLastBufferTimestampUs;
         private final boolean mObtainBlockForEachBuffer;
-        private final LinkedBlockingQueue<Long> mTimestampQueue;
+        private final List<Long> mTimestampList;
         private boolean mSignaledEos = false;
         private boolean mSetParams = true;
+        private final MediaCodec.CryptoInfo mCryptoInfo = new MediaCodec.CryptoInfo();
+        private final boolean mContentEncrypted;
     }
 
     private static interface OutputSlotListener {
@@ -256,9 +349,9 @@
     }
 
     private static class DummyOutputSlotListener implements OutputSlotListener {
-        public DummyOutputSlotListener(boolean graphic, LinkedBlockingQueue<Long> timestampQueue) {
+        public DummyOutputSlotListener(boolean graphic, List<Long> timestampList) {
             mGraphic = graphic;
-            mTimestampQueue = timestampQueue;
+            mTimestampList = timestampList;
         }
 
         @Override
@@ -273,10 +366,7 @@
                 frame.getLinearBlock().recycle();
             }
 
-            Long ts = mTimestampQueue.peek();
-            if (ts != null && ts == frame.getPresentationTimeUs()) {
-                mTimestampQueue.poll();
-            }
+            mTimestampList.remove(frame.getPresentationTimeUs());
 
             codec.releaseOutputBuffer(index, false);
 
@@ -284,16 +374,16 @@
         }
 
         private final boolean mGraphic;
-        private final LinkedBlockingQueue<Long> mTimestampQueue;
+        private final List<Long> mTimestampList;
     }
 
     private static class SurfaceOutputSlotListener implements OutputSlotListener {
         public SurfaceOutputSlotListener(
                 OutputSurface surface,
-                LinkedBlockingQueue<Long> timestampQueue,
+                List<Long> timestampList,
                 List<FormatChangeEvent> events) {
             mOutputSurface = surface;
-            mTimestampQueue = timestampQueue;
+            mTimestampList = timestampList;
             mEvents = (events != null) ? events : new ArrayList<>();
         }
 
@@ -308,13 +398,11 @@
                 render = true;
             }
 
-            Long ts = mTimestampQueue.peek();
-            if (ts != null && ts == frame.getPresentationTimeUs()) {
-                mTimestampQueue.poll();
-            }
+            mTimestampList.remove(frame.getPresentationTimeUs());
 
             if (!frame.getChangedKeys().isEmpty()) {
-                mEvents.add(new FormatChangeEvent(ts, frame.getChangedKeys(), frame.getFormat()));
+                mEvents.add(new FormatChangeEvent(
+                        frame.getPresentationTimeUs(), frame.getChangedKeys(), frame.getFormat()));
             }
 
             codec.releaseOutputBuffer(index, render);
@@ -326,7 +414,7 @@
         }
 
         private final OutputSurface mOutputSurface;
-        private final LinkedBlockingQueue<Long> mTimestampQueue;
+        private final List<Long> mTimestampList;
         private final List<FormatChangeEvent> mEvents;
     }
 
@@ -344,7 +432,74 @@
             long lastBufferTimestampUs,
             boolean obtainBlockForEachBuffer) {
         return runDecodeShortVideo(
-                inputResourceId, lastBufferTimestampUs, obtainBlockForEachBuffer, null, null);
+                getMediaExtractorForMimeType(inputResourceId, "video/"),
+                lastBufferTimestampUs, obtainBlockForEachBuffer, null, null, null);
+    }
+
+    private static final UUID CLEARKEY_SCHEME_UUID =
+            new UUID(0x1077efecc0b24d02L, 0xace33c1e52e2fb4bL);
+
+    private static final byte[] CLEAR_KEY_CENC = convert(new int[] {
+            0x3f, 0x0a, 0x33, 0xf3, 0x40, 0x98, 0xb9, 0xe2,
+            0x2b, 0xc0, 0x78, 0xe0, 0xa1, 0xb5, 0xe8, 0x54 });
+
+    private static final byte[] DRM_INIT_DATA = convert(new int[] {
+            // BMFF box header (4 bytes size + 'pssh')
+            0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
+            // Full box header (version = 1 flags = 0)
+            0x01, 0x00, 0x00, 0x00,
+            // SystemID
+            0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c,
+            0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+            // Number of key ids
+            0x00, 0x00, 0x00, 0x01,
+            // Key id
+            0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+            0x30, 0x30, 0x30, 0x30, 0x30,
+            // size of data, must be zero
+            0x00, 0x00, 0x00, 0x00 });
+
+    private static final long ENCRYPTED_CONTENT_FIRST_BUFFER_TIMESTAMP_US = 12083333;
+    private static final long ENCRYPTED_CONTENT_LAST_BUFFER_TIMESTAMP_US = 15041666;
+
+    private static byte[] convert(int[] intArray) {
+        byte[] byteArray = new byte[intArray.length];
+        for (int i = 0; i < intArray.length; ++i) {
+            byteArray[i] = (byte)intArray[i];
+        }
+        return byteArray;
+    }
+
+    private boolean runDecodeShortEncryptedVideo(boolean obtainBlockForEachBuffer) {
+        MediaExtractor extractor = new MediaExtractor();
+
+        try (final MediaDrm drm = new MediaDrm(CLEARKEY_SCHEME_UUID)) {
+            Uri uri = Uri.parse(Utils.getMediaPath() + "/clearkey/llama_h264_main_720p_8000.mp4");
+            extractor.setDataSource(uri.toString(), null);
+            extractor.selectTrack(0);
+            extractor.seekTo(12083333, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+            drm.setOnEventListener(
+                    (MediaDrm mediaDrm, byte[] sessionId, int event, int extra, byte[] data) -> {
+                        if (event == MediaDrm.EVENT_KEY_REQUIRED
+                                || event == MediaDrm.EVENT_KEY_EXPIRED) {
+                            MediaDrmClearkeyTest.retrieveKeys(
+                                    mediaDrm, "cenc", sessionId, DRM_INIT_DATA,
+                                    MediaDrm.KEY_TYPE_STREAMING,
+                                    new byte[][] { CLEAR_KEY_CENC });
+                        }
+                    });
+            byte[] sessionId = drm.openSession();
+            MediaDrmClearkeyTest.retrieveKeys(
+                    drm, "cenc", sessionId, DRM_INIT_DATA, MediaDrm.KEY_TYPE_STREAMING,
+                    new byte[][] { CLEAR_KEY_CENC });
+            boolean result = runDecodeShortVideo(
+                    extractor, ENCRYPTED_CONTENT_LAST_BUFFER_TIMESTAMP_US,
+                    obtainBlockForEachBuffer, null /* format */, null /* events */, sessionId);
+            drm.closeSession(sessionId);
+            return result;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
 
     private static class FormatChangeEvent {
@@ -366,18 +521,19 @@
     }
 
     private boolean runDecodeShortVideo(
-            int inputResourceId,
-            long lastBufferTimestampUs,
+            MediaExtractor mediaExtractor,
+            Long lastBufferTimestampUs,
             boolean obtainBlockForEachBuffer,
             MediaFormat format,
-            List<FormatChangeEvent> events) {
+            List<FormatChangeEvent> events,
+            byte[] sessionId) {
         OutputSurface outputSurface = null;
-        MediaExtractor mediaExtractor = null;
         MediaCodec mediaCodec = null;
+        MediaCrypto crypto = null;
         try {
             outputSurface = new OutputSurface(1, 1);
-            mediaExtractor = getMediaExtractorForMimeType(inputResourceId, "video/");
-            MediaFormat mediaFormat = mediaExtractor.getTrackFormat(mediaExtractor.getSampleTrackIndex());
+            MediaFormat mediaFormat = mediaExtractor.getTrackFormat(
+                    mediaExtractor.getSampleTrackIndex());
             if (format != null) {
                 // copy CSD
                 for (int i = 0; i < 3; ++i) {
@@ -396,21 +552,28 @@
             }
             mediaCodec = MediaCodec.createByCodecName(codecs[0]);
 
-            LinkedBlockingQueue<Long> timestampQueue = new LinkedBlockingQueue<>();
+            if (sessionId != null) {
+                crypto = new MediaCrypto(CLEARKEY_SCHEME_UUID, new byte[0] /* initData */);
+                crypto.setMediaDrmSession(sessionId);
+            }
+            List<Long> timestampList = Collections.synchronizedList(new ArrayList<>());
             boolean result = runComponentWithLinearInput(
                     mediaCodec,
+                    crypto,
                     mediaFormat,
                     outputSurface.getSurface(),
                     false,  // encoder
-                    new ExtractorInputSlotListener(
-                            mediaExtractor,
-                            lastBufferTimestampUs,
-                            obtainBlockForEachBuffer,
-                            timestampQueue),
-                    new SurfaceOutputSlotListener(outputSurface, timestampQueue, events));
+                    new ExtractorInputSlotListener.Builder()
+                            .setExtractor(mediaExtractor)
+                            .setLastBufferTimestampUs(lastBufferTimestampUs)
+                            .setObtainBlockForEachBuffer(obtainBlockForEachBuffer)
+                            .setTimestampQueue(timestampList)
+                            .setContentEncrypted(sessionId != null)
+                            .build(),
+                    new SurfaceOutputSlotListener(outputSurface, timestampList, events));
             if (result) {
-                assertTrue("Timestamp should match between input / output",
-                        timestampQueue.isEmpty());
+                assertTrue("Timestamp should match between input / output: " + timestampList,
+                        timestampList.isEmpty());
             }
             return result;
         } catch (IOException e) {
@@ -428,6 +591,9 @@
             if (outputSurface != null) {
                 outputSurface.release();
             }
+            if (crypto != null) {
+                crypto.release();
+            }
         }
     }
 
@@ -449,21 +615,23 @@
             }
             mediaCodec = MediaCodec.createByCodecName(codecs[0]);
 
-            LinkedBlockingQueue<Long> timestampQueue = new LinkedBlockingQueue<>();
+            List<Long> timestampList = Collections.synchronizedList(new ArrayList<>());
             boolean result = runComponentWithLinearInput(
                     mediaCodec,
+                    null,  // crypto
                     mediaFormat,
                     null,  // surface
                     false,  // encoder
-                    new ExtractorInputSlotListener(
-                            mediaExtractor,
-                            lastBufferTimestampUs,
-                            obtainBlockForEachBuffer,
-                            timestampQueue),
-                    new DummyOutputSlotListener(false /* graphic */, timestampQueue));
+                    new ExtractorInputSlotListener.Builder()
+                            .setExtractor(mediaExtractor)
+                            .setLastBufferTimestampUs(lastBufferTimestampUs)
+                            .setObtainBlockForEachBuffer(obtainBlockForEachBuffer)
+                            .setTimestampQueue(timestampList)
+                            .build(),
+                    new DummyOutputSlotListener(false /* graphic */, timestampList));
             if (result) {
-                assertTrue("Timestamp should match between input / output",
-                        timestampQueue.isEmpty());
+                assertTrue("Timestamp should match between input / output: " + timestampList,
+                        timestampList.isEmpty());
             }
             return result;
         } catch (IOException e) {
@@ -499,21 +667,22 @@
             }
             mediaCodec = MediaCodec.createByCodecName(codecs[0]);
 
-            LinkedBlockingQueue<Long> timestampQueue = new LinkedBlockingQueue<>();
+            List<Long> timestampList = Collections.synchronizedList(new ArrayList<>());
             boolean result = runComponentWithLinearInput(
                     mediaCodec,
+                    null,  // crypto
                     mediaFormat,
                     null,  // surface
                     true,  // encoder
-                    new ExtractorInputSlotListener(
-                            mediaExtractor,
-                            LAST_BUFFER_TIMESTAMP_US,
-                            false,
-                            timestampQueue),
-                    new DummyOutputSlotListener(false /* graphic */, timestampQueue));
+                    new ExtractorInputSlotListener.Builder()
+                            .setExtractor(mediaExtractor)
+                            .setLastBufferTimestampUs(LAST_BUFFER_TIMESTAMP_US)
+                            .setTimestampQueue(timestampList)
+                            .build(),
+                    new DummyOutputSlotListener(false /* graphic */, timestampList));
             if (result) {
-                assertTrue("Timestamp should match between input / output",
-                        timestampQueue.isEmpty());
+                assertTrue("Timestamp should match between input / output: " + timestampList,
+                        timestampList.isEmpty());
             }
             return result;
         } catch (IOException e) {
@@ -563,7 +732,7 @@
                 return true;
             }
 
-            LinkedBlockingQueue<Long> timestampQueue = new LinkedBlockingQueue<>();
+            List<Long> timestampList = Collections.synchronizedList(new ArrayList<>());
 
             final LinkedBlockingQueue<SlotEvent> queue = new LinkedBlockingQueue<>();
             mediaCodec.setCallback(new MediaCodec.Callback() {
@@ -642,7 +811,7 @@
                         if (frameIndex >= 32) {
                             signaledEos = true;
                         }
-                        timestampQueue.offer(timestampUs);
+                        timestampList.add(timestampUs);
                         mediaCodec.getQueueRequest(event.index)
                                 .setHardwareBuffer(buffer)
                                 .setPresentationTimeUs(timestampUs)
@@ -658,18 +827,15 @@
                         frame.getLinearBlock().recycle();
                     }
 
-                    Long ts = timestampQueue.peek();
-                    if (ts != null && ts == frame.getPresentationTimeUs()) {
-                        timestampQueue.poll();
-                    }
+                    timestampList.remove(frame.getPresentationTimeUs());
 
                     mediaCodec.releaseOutputBuffer(event.index, false);
                 }
             }
 
-            if (!timestampQueue.isEmpty()) {
-                assertTrue("Timestamp should match between input / output",
-                        timestampQueue.isEmpty());
+            if (!timestampList.isEmpty()) {
+                assertTrue("Timestamp should match between input / output: " + timestampList,
+                        timestampList.isEmpty());
             }
             return eos;
         } catch (IOException e) {
@@ -691,6 +857,7 @@
 
     private boolean runComponentWithLinearInput(
             MediaCodec mediaCodec,
+            MediaCrypto crypto,
             MediaFormat mediaFormat,
             Surface surface,
             boolean encoder,
@@ -723,6 +890,9 @@
             assertTrue("Google default c2.* codecs are copy-free compatible with LinearBlocks",
                     MediaCodec.LinearBlock.isCodecCopyFreeCompatible(codecNames));
         }
+        if (crypto != null) {
+            codecNames[0] = codecNames[0] + ".secure";
+        }
         input.block = MediaCodec.LinearBlock.obtain(
                 APP_BUFFER_SIZE, codecNames);
         assertTrue("Blocks obtained through LinearBlock.obtain must be mappable",
@@ -734,7 +904,7 @@
         if (encoder) {
             flags |= MediaCodec.CONFIGURE_FLAG_ENCODE;
         }
-        mediaCodec.configure(mediaFormat, surface, null, flags);
+        mediaCodec.configure(mediaFormat, surface, crypto, flags);
         mediaCodec.start();
         boolean eos = false;
         boolean signaledEos = false;
@@ -757,15 +927,13 @@
         return eos;
     }
 
-    private MediaExtractor getMediaExtractorForMimeType(int resourceId, String mimeTypePrefix)
-            throws IOException {
+    private MediaExtractor getMediaExtractorForMimeType(int resourceId, String mimeTypePrefix) {
         MediaExtractor mediaExtractor = new MediaExtractor();
-        AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resourceId);
-        try {
+        try (AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resourceId)) {
             mediaExtractor.setDataSource(
                     afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
-        } finally {
-            afd.close();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
         }
         int trackIndex;
         for (trackIndex = 0; trackIndex < mediaExtractor.getTrackCount(); trackIndex++) {
diff --git a/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java b/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java
index 5f9b499..f648a3c 100644
--- a/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaDrmClearkeyTest.java
@@ -138,7 +138,7 @@
      *
      * @return size of keyIds vector that contains the key ids, 0 for error
      */
-    private int getKeyIds(byte[] keyRequestBlob, Vector<String> keyIds) {
+    private static int getKeyIds(byte[] keyRequestBlob, Vector<String> keyIds) {
         if (0 == keyRequestBlob.length || keyIds == null)
             return 0;
 
@@ -163,7 +163,8 @@
      *
      * @return JSON Web Key string.
      */
-    private String createJsonWebKeySet(Vector<String> keyIds, Vector<String> keys, int keyType) {
+    private static String createJsonWebKeySet(
+            Vector<String> keyIds, Vector<String> keys, int keyType) {
         String jwkSet = "{\"keys\":[";
         for (int i = 0; i < keyIds.size(); ++i) {
             String id = new String(keyIds.get(i).getBytes(Charset.forName("UTF-8")));
@@ -184,8 +185,10 @@
     /**
      * Retrieves clear key ids from getKeyRequest(), create JSON Web Key
      * set and send it to the CDM via provideKeyResponse().
+     *
+     * @return key set ID
      */
-    private void getKeys(MediaDrm drm, String initDataType,
+    static byte[] retrieveKeys(MediaDrm drm, String initDataType,
             byte[] sessionId, byte[] drmInitData, int keyType, byte[][] clearKeyIds) {
         MediaDrm.KeyRequest drmRequest = null;
         try {
@@ -197,19 +200,19 @@
         }
         if (drmRequest == null) {
             Log.e(TAG, "Failed getKeyRequest");
-            return;
+            return null;
         }
 
         Vector<String> keyIds = new Vector<String>();
         if (0 == getKeyIds(drmRequest.getData(), keyIds)) {
             Log.e(TAG, "No key ids found in initData");
-            return;
+            return null;
         }
 
         if (clearKeyIds.length != keyIds.size()) {
             Log.e(TAG, "Mismatch number of key ids and keys: ids=" +
                     keyIds.size() + ", keys=" + clearKeyIds.length);
-            return;
+            return null;
         }
 
         // Base64 encodes clearkeys. Keys are known to the application.
@@ -225,7 +228,7 @@
 
         try {
             try {
-                mKeySetId = drm.provideKeyResponse(sessionId, jsonResponse);
+                return drm.provideKeyResponse(sessionId, jsonResponse);
             } catch (IllegalStateException e) {
                 Log.e(TAG, "Failed to provide key response: " + e.toString());
             }
@@ -233,6 +236,16 @@
             e.printStackTrace();
             Log.e(TAG, "Failed to provide key response: " + e.toString());
         }
+        return null;
+    }
+
+    /**
+     * Retrieves clear key ids from getKeyRequest(), create JSON Web Key
+     * set and send it to the CDM via provideKeyResponse().
+     */
+    private void getKeys(MediaDrm drm, String initDataType,
+            byte[] sessionId, byte[] drmInitData, int keyType, byte[][] clearKeyIds) {
+        mKeySetId = retrieveKeys(drm, initDataType, sessionId, drmInitData, keyType, clearKeyIds);
     }
 
     private @NonNull MediaDrm startDrm(final byte[][] clearKeyIds, final String initDataType,
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureActivity.java b/tests/tests/media/src/android/media/cts/MediaProjectionActivity.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/AudioPlaybackCaptureActivity.java
rename to tests/tests/media/src/android/media/cts/MediaProjectionActivity.java
index d74772b..8ec5499 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureActivity.java
+++ b/tests/tests/media/src/android/media/cts/MediaProjectionActivity.java
@@ -43,8 +43,8 @@
 // This is a partial copy of android.view.cts.surfacevalidator.CapturedActivity.
 // Common code should be move in a shared library
 /** Start this activity to retrieve a MediaProjection through waitForMediaProjection() */
-public class AudioPlaybackCaptureActivity extends Activity {
-    private static final String TAG = "AudioPlaybackCaptureActivity";
+public class MediaProjectionActivity extends Activity {
+    private static final String TAG = "MediaProjectionActivity";
     private static final int PERMISSION_CODE = 1;
     private static final int PERMISSION_DIALOG_WAIT_MS = 1000;
     private static final String ACCEPT_RESOURCE_ID = "android:id/button1";
diff --git a/tests/tests/media/src/android/media/cts/MediaProjectionTest.java b/tests/tests/media/src/android/media/cts/MediaProjectionTest.java
new file mode 100644
index 0000000..7bd9c64
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaProjectionTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 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.media.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.projection.MediaProjection;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test MediaProjection lifecycle.
+ *
+ * This test starts and stops a MediaProjection screen capture session using
+ * MediaProjectionActivity.
+ *
+ * Currently we check that we are able to draw overlay windows during the session but not before
+ * or after. (We request SYATEM_ALERT_WINDOW permission, but it is not granted, so by default we
+ * cannot.)
+ *
+ * Note that there are other tests verifying that screen capturing actually works correctly in
+ * CtsWindowManagerDeviceTestCases.
+ */
+@NonMediaMainlineTest
+public class MediaProjectionTest {
+    @Rule
+    public ActivityTestRule<MediaProjectionActivity> mActivityRule =
+            new ActivityTestRule<>(MediaProjectionActivity.class, false, false);
+
+    private MediaProjectionActivity mActivity;
+    private MediaProjection mMediaProjection;
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getContext();
+    }
+
+    @Test
+    public void testOverlayAllowedDuringScreenCapture() throws Exception {
+        assertFalse(Settings.canDrawOverlays(mContext));
+
+        startMediaProjection();
+        assertTrue(Settings.canDrawOverlays(mContext));
+
+        stopMediaProjection();
+        assertFalse(Settings.canDrawOverlays(mContext));
+    }
+
+    private void startMediaProjection() throws Exception {
+        mActivityRule.launchActivity(null);
+        mActivity = mActivityRule.getActivity();
+        mMediaProjection = mActivity.waitForMediaProjection();
+    }
+
+    private void stopMediaProjection() throws Exception {
+        final int STOP_TIMEOUT_MS = 1000;
+        CountDownLatch stoppedLatch = new CountDownLatch(1);
+
+        mMediaProjection.registerCallback(new MediaProjection.Callback() {
+            public void onStop() {
+                stoppedLatch.countDown();
+            }
+        }, new Handler(Looper.getMainLooper()));
+        mMediaProjection.stop();
+
+        assertTrue("Could not stop the MediaProjection in " + STOP_TIMEOUT_MS + "ms",
+                stoppedLatch.await(STOP_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
index 2d1998e..b6be506 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
@@ -121,6 +121,15 @@
         }
     }
 
+    @Test
+    public void testGetRoutesAfterCreation() {
+        List<MediaRoute2Info> initialRoutes = mRouter2.getRoutes();
+        assertFalse(initialRoutes.isEmpty());
+        for (MediaRoute2Info route : initialRoutes) {
+            assertTrue(route.isSystemRoute());
+        }
+    }
+
     /**
      * Tests if we get proper routes for application that has special route type.
      */
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
index d62bc6a..7df46ea 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MediaParserTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import android.media.MediaCodec;
 import android.media.MediaFormat;
 import android.media.MediaParser;
 import android.os.Build;
@@ -29,8 +30,8 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.google.android.exoplayer2.testutil.FakeExtractorInput;
-import com.google.android.exoplayer2.testutil.FakeExtractorOutput;
 import com.google.android.exoplayer2.testutil.TestUtil;
+import com.google.android.exoplayer2.util.Util;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -38,18 +39,19 @@
 import org.junit.runner.RunWith;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Map;
 
 @RunWith(AndroidJUnit4.class)
 public class MediaParserTest {
 
+    private static final String PARAMETER_IN_BAND_CRYPTO_INFO =
+            "android.media.mediaparser.inBandCryptoInfo";
+
     @Before
     public void setUp() {
-        String version = Build.VERSION.CODENAME;
-        // Avoid running these tests before R, on which MediaParser was defined.
-        // These check is inlined from BuildCompat to avoid bringing in the entire dependency.
-        assumeTrue(version.length() == 1 && version.charAt(0) >= 'R' && version.charAt(0) <= 'Z');
+        assumeTrue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R);
     }
 
     @Test
@@ -203,8 +205,7 @@
 
     @Test
     public void testLackOfSupportForUnsupportedParameter() {
-        MediaParser mediaParser =
-                MediaParser.create(new MockMediaParserOutputConsumer(new FakeExtractorOutput()));
+        MediaParser mediaParser = MediaParser.create(new MockMediaParserOutputConsumer());
         assertThat(mediaParser.supportsParameter("android.media.mediaparser.UNSUPPORTED_PARAMETER"))
                 .isFalse();
         mediaParser.release();
@@ -213,32 +214,32 @@
     // OGG.
 
     @Test
-    public void testOggBearVorbis() throws IOException, InterruptedException {
-        testExtractAsset("ogg/bear_vorbis.ogg");
+    public void testOggBearVorbis() throws IOException {
+        testAssetExtraction("ogg/bear_vorbis.ogg");
     }
 
     @Test
-    public void testOggBear() throws IOException, InterruptedException {
-        testExtractAsset("ogg/bear.opus");
+    public void testOggBear() throws IOException {
+        testAssetExtraction("ogg/bear.opus");
     }
 
     @Test
-    public void testOggBearFlac() throws IOException, InterruptedException {
-        testExtractAsset("ogg/bear_flac.ogg");
+    public void testOggBearFlac() throws IOException {
+        testAssetExtraction("ogg/bear_flac.ogg");
     }
 
     @Test
-    public void testOggNoFlacSeekTable() throws IOException, InterruptedException {
-        testExtractAsset("ogg/bear_flac_noseektable.ogg");
+    public void testOggNoFlacSeekTable() throws IOException {
+        testAssetExtraction("ogg/bear_flac_noseektable.ogg");
     }
 
     @Test
-    public void testOggFlacHeaderSniff() throws IOException, InterruptedException {
+    public void testOggFlacHeaderSniff() throws IOException {
         testSniffAsset("ogg/flac_header", /* expectedExtractorName= */ MediaParser.PARSER_NAME_OGG);
     }
 
     @Test
-    public void testOggOpusHeaderSniff() throws IOException, InterruptedException {
+    public void testOggOpusHeaderSniff() throws IOException {
         try {
             testSniffAsset(
                     "ogg/opus_header", /* expectedExtractorName= */ MediaParser.PARSER_NAME_OGG);
@@ -249,7 +250,7 @@
     }
 
     @Test
-    public void testOggInvalidHeaderSniff() throws IOException, InterruptedException {
+    public void testOggInvalidHeaderSniff() throws IOException {
         try {
             testSniffAsset(
                     "ogg/invalid_ogg_header",
@@ -270,118 +271,116 @@
     // FLAC.
 
     @Test
-    public void testFlacUncommonSampleRateFlac() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_uncommon_sample_rate.flac");
+    public void testFlacUncommonSampleRateFlac() throws IOException {
+        testAssetExtraction("flac/bear_uncommon_sample_rate.flac");
     }
 
     @Test
-    public void testFlacNoSeekTableAndNoNumSamples() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_no_seek_table_no_num_samples.flac");
+    public void testFlacNoSeekTableAndNoNumSamples() throws IOException {
+        testAssetExtraction("flac/bear_no_seek_table_no_num_samples.flac");
     }
 
     @Test
-    public void testFlacWithPicture() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_with_picture.flac");
+    public void testFlacWithPicture() throws IOException {
+        testAssetExtraction("flac/bear_with_picture.flac");
     }
 
     @Test
-    public void testFlacWithVorbisComments() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_with_vorbis_comments.flac");
+    public void testFlacWithVorbisComments() throws IOException {
+        testAssetExtraction("flac/bear_with_vorbis_comments.flac");
     }
 
     @Test
-    public void testFlacOneMetadataBlock() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_one_metadata_block.flac");
+    public void testFlacOneMetadataBlock() throws IOException {
+        testAssetExtraction("flac/bear_one_metadata_block.flac");
     }
 
     @Test
-    public void testFlacNoMinMaxFrameSize() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_no_min_max_frame_size.flac");
+    public void testFlacNoMinMaxFrameSize() throws IOException {
+        testAssetExtraction("flac/bear_no_min_max_frame_size.flac");
     }
 
     @Test
-    public void testFlacNoNumSamples() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_no_num_samples.flac");
+    public void testFlacNoNumSamples() throws IOException {
+        testAssetExtraction("flac/bear_no_num_samples.flac");
     }
 
     @Test
-    public void testFlacWithId3() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear_with_id3.flac");
+    public void testFlacWithId3() throws IOException {
+        testAssetExtraction("flac/bear_with_id3.flac");
     }
 
     @Test
-    public void testFlacSample() throws IOException, InterruptedException {
-        testExtractAsset("flac/bear.flac");
+    public void testFlacSample() throws IOException {
+        testAssetExtraction("flac/bear.flac");
     }
 
     // MP3.
 
     @Test
-    public void testMp3WithNoSeekTableVariableFrameSize() throws IOException, InterruptedException {
-        testExtractAsset("mp3/bear-cbr-variable-frame-size-no-seek-table.mp3");
+    public void testMp3WithNoSeekTableVariableFrameSize() throws IOException {
+        testAssetExtraction("mp3/bear-cbr-variable-frame-size-no-seek-table.mp3");
     }
 
     @Test
-    public void testMp3WithVariableBitrateAndXingHeader() throws IOException, InterruptedException {
-        testExtractAsset("mp3/bear-vbr-xing-header.mp3");
+    public void testMp3WithVariableBitrateAndXingHeader() throws IOException {
+        testAssetExtraction("mp3/bear-vbr-xing-header.mp3");
     }
 
     @Test
-    public void testMp3WithNoSeekTableVariableBitrate() throws IOException, InterruptedException {
-        testExtractAsset("mp3/bear-vbr-no-seek-table.mp3");
+    public void testMp3WithNoSeekTableVariableBitrate() throws IOException {
+        testAssetExtraction("mp3/bear-vbr-no-seek-table.mp3");
     }
 
     @Test
-    public void testMp3WithTrimmedSample() throws IOException, InterruptedException {
-        testExtractAsset("mp3/play-trimmed.mp3");
+    public void testMp3WithTrimmedSample() throws IOException {
+        testAssetExtraction("mp3/play-trimmed.mp3");
     }
 
     @Test
-    public void testMp3WithId3() throws IOException, InterruptedException {
-        testExtractAsset("mp3/bear-id3.mp3");
+    public void testMp3WithId3() throws IOException {
+        testAssetExtraction("mp3/bear-id3.mp3");
     }
 
     // WAV.
 
     @Test
-    public void testWavWithImaAdpcm() throws IOException, InterruptedException {
-        testExtractAsset("wav/sample_ima_adpcm.wav");
+    public void testWavWithImaAdpcm() throws IOException {
+        testAssetExtraction("wav/sample_ima_adpcm.wav");
     }
 
     @Test
-    public void testWav() throws IOException, InterruptedException {
-        testExtractAsset("wav/sample.wav");
+    public void testWav() throws IOException {
+        testAssetExtraction("wav/sample.wav");
     }
 
     // AMR.
 
     @Test
-    public void testAmrNarrowBandSamplesWithConstantBitrateSeeking()
-            throws IOException, InterruptedException {
-        testExtractAsset("amr/sample_nb_cbr.amr");
+    public void testAmrNarrowBandSamplesWithConstantBitrateSeeking() throws IOException {
+        testAssetExtraction("amr/sample_nb_cbr.amr");
     }
 
     @Test
-    public void testAmrNarrowBandSamples() throws IOException, InterruptedException {
-        testExtractAsset("amr/sample_nb.amr");
+    public void testAmrNarrowBandSamples() throws IOException {
+        testAssetExtraction("amr/sample_nb.amr");
     }
 
     @Test
-    public void testAmrWideBandSamples() throws IOException, InterruptedException {
-        testExtractAsset("amr/sample_wb.amr");
+    public void testAmrWideBandSamples() throws IOException {
+        testAssetExtraction("amr/sample_wb.amr");
     }
 
     @Test
-    public void testAmrWideBandSamplesWithConstantBitrateSeeking()
-            throws IOException, InterruptedException {
-        testExtractAsset("amr/sample_wb_cbr.amr");
+    public void testAmrWideBandSamplesWithConstantBitrateSeeking() throws IOException {
+        testAssetExtraction("amr/sample_wb_cbr.amr");
     }
 
     // FLV.
 
     @Test
-    public void testFlv() throws IOException, InterruptedException {
-        testExtractAsset("flv/sample.flv");
+    public void testFlv() throws IOException {
+        testAssetExtraction("flv/sample.flv");
     }
 
     // PS.
@@ -389,38 +388,37 @@
     // TODO: Enable once the timeout is fixed.
     @Test
     @Ignore
-    public void testPsElphantsDream() throws IOException, InterruptedException {
-        testExtractAsset("ts/elephants_dream.mpg");
+    public void testPsElphantsDream() throws IOException {
+        testAssetExtraction("ts/elephants_dream.mpg");
     }
 
     @Test
-    public void testPsWithAc3() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_ac3.ps");
+    public void testPsWithAc3() throws IOException {
+        testAssetExtraction("ts/sample_ac3.ps");
     }
 
     @Test
-    public void testPsWithH262MpegAudio() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_h262_mpeg_audio.ps");
+    public void testPsWithH262MpegAudio() throws IOException {
+        testAssetExtraction("ts/sample_h262_mpeg_audio.ps");
     }
 
     // ADTS.
 
     @Test
-    public void testAdtsTruncatedWithConstantBitrateSeeking()
-            throws IOException, InterruptedException {
-        testExtractAsset(
+    public void testAdtsTruncatedWithConstantBitrateSeeking() throws IOException {
+        testAssetExtraction(
                 "ts/sample_cbs_truncated.adts",
                 Collections.singletonMap(MediaParser.PARAMETER_ADTS_ENABLE_CBR_SEEKING, true));
     }
 
     @Test
-    public void testAdts() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample.adts");
+    public void testAdts() throws IOException {
+        testAssetExtraction("ts/sample.adts");
     }
 
     @Test
-    public void testAdtsWithConstantBitrateSeeking() throws IOException, InterruptedException {
-        testExtractAsset(
+    public void testAdtsWithConstantBitrateSeeking() throws IOException {
+        testAssetExtraction(
                 "ts/sample_cbs.adts",
                 Collections.singletonMap(MediaParser.PARAMETER_ADTS_ENABLE_CBR_SEEKING, true));
     }
@@ -428,150 +426,195 @@
     // AC-3.
 
     @Test
-    public void testAc3() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample.ac3");
+    public void testAc3() throws IOException {
+        testAssetExtraction("ts/sample.ac3");
     }
 
     // AC-4.
 
     @Test
-    public void testAc4() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample.ac4");
+    public void testAc4() throws IOException {
+        testAssetExtraction("ts/sample.ac4");
     }
 
     // EAC-3.
 
     @Test
-    public void testEac3() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample.eac3");
+    public void testEac3() throws IOException {
+        testAssetExtraction("ts/sample.eac3");
     }
 
     // TS.
 
     @Test
-    public void testTsBigBuckBunny() throws IOException, InterruptedException {
-        testExtractAsset("ts/bbb_2500ms.ts");
+    public void testTsBigBuckBunny() throws IOException {
+        testAssetExtraction("ts/bbb_2500ms.ts");
     }
 
     @Test
-    public void testTsWithH262MpegAudio() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_h262_mpeg_audio.ts");
+    public void testTsWithH262MpegAudio() throws IOException {
+        testAssetExtraction("ts/sample_h262_mpeg_audio.ts");
     }
 
     @Test
-    public void testTsWithH264MpegAudio() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_h264_mpeg_audio.ts");
+    public void testTsWithH264MpegAudio() throws IOException {
+        testAssetExtraction("ts/sample_h264_mpeg_audio.ts");
     }
 
     @Test
-    public void testTsWithH264DetectAccessUnits() throws IOException, InterruptedException {
-        testExtractAsset(
+    public void testTsWithH264DetectAccessUnits() throws IOException {
+        testAssetExtraction(
                 "ts/sample_h264_no_access_unit_delimiters.ts",
                 Collections.singletonMap(MediaParser.PARAMETER_TS_DETECT_ACCESS_UNITS, true));
     }
 
     @Test
-    public void testTsWithH264DtsAudio() throws IOException, InterruptedException {
-        testExtractAsset(
+    public void testTsWithH264DtsAudio() throws IOException {
+        testAssetExtraction(
                 "ts/sample_h264_dts_audio.ts",
                 Collections.singletonMap(
                         MediaParser.PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS, true));
     }
 
     @Test
-    public void testTsWithLatm() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_latm.ts");
+    public void testTsWithLatm() throws IOException {
+        testAssetExtraction("ts/sample_latm.ts");
     }
 
     @Test
-    public void testTsWithSdt() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_with_sdt.ts");
+    public void testTsWithSdt() throws IOException {
+        testAssetExtraction("ts/sample_with_sdt.ts");
     }
 
     @Test
-    public void testTsWithH265() throws IOException, InterruptedException {
-        testExtractAsset("ts/sample_h265.ts");
+    public void testTsWithH265() throws IOException {
+        testAssetExtraction("ts/sample_h265.ts");
     }
 
     // MKV.
 
     @Test
-    public void testMatroskaSubsampleEncryptedNoAltref() throws IOException, InterruptedException {
-        testExtractAsset("mkv/subsample_encrypted_noaltref.webm");
+    public void testMatroskaSubsampleEncryptedNoAltref() throws IOException {
+        testAssetExtraction("mkv/subsample_encrypted_noaltref.webm");
     }
 
     @Test
-    public void testMatroskaFile() throws IOException, InterruptedException {
-        testExtractAsset("mkv/sample.mkv");
+    public void testMatroskaFile() throws IOException {
+        testAssetExtraction("mkv/sample.mkv");
     }
 
     @Test
-    public void testMatroskaFullBlocks() throws IOException, InterruptedException {
-        testExtractAsset("mkv/full_blocks.mkv");
+    public void testMatroskaFullBlocks() throws IOException {
+        testAssetExtraction("mkv/full_blocks.mkv");
     }
 
     @Test
-    public void testMatroskaSubsampleEncryptedAltref() throws IOException, InterruptedException {
-        testExtractAsset("mkv/subsample_encrypted_altref.webm");
+    public void testMatroskaSubsampleEncryptedAltref() throws IOException {
+        testAssetExtraction("mkv/subsample_encrypted_altref.webm");
+    }
+
+    @Test
+    public void testMatroskaOutOfBandCrypto() throws IOException {
+        MockMediaParserOutputConsumer outputConsumer = new MockMediaParserOutputConsumer();
+        MockMediaParserInputReader inputReader =
+                getInputReader("mkv/subsample_encrypted_noaltref.webm");
+        MediaParser mediaParser = MediaParser.create(outputConsumer);
+        // Initialization vectors are 16 bytes in size, as per CryptoInfo documentation.
+        MediaCodec.CryptoInfo expectedCryptoInfo = new MediaCodec.CryptoInfo();
+        expectedCryptoInfo.set(
+                /* newNumSubsamples=*/ 1,
+                /* newNumBytesOfClearData= */ new int[] {2},
+                /* newNumBytesOfEncryptedData= */ new int[] {5},
+                /* newKey= */ Arrays.copyOf(
+                        Util.getBytesFromHexString("01020304050607080910111213141516"), 16),
+                /* newIv= */ Arrays.copyOf(Util.getBytesFromHexString("0101010101010101"), 16),
+                MediaCodec.CRYPTO_MODE_AES_CTR);
+        advanceUntilSample(outputConsumer, inputReader, mediaParser, /* sampleNumber= */ 1);
+        assertEqual(outputConsumer.getLastOutputCryptoInfo(), expectedCryptoInfo);
+        mediaParser.release();
     }
 
     // MP4.
 
     @Test
-    public void testMp4Ac4Fragmented() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_ac4_fragmented.mp4");
+    public void testMp4Ac4Fragmented() throws IOException {
+        testAssetExtraction("mp4/sample_ac4_fragmented.mp4");
     }
 
     @Test
-    public void testMp4AndrdoidSlowMotion() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_android_slow_motion.mp4");
+    public void testMp4AndrdoidSlowMotion() throws IOException {
+        testAssetExtraction("mp4/sample_android_slow_motion.mp4");
     }
 
     @Test
-    public void testMp4FragmentedSei() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_fragmented_sei.mp4");
+    public void testMp4FragmentedSei() throws IOException {
+        testAssetExtraction("mp4/sample_fragmented_sei.mp4");
     }
 
     @Test
-    public void testMp4WithAc4() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_ac4.mp4");
+    public void testMp4WithAc4() throws IOException {
+        testAssetExtraction("mp4/sample_ac4.mp4");
     }
 
     @Test
-    public void testMp4FragmentedSeekable() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_fragmented_seekable.mp4");
+    public void testMp4FragmentedSeekable() throws IOException {
+        testAssetExtraction("mp4/sample_fragmented_seekable.mp4");
     }
 
     @Test
-    public void testMp4WithProtectedAc4() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_ac4_protected.mp4");
+    public void testMp4WithProtectedAc4() throws IOException {
+        testAssetExtraction("mp4/sample_ac4_protected.mp4");
     }
 
     @Test
-    public void testMp4() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample.mp4");
+    public void testMp4() throws IOException {
+        testAssetExtraction("mp4/sample.mp4");
     }
 
     @Test
-    public void testMp4MdatTooLong() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_mdat_too_long.mp4");
+    public void testMp4MdatTooLong() throws IOException {
+        testAssetExtraction("mp4/sample_mdat_too_long.mp4");
     }
 
     @Test
-    public void testMp4Fragmented() throws IOException, InterruptedException {
-        testExtractAsset("mp4/sample_fragmented.mp4");
+    public void testMp4Fragmented() throws IOException {
+        testAssetExtraction("mp4/sample_fragmented.mp4");
+    }
+
+    @Test
+    public void testMp4FragmentedOutOfBandCrypto() throws IOException {
+        MockMediaParserOutputConsumer outputConsumer = new MockMediaParserOutputConsumer();
+        MockMediaParserInputReader inputReader = getInputReader("mp4/sample_ac4_protected.mp4");
+        MediaParser mediaParser = MediaParser.create(outputConsumer);
+        // Initialization vectors are 16 bytes in size, as per CryptoInfo documentation.
+        MediaCodec.CryptoInfo expectedCryptoInfo = new MediaCodec.CryptoInfo();
+        expectedCryptoInfo.set(
+                /* newNumSubsamples=*/ 1,
+                /* newNumBytesOfClearData= */ new int[] {7},
+                /* newNumBytesOfEncryptedData= */ new int[] {360},
+                /* newKey= */ Arrays.copyOf(
+                        Util.getBytesFromHexString("91341951696b5e1ba232439ecec1f12a"), 16),
+                /* newIv= */ Arrays.copyOf(Util.getBytesFromHexString("aab4ed0108dd5267"), 16),
+                MediaCodec.CRYPTO_MODE_AES_CTR);
+        advanceUntilSample(outputConsumer, inputReader, mediaParser, /* sampleNumber= */ 1);
+        assertEqual(outputConsumer.getLastOutputCryptoInfo(), expectedCryptoInfo);
+
+        expectedCryptoInfo.iv = Arrays.copyOf(Util.getBytesFromHexString("aab4ed0108dd5272"), 16);
+        expectedCryptoInfo.numBytesOfEncryptedData = new int[] {488};
+        advanceUntilSample(outputConsumer, inputReader, mediaParser, /* sampleNumber= */ 12);
+        assertEqual(outputConsumer.getLastOutputCryptoInfo(), expectedCryptoInfo);
+
+        mediaParser.release();
     }
 
     // Internal methods.
 
     private static void testCreationByName(String name) {
-        MediaParser.createByName(name, new MockMediaParserOutputConsumer(new FakeExtractorOutput()))
-                .release();
+        MediaParser.createByName(name, new MockMediaParserOutputConsumer()).release();
     }
 
     private static void assertSupportFor(String parameterName) {
-        MediaParser mediaParser =
-                MediaParser.create(new MockMediaParserOutputConsumer(new FakeExtractorOutput()));
+        MediaParser mediaParser = MediaParser.create(new MockMediaParserOutputConsumer());
         assertThat(mediaParser.supportsParameter(parameterName)).isTrue();
         mediaParser.release();
     }
@@ -583,8 +626,7 @@
 
     private static void testParameterSetting(
             String parameterName, Object value, boolean valueIsIllegal) {
-        MediaParser mediaParser =
-                MediaParser.create(new MockMediaParserOutputConsumer(new FakeExtractorOutput()));
+        MediaParser mediaParser = MediaParser.create(new MockMediaParserOutputConsumer());
         boolean illegalArgument = false;
         try {
             mediaParser.setParameter(parameterName, value);
@@ -597,37 +639,33 @@
     }
 
     private static void testSniffAsset(String assetPath, String expectedParserName)
-            throws IOException, InterruptedException {
-        extractAsset(assetPath, Collections.emptyMap(), expectedParserName);
+            throws IOException {
+        testAssetExtraction(assetPath, Collections.emptyMap(), expectedParserName);
     }
 
-    private static void testExtractAsset(String assetPath)
-            throws IOException, InterruptedException {
-        testExtractAsset(assetPath, Collections.emptyMap());
+    private static void testAssetExtraction(String assetPath) throws IOException {
+        testAssetExtraction(assetPath, Collections.emptyMap());
     }
 
-    private static void testExtractAsset(String assetPath, Map<String, Object> parameters)
-            throws IOException, InterruptedException {
-        extractAsset(assetPath, parameters, /* expectedParserName= */ null);
+    private static void testAssetExtraction(String assetPath, Map<String, Object> parameters)
+            throws IOException {
+        testAssetExtraction(assetPath, parameters, /* expectedParserName= */ null);
     }
 
-    private static void extractAsset(
+    private static void testAssetExtraction(
             String assetPath, Map<String, Object> parameters, String expectedParserName)
-            throws IOException, InterruptedException {
-        byte[] assetBytes =
-                TestUtil.getByteArray(
-                        InstrumentationRegistry.getInstrumentation().getContext(), assetPath);
-        MockMediaParserInputReader mockInput =
-                new MockMediaParserInputReader(
-                        new FakeExtractorInput.Builder().setData(assetBytes).build());
+            throws IOException {
+        MockMediaParserInputReader inputReader = getInputReader(assetPath);
+        boolean usingInBandCryptoInfo =
+                (boolean) parameters.getOrDefault(PARAMETER_IN_BAND_CRYPTO_INFO, false);
         MockMediaParserOutputConsumer outputConsumer =
-                new MockMediaParserOutputConsumer(new FakeExtractorOutput());
+                new MockMediaParserOutputConsumer(usingInBandCryptoInfo);
         MediaParser mediaParser = MediaParser.create(outputConsumer);
         for (Map.Entry<String, Object> entry : parameters.entrySet()) {
             mediaParser.setParameter(entry.getKey(), entry.getValue());
         }
 
-        mediaParser.advance(mockInput);
+        mediaParser.advance(inputReader);
         if (expectedParserName != null) {
             assertThat(expectedParserName).isEqualTo(mediaParser.getParserName());
             // We are only checking that the extractor is the right one.
@@ -635,7 +673,7 @@
             return;
         }
 
-        while (mediaParser.advance(mockInput)) {
+        while (mediaParser.advance(inputReader)) {
             // Do nothing.
         }
 
@@ -651,10 +689,10 @@
                                 ? 0
                                 : (durationUs * j) / 3;
                 MediaParser.SeekPoint seekPoint = seekMap.getSeekPoints(timeUs).first;
-                mockInput.reset();
-                mockInput.setPosition((int) seekPoint.position);
+                inputReader.reset();
+                inputReader.setPosition((int) seekPoint.position);
                 mediaParser.seek(seekPoint);
-                while (mediaParser.advance(mockInput)) {
+                while (mediaParser.advance(inputReader)) {
                     // Do nothing.
                 }
                 if (durationUs == MediaParser.SeekMap.UNKNOWN_DURATION) {
@@ -665,6 +703,39 @@
         mediaParser.release();
     }
 
+    private static MockMediaParserInputReader getInputReader(String assetPath) throws IOException {
+        byte[] assetBytes =
+                TestUtil.getByteArray(
+                        InstrumentationRegistry.getInstrumentation().getContext(), assetPath);
+        return new MockMediaParserInputReader(
+                new FakeExtractorInput.Builder().setData(assetBytes).build());
+    }
+
+    private static void advanceUntilSample(
+            MockMediaParserOutputConsumer outputConsumer,
+            MockMediaParserInputReader inputReader,
+            MediaParser mediaParser,
+            int sampleNumber)
+            throws IOException {
+        while (outputConsumer.getCompletedSampleCount() != sampleNumber) {
+            assertThat(mediaParser.advance(inputReader)).isTrue();
+        }
+    }
+
+    private static void assertEqual(
+            MediaCodec.CryptoInfo actualCryptoInfo, MediaCodec.CryptoInfo expectedCryptoInfo) {
+        assertThat(actualCryptoInfo.mode).isEqualTo(expectedCryptoInfo.mode);
+        assertThat(actualCryptoInfo.key).isEqualTo(expectedCryptoInfo.key);
+        assertThat(actualCryptoInfo.iv).isEqualTo(expectedCryptoInfo.iv);
+        assertThat(actualCryptoInfo.numSubSamples).isEqualTo(expectedCryptoInfo.numSubSamples);
+        for (int i = 0; i < actualCryptoInfo.numSubSamples; i++) {
+            assertThat(actualCryptoInfo.numBytesOfClearData[i])
+                    .isEqualTo(expectedCryptoInfo.numBytesOfClearData[i]);
+            assertThat(actualCryptoInfo.numBytesOfEncryptedData[i])
+                    .isEqualTo(expectedCryptoInfo.numBytesOfEncryptedData[i]);
+        }
+    }
+
     // Internal classes.
 
     private static FluentMediaParserSubject assertParsers(String... names) {
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
index b87d825..ff7c677 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
@@ -38,16 +38,33 @@
 
 public class MockMediaParserOutputConsumer implements MediaParser.OutputConsumer {
 
+    private final boolean mUsingInBandCryptoInfo;
     private final FakeExtractorOutput mFakeExtractorOutput;
     private final ArrayList<TrackOutput> mTrackOutputs;
 
-    private MediaParser.SeekMap mSeekMap;
+    @Nullable private MediaParser.SeekMap mSeekMap;
+    private int mCompletedSampleCount;
+    @Nullable private MediaCodec.CryptoInfo mLastOutputCryptoInfo;
 
-    public MockMediaParserOutputConsumer(FakeExtractorOutput fakeExtractorOutput) {
-        mFakeExtractorOutput = fakeExtractorOutput;
+    public MockMediaParserOutputConsumer() {
+        this(/* usingInBandCryptoInfo= */ false);
+    }
+
+    public MockMediaParserOutputConsumer(boolean usingInBandCryptoInfo) {
+        mUsingInBandCryptoInfo = usingInBandCryptoInfo;
+        mFakeExtractorOutput = new FakeExtractorOutput();
         mTrackOutputs = new ArrayList<>();
     }
 
+    public int getCompletedSampleCount() {
+        return mCompletedSampleCount;
+    }
+
+    @Nullable
+    public MediaCodec.CryptoInfo getLastOutputCryptoInfo() {
+        return mLastOutputCryptoInfo;
+    }
+
     public void clearTrackOutputs() {
         mFakeExtractorOutput.clearTrackOutputs();
     }
@@ -105,7 +122,12 @@
             int flags,
             int size,
             int offset,
-            MediaCodec.CryptoInfo cryptoData) {}
+            @Nullable MediaCodec.CryptoInfo cryptoInfo) {
+        mCompletedSampleCount++;
+        if (!mUsingInBandCryptoInfo) {
+            mLastOutputCryptoInfo = cryptoInfo;
+        }
+    }
 
     // Internal methods.
 
diff --git a/tests/tests/multiuser/AndroidManifest.xml b/tests/tests/multiuser/AndroidManifest.xml
index fc6f3d9..17a71d7 100644
--- a/tests/tests/multiuser/AndroidManifest.xml
+++ b/tests/tests/multiuser/AndroidManifest.xml
@@ -19,6 +19,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.multiuser.cts"
           android:targetSandboxVersion="2">
+    <!-- Must be at least 30, otherwise some tests could be invalid. -->
+    <uses-sdk android:targetSdkVersion="30"/>
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java b/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java
new file mode 100644
index 0000000..75aa112
--- /dev/null
+++ b/tests/tests/multiuser/src/android/multiuser/cts/UserManagerTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.multiuser.cts;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.content.Context;
+import android.os.UserManager;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class UserManagerTest {
+
+    /**
+     * Verify that the isUserAGoat() method always returns false for API level 30. This is
+     * because apps targeting R no longer have access to package queries by default.
+     */
+    @Test
+    public void testUserGoat_api30() {
+        final Context context = getInstrumentation().getContext();
+        assertFalse("isUserAGoat() should return false",
+                context.getSystemService(UserManager.class).isUserAGoat());
+    }
+}
diff --git a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
index c6f7184..4ff944f 100644
--- a/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
+++ b/tests/tests/nativehardware/jni/AHardwareBufferGLTest.cpp
@@ -1864,6 +1864,10 @@
     desc.width = 100;
     desc.height = 100;
     desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
+    if (FormatIsYuv(desc.format)) {
+        // YUV formats are only supported for textures, so add texture usage.
+        desc.usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    }
     // This test does not make sense for layered buffers - don't bother testing them.
     if (desc.layers > 1) return;
     if (!SetUpBuffer(desc)) return;
@@ -1905,6 +1909,10 @@
     desc.width = 16;
     desc.height = 16;
     desc.usage = AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY;
+    if (FormatIsYuv(desc.format)) {
+        // YUV formats are only supported for textures, so add texture usage.
+        desc.usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    }
     // This test does not make sense for GL formats. Layered buffers do not support CPU access.
     if ((desc.stride & kGlFormat) || desc.layers > 1) {
         ALOGI("Test skipped: Test is for single-layer HardwareBuffer formats only.");
@@ -2634,4 +2642,4 @@
         AHardwareBuffer_Desc{17, 23, 7, AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, 0, 0, 0, 0}),
     &GetTestName);
 
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
index 46fae33..93a6d91 100644
--- a/tests/tests/net/Android.bp
+++ b/tests/tests/net/Android.bp
@@ -77,6 +77,7 @@
 android_test {
     name: "CtsNetTestCasesLatestSdk",
     defaults: ["CtsNetTestCasesDefaults"],
+    jni_uses_sdk_apis: true,
     min_sdk_version: "29",
     target_sdk_version: "29",
     test_suites: [
diff --git a/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt b/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt
index 03b961b..2824db7 100644
--- a/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/tests/net/src/android/net/cts/NetworkAgentTest.kt
@@ -592,4 +592,50 @@
             assertNull(it.uri)
         }
     }
+
+    @Test
+    fun testTemporarilyUnmeteredCapability() {
+        // This test will create a networks with/without NET_CAPABILITY_TEMPORARILY_NOT_METERED
+        // and check that the callback reflects the capability changes.
+        // First create a request to make sure the network is kept up
+        val request1 = NetworkRequest.Builder()
+                .clearCapabilities()
+                .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+                .build()
+        val callback1 = TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also {
+            registerNetworkCallback(request1, it)
+        }
+        requestNetwork(request1, callback1)
+
+        // Then file the interesting request
+        val request = NetworkRequest.Builder()
+                .clearCapabilities()
+                .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+                .build()
+        val callback = TestableNetworkCallback()
+        requestNetwork(request, callback)
+
+        // Connect the network
+        createConnectedNetworkAgent().let { (agent, _) ->
+            callback.expectAvailableThenValidatedCallbacks(agent.network)
+
+            // Send TEMP_NOT_METERED and check that the callback is called appropriately.
+            val nc1 = NetworkCapabilities(agent.nc)
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+            agent.sendNetworkCapabilities(nc1)
+            callback.expectCapabilitiesThat(agent.network) {
+                it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+            }
+
+            // Remove TEMP_NOT_METERED and check that the callback is called appropriately.
+            val nc2 = NetworkCapabilities(agent.nc)
+                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+            agent.sendNetworkCapabilities(nc2)
+            callback.expectCapabilitiesThat(agent.network) {
+                !it.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
+            }
+        }
+
+        // tearDown() will unregister the requests and agents
+    }
 }
diff --git a/tests/tests/net/src/android/net/cts/NetworkRequestTest.java b/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
index 5e92b41..e8af1b3 100644
--- a/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
+++ b/tests/tests/net/src/android/net/cts/NetworkRequestTest.java
@@ -18,6 +18,7 @@
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -33,11 +34,12 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.NetworkSpecifier;
-import android.net.TelephonyNetworkSpecifier;
+import android.net.UidRange;
 import android.net.wifi.WifiNetworkSpecifier;
 import android.os.Build;
-import android.os.Process;
 import android.os.PatternMatcher;
+import android.os.Process;
+import android.util.ArraySet;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -59,6 +61,20 @@
     private static final String TEST_PACKAGE_NAME = "test.package.name";
     private static final MacAddress ARBITRARY_ADDRESS = MacAddress.fromString("3:5:8:12:9:2");
 
+    private class LocalNetworkSpecifier extends NetworkSpecifier {
+        private final int mId;
+
+        LocalNetworkSpecifier(int id) {
+            mId = id;
+        }
+
+        @Override
+        public boolean canBeSatisfiedBy(NetworkSpecifier other) {
+            return other instanceof LocalNetworkSpecifier
+                && mId == ((LocalNetworkSpecifier) other).mId;
+        }
+    }
+
     @Test
     public void testCapabilities() {
         assertTrue(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build()
@@ -71,6 +87,16 @@
         verifyNoCapabilities(nr);
     }
 
+    @Test
+    public void testTemporarilyNotMeteredCapability() {
+        assertTrue(new NetworkRequest.Builder()
+                .addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build()
+                .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+        assertFalse(new NetworkRequest.Builder()
+                .removeCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED).build()
+                .hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+    }
+
     private void verifyNoCapabilities(NetworkRequest nr) {
         // NetworkCapabilities.mNetworkCapabilities is defined as type long
         final int MAX_POSSIBLE_CAPABILITY = Long.SIZE;
@@ -129,54 +155,108 @@
     @Test
     @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testCanBeSatisfiedBy() {
-        final TelephonyNetworkSpecifier specifier1 = new TelephonyNetworkSpecifier.Builder()
-                .setSubscriptionId(1234 /* subId */)
-                .build();
-        final TelephonyNetworkSpecifier specifier2 = new TelephonyNetworkSpecifier.Builder()
-                .setSubscriptionId(5678 /* subId */)
-                .build();
-        final NetworkCapabilities cap = new NetworkCapabilities()
+        final LocalNetworkSpecifier specifier1 = new LocalNetworkSpecifier(1234 /* id */);
+        final LocalNetworkSpecifier specifier2 = new LocalNetworkSpecifier(5678 /* id */);
+
+        final NetworkCapabilities capCellularMmsInternet = new NetworkCapabilities()
                 .addTransportType(TRANSPORT_CELLULAR)
                 .addCapability(NET_CAPABILITY_MMS)
                 .addCapability(NET_CAPABILITY_INTERNET);
-        final NetworkCapabilities capDualTransport = new NetworkCapabilities(cap)
-                .addTransportType(TRANSPORT_VPN);
-        final NetworkCapabilities capWithSpecifier1 =
-                new NetworkCapabilities(cap).setNetworkSpecifier(specifier1);
-        final NetworkCapabilities capDiffTransportWithSpecifier1 = new NetworkCapabilities()
+        final NetworkCapabilities capCellularVpnMmsInternet =
+                new NetworkCapabilities(capCellularMmsInternet).addTransportType(TRANSPORT_VPN);
+        final NetworkCapabilities capCellularMmsInternetSpecifier1 =
+                new NetworkCapabilities(capCellularMmsInternet).setNetworkSpecifier(specifier1);
+        final NetworkCapabilities capVpnInternetSpecifier1 = new NetworkCapabilities()
                 .addCapability(NET_CAPABILITY_INTERNET)
                 .addTransportType(TRANSPORT_VPN)
                 .setNetworkSpecifier(specifier1);
+        final NetworkCapabilities capCellularMmsInternetMatchallspecifier =
+                new NetworkCapabilities(capCellularMmsInternet)
+                    .setNetworkSpecifier(new MatchAllNetworkSpecifier());
+        final NetworkCapabilities capCellularMmsInternetSpecifier2 =
+                new NetworkCapabilities(capCellularMmsInternet).setNetworkSpecifier(specifier2);
 
-        final NetworkRequest requestWithSpecifier1 = new NetworkRequest.Builder()
+        final NetworkRequest requestCellularInternetSpecifier1 = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_CELLULAR)
                 .addCapability(NET_CAPABILITY_INTERNET)
                 .setNetworkSpecifier(specifier1)
                 .build();
-        assertFalse(requestWithSpecifier1.canBeSatisfiedBy(null));
-        assertFalse(requestWithSpecifier1.canBeSatisfiedBy(new NetworkCapabilities()));
-        assertTrue(requestWithSpecifier1.canBeSatisfiedBy(new NetworkCapabilities(cap)
-                .setNetworkSpecifier(new MatchAllNetworkSpecifier())));
-        assertTrue(requestWithSpecifier1.canBeSatisfiedBy(cap));
-        assertTrue(requestWithSpecifier1.canBeSatisfiedBy(capWithSpecifier1));
-        assertTrue(requestWithSpecifier1.canBeSatisfiedBy(capDualTransport));
-        assertFalse(requestWithSpecifier1.canBeSatisfiedBy(
-                new NetworkCapabilities(cap).setNetworkSpecifier(specifier2)));
+        assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(null));
+        assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(new NetworkCapabilities()));
+        assertTrue(requestCellularInternetSpecifier1.canBeSatisfiedBy(
+                capCellularMmsInternetMatchallspecifier));
+        assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(capCellularMmsInternet));
+        assertTrue(requestCellularInternetSpecifier1.canBeSatisfiedBy(
+                capCellularMmsInternetSpecifier1));
+        assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(capCellularVpnMmsInternet));
+        assertFalse(requestCellularInternetSpecifier1.canBeSatisfiedBy(
+                capCellularMmsInternetSpecifier2));
 
-        final NetworkRequest request = new NetworkRequest.Builder()
+        final NetworkRequest requestCellularInternet = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_CELLULAR)
                 .addCapability(NET_CAPABILITY_INTERNET)
                 .build();
-        assertTrue(request.canBeSatisfiedBy(cap));
-        assertTrue(request.canBeSatisfiedBy(capWithSpecifier1));
-        assertTrue(request.canBeSatisfiedBy(
-                new NetworkCapabilities(cap).setNetworkSpecifier(specifier2)));
-        assertFalse(request.canBeSatisfiedBy(capDiffTransportWithSpecifier1));
-        assertTrue(request.canBeSatisfiedBy(capDualTransport));
+        assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternet));
+        assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternetSpecifier1));
+        assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularMmsInternetSpecifier2));
+        assertFalse(requestCellularInternet.canBeSatisfiedBy(capVpnInternetSpecifier1));
+        assertTrue(requestCellularInternet.canBeSatisfiedBy(capCellularVpnMmsInternet));
+    }
 
-        assertEquals(requestWithSpecifier1.canBeSatisfiedBy(capWithSpecifier1),
-                new NetworkCapabilities(capWithSpecifier1)
-                    .satisfiedByNetworkCapabilities(capWithSpecifier1));
+    @Test
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testInvariantInCanBeSatisfiedBy() {
+        // Test invariant that result of NetworkRequest.canBeSatisfiedBy() should be the same with
+        // NetworkCapabilities.satisfiedByNetworkCapabilities().
+        final LocalNetworkSpecifier specifier1 = new LocalNetworkSpecifier(1234 /* id */);
+        final int uid = Process.myUid();
+        final ArraySet<UidRange> ranges = new ArraySet<>();
+        ranges.add(new UidRange(uid, uid));
+        final NetworkRequest requestCombination = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET)
+                .setLinkUpstreamBandwidthKbps(1000)
+                .setNetworkSpecifier(specifier1)
+                .setSignalStrength(-123)
+                .setUids(ranges).build();
+        final NetworkCapabilities capCell = new NetworkCapabilities.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        assertCorrectlySatisfies(false, requestCombination, capCell);
+
+        final NetworkCapabilities capCellInternet = new NetworkCapabilities.Builder(capCell)
+                .addCapability(NET_CAPABILITY_INTERNET).build();
+        assertCorrectlySatisfies(false, requestCombination, capCellInternet);
+
+        final NetworkCapabilities capCellInternetBW =
+                new NetworkCapabilities.Builder(capCellInternet)
+                    .setLinkUpstreamBandwidthKbps(1024).build();
+        assertCorrectlySatisfies(false, requestCombination, capCellInternetBW);
+
+        final NetworkCapabilities capCellInternetBWSpecifier1 =
+                new NetworkCapabilities.Builder(capCellInternetBW)
+                    .setNetworkSpecifier(specifier1).build();
+        assertCorrectlySatisfies(false, requestCombination, capCellInternetBWSpecifier1);
+
+        final NetworkCapabilities capCellInternetBWSpecifier1Signal =
+                new NetworkCapabilities.Builder(capCellInternetBWSpecifier1)
+                    .setSignalStrength(-123).build();
+        assertCorrectlySatisfies(true, requestCombination,
+                capCellInternetBWSpecifier1Signal);
+
+        final NetworkCapabilities capCellInternetBWSpecifier1SignalUid =
+                new NetworkCapabilities.Builder(capCellInternetBWSpecifier1Signal)
+                    .setOwnerUid(uid)
+                    .setAdministratorUids(new int [] {uid}).build();
+        assertCorrectlySatisfies(true, requestCombination,
+                capCellInternetBWSpecifier1SignalUid);
+    }
+
+    private void assertCorrectlySatisfies(boolean expect, NetworkRequest request,
+            NetworkCapabilities nc) {
+        assertEquals(expect, request.canBeSatisfiedBy(nc));
+        assertEquals(
+                request.canBeSatisfiedBy(nc),
+                request.networkCapabilities.satisfiedByNetworkCapabilities(nc));
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/tests/neuralnetworks/AndroidTest.xml b/tests/tests/neuralnetworks/AndroidTest.xml
index b7894e5..6ec4752 100644
--- a/tests/tests/neuralnetworks/AndroidTest.xml
+++ b/tests/tests/neuralnetworks/AndroidTest.xml
@@ -32,4 +32,8 @@
              in code coverage evaluations) -->
         <option name="native-test-timeout" value="1200000" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.neuralnetworks" />
+    </object>
 </configuration>
diff --git a/tests/tests/neuralnetworks/benchmark/AndroidTest.xml b/tests/tests/neuralnetworks/benchmark/AndroidTest.xml
index e4fea4a..e122f67 100644
--- a/tests/tests/neuralnetworks/benchmark/AndroidTest.xml
+++ b/tests/tests/neuralnetworks/benchmark/AndroidTest.xml
@@ -27,4 +27,8 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.nn.benchmark.cts" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.neuralnetworks" />
+    </object>
 </configuration>
diff --git a/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml b/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
index f1d5cf7..1affa18 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
+++ b/tests/tests/neuralnetworks/tflite_delegate/AndroidTest.xml
@@ -31,4 +31,8 @@
         <!-- test-timeout unit is ms, value = 2 min -->
         <option name="native-test-timeout" value="120000" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.neuralnetworks" />
+    </object>
 </configuration>
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
index 9421128..fbfd309 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
+++ b/tests/tests/notificationlegacy/notificationlegacy29/AndroidTest.xml
@@ -29,4 +29,8 @@
         <option name="runtime-hint" value="5m" />
         <option name="hidden-api-checks" value="false" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.extservices" />
+    </object>
 </configuration>
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java
index 5b70d19..52fe892 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationManager29Test.java
@@ -106,9 +106,9 @@
     private StatusBarNotification findPostedNotification(int id) {
         // notification is a bit asynchronous so it may take a few ms to appear in
         // getActiveNotifications()
-        // we will check for it for up to 300ms before giving up
+        // we will check for it for up to 500ms before giving up
         StatusBarNotification n = null;
-        for (int tries = 3; tries--> 0;) {
+        for (int tries = 5; tries--> 0;) {
             final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
             for (StatusBarNotification sbn : sbns) {
                 Log.d(TAG, "Found " + sbn.getKey());
diff --git a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
index 37f90e9..ef2a0c1 100644
--- a/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/opengl/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -113,15 +113,6 @@
 
         String extensions = mActivity.getExtensionsString();
 
-        final String es30RequiredList[] = {
-            "OES_EGL_image_external_essl3"
-        };
-
-        for (int i = 0; i < es30RequiredList.length; ++i) {
-            assertTrue("OpenGL ES version 3.0+ is missing extension " + es30RequiredList[i],
-                    hasExtension(extensions, es30RequiredList[i]));
-        }
-
         if (getMajorVersion(reportedVersion) != 3 || getMinorVersion(reportedVersion) < 1)
             return;
 
diff --git a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 39d8f1b..d18479d 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -200,6 +200,34 @@
         }
     }
 
+    @AppModeFull(reason = "Uses separate apps for testing")
+    fun testAutoRevoke_whitelistingApis() {
+        withDummyApp {
+            val pm = context.packageManager
+            runWithShellPermissionIdentity {
+                assertFalse(pm.isAutoRevokeWhitelisted(APK_PACKAGE_NAME))
+            }
+
+            runWithShellPermissionIdentity {
+                assertTrue(pm.setAutoRevokeWhitelisted(APK_PACKAGE_NAME, true))
+            }
+            eventually {
+                runWithShellPermissionIdentity {
+                    assertTrue(pm.isAutoRevokeWhitelisted(APK_PACKAGE_NAME))
+                }
+            }
+
+            runWithShellPermissionIdentity {
+                assertTrue(pm.setAutoRevokeWhitelisted(APK_PACKAGE_NAME, false))
+            }
+            eventually {
+                runWithShellPermissionIdentity {
+                    assertFalse(pm.isAutoRevokeWhitelisted(APK_PACKAGE_NAME))
+                }
+            }
+        }
+    }
+
     private fun wakeUpScreen() {
         runShellCommand("input keyevent KEYCODE_WAKEUP")
         runShellCommand("input keyevent 82")
@@ -343,9 +371,9 @@
     }
 
     private fun waitForIdle() {
-        instrumentation.uiAutomation.waitForIdle(2000, 5000)
+        instrumentation.uiAutomation.waitForIdle(1000, 10000)
         Thread.sleep(500)
-        instrumentation.uiAutomation.waitForIdle(2000, 5000)
+        instrumentation.uiAutomation.waitForIdle(1000, 10000)
     }
 
     private inline fun <T> eventually(crossinline action: () -> T): T {
diff --git a/tests/tests/packagewatchdog/AndroidTest.xml b/tests/tests/packagewatchdog/AndroidTest.xml
index 8a4cbbc..23113be 100644
--- a/tests/tests/packagewatchdog/AndroidTest.xml
+++ b/tests/tests/packagewatchdog/AndroidTest.xml
@@ -27,4 +27,8 @@
         <option name="package" value="android.packagewatchdog.cts" />
         <option name="runtime-hint" value="1m" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.extservices" />
+    </object>
 </configuration>
diff --git a/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java b/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
index de9a30b..99fdadb 100755
--- a/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
+++ b/tests/tests/permission/src/android/permission/cts/SplitPermissionsSystemTest.java
@@ -23,6 +23,7 @@
 import static android.Manifest.permission.READ_CALL_LOG;
 import static android.Manifest.permission.READ_CONTACTS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.READ_PHONE_STATE;
 import static android.Manifest.permission.WRITE_CALL_LOG;
 import static android.Manifest.permission.WRITE_CONTACTS;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
@@ -55,6 +56,10 @@
 
     private static final int NO_TARGET = Build.VERSION_CODES.CUR_DEVELOPMENT + 1;
 
+    // Redefined here since it's only present in the system API surface.
+    private static final String READ_PRIVILEGED_PHONE_STATE =
+            "android.permission.READ_PRIVILEGED_PHONE_STATE";
+
     private List<SplitPermissionInfo> mSplitPermissions;
 
     @Before
@@ -108,10 +113,13 @@
                 case READ_EXTERNAL_STORAGE:
                     assertSplit(split, ACCESS_MEDIA_LOCATION, Build.VERSION_CODES.Q);
                     break;
+                case READ_PRIVILEGED_PHONE_STATE:
+                    assertSplit(split, READ_PHONE_STATE, NO_TARGET);
+                    break;
             }
         }
 
-        assertEquals(7, seenSplits.size());
+        assertEquals(8, seenSplits.size());
     }
 
     private void assertSplit(SplitPermissionInfo split, String permission, int targetSdk) {
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index abc63a5..dcc3aef 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -3778,11 +3778,6 @@
     <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
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index 290bcf8..d88c9a9 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -270,6 +270,11 @@
         // Wait for write of the first page.
         waitForWriteAdapterCallback(1);
 
+        runOnMainThread(() -> {
+            addPrinter(FIRST_PRINTER_LOCAL_ID, false);
+            addPrinter(SECOND_PRINTER_LOCAL_ID, false);
+        });
+
         runOnMainThread(() -> assertFalse(sSession.isDestroyed()));
         runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
 
@@ -378,6 +383,11 @@
         // Wait for write of the first page.
         waitForWriteAdapterCallback(1);
 
+        runOnMainThread(() -> {
+            addPrinter(FIRST_PRINTER_LOCAL_ID, false);
+            addPrinter(SECOND_PRINTER_LOCAL_ID, false);
+        });
+
         runOnMainThread(() -> assertFalse(sSession.isDestroyed()));
         runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
 
@@ -468,6 +478,11 @@
         // Wait for write of the first page.
         waitForWriteAdapterCallback(1);
 
+        runOnMainThread(() -> {
+            addPrinter(FIRST_PRINTER_LOCAL_ID, false);
+            addPrinter(SECOND_PRINTER_LOCAL_ID, false);
+        });
+
         runOnMainThread(() -> assertFalse(sSession.isDestroyed()));
         runOnMainThread(() -> assertEquals(0, sSession.getTrackedPrinters().size()));
 
@@ -669,9 +684,6 @@
 
             assertTrue(sSession.isPrinterDiscoveryStarted());
 
-            addPrinter(FIRST_PRINTER_LOCAL_ID, false);
-            addPrinter(SECOND_PRINTER_LOCAL_ID, false);
-
             return null;
         }, invocation -> {
             assertFalse(sSession.isPrinterDiscoveryStarted());
diff --git a/tests/tests/provider/res/raw/testvideo2.mp4 b/tests/tests/provider/res/raw/testvideo2.mp4
new file mode 100644
index 0000000..1be8bee
--- /dev/null
+++ b/tests/tests/provider/res/raw/testvideo2.mp4
Binary files differ
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index 017ef83..feeb87c 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -17,12 +17,19 @@
 package android.provider.cts;
 
 import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.app.UiAutomation;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
@@ -329,6 +336,44 @@
         }
     }
 
+    /**
+     * Extract the average overall color of the given bitmap.
+     * <p>
+     * Internally takes advantage of gaussian blurring that is naturally applied
+     * when downscaling an image.
+     */
+    public static int extractAverageColor(Bitmap bitmap) {
+        final Bitmap res = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(res);
+        final Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        final Rect dst = new Rect(0, 0, 1, 1);
+        canvas.drawBitmap(bitmap, src, dst, null);
+        return res.getPixel(0, 0);
+    }
+
+    public static void assertColorMostlyEquals(int expected, int actual) {
+        assertTrue("Expected " + Integer.toHexString(expected) + " but was "
+                + Integer.toHexString(actual), isColorMostlyEquals(expected, actual));
+    }
+
+    public static void assertColorMostlyNotEquals(int expected, int actual) {
+        assertFalse("Expected " + Integer.toHexString(expected) + " but was "
+                + Integer.toHexString(actual), isColorMostlyEquals(expected, actual));
+    }
+
+    private static boolean isColorMostlyEquals(int expected, int actual) {
+        final float[] expectedHSV = new float[3];
+        final float[] actualHSV = new float[3];
+        Color.colorToHSV(expected, expectedHSV);
+        Color.colorToHSV(actual, actualHSV);
+
+        // Fail if more than a 10% difference in any component
+        if (Math.abs(expectedHSV[0] - actualHSV[0]) > 36) return false;
+        if (Math.abs(expectedHSV[1] - actualHSV[1]) > 0.1f) return false;
+        if (Math.abs(expectedHSV[2] - actualHSV[2]) > 0.1f) return false;
+        return true;
+    }
+
     public static void assertExists(String path) throws IOException {
         assertExists(null, path);
     }
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
index 357e5e8..8a4619e 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsPanelTest.java
@@ -128,6 +128,7 @@
 
     @Test
     public void mediaOutputPanel_withPackageNameExtra_correctPackage() {
+        assumeTrue(mHasTouchScreen);
         launchMediaOutputPanel(TEST_PACKAGE_NAME);
 
         String currentPackage = mDevice.getCurrentPackageName();
@@ -137,6 +138,7 @@
 
     @Test
     public void mediaOutputPanel_noPutPackageNameExtra_correctPackage() {
+        assumeTrue(mHasTouchScreen);
         launchMediaOutputPanel(null /* packageName */);
 
         String currentPackage = mDevice.getCurrentPackageName();
@@ -155,6 +157,7 @@
 
     @Test
     public void mediaOutputPanel_correctTitle() {
+        assumeTrue(mHasTouchScreen);
         launchMediaOutputPanel(TEST_PACKAGE_NAME);
 
         final UiObject2 titleView = mDevice.findObject(By.res(mSettingsPackage, RESOURCE_HEADER));
@@ -223,6 +226,7 @@
 
     @Test
     public void mediaOutputPanel_doneClosesPanel() {
+        assumeTrue(mHasTouchScreen);
         // Launch panel
         launchMediaOutputPanel(TEST_PACKAGE_NAME);
         String currentPackage = mDevice.getCurrentPackageName();
@@ -312,6 +316,7 @@
 
     @Test
     public void mediaOutputPanel_seeMoreButton_doNothing() {
+        assumeTrue(mHasTouchScreen);
         // Launch panel
         launchMediaOutputPanel(TEST_PACKAGE_NAME);
         String currentPackage = mDevice.getCurrentPackageName();
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java
index b45d919..0d0ec25 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Audio_PlaylistsTest.java
@@ -118,6 +118,7 @@
         values.put(Playlists.NAME, name1);
         final Uri playlist = mContentResolver
                 .insert(MediaStore.Audio.Playlists.getContentUri(mVolumeName), values);
+        MediaStore.waitForIdle(mContentResolver);
         try (Cursor c = mContentResolver.query(playlist,
                 new String[] { Playlists.NAME, MediaColumns.DISPLAY_NAME }, null, null)) {
             assertTrue(c.moveToFirst());
@@ -128,6 +129,7 @@
         values.clear();
         values.put(Playlists.NAME, name2);
         mContentResolver.update(playlist, values, null);
+        MediaStore.waitForIdle(mContentResolver);
         try (Cursor c = mContentResolver.query(playlist,
                 new String[] { Playlists.NAME, MediaColumns.DISPLAY_NAME }, null, null)) {
             assertTrue(c.moveToFirst());
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
index 0435a45..df47fac 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
@@ -76,9 +76,6 @@
 public class MediaStore_Images_MediaTest {
     private static final String MIME_TYPE_JPEG = "image/jpeg";
 
-    private static final File EXTERNAL_STORAGE_DIR = Environment.getExternalStorageDirectory();
-    private static final File DCIM_DIR = new File(EXTERNAL_STORAGE_DIR, Environment.DIRECTORY_DCIM);
-
     private Context mContext;
     private ContentResolver mContentResolver;
 
@@ -303,16 +300,21 @@
      */
     @Test
     public void testUpdateAndReplace() throws Exception {
+        Assume.assumeFalse(mVolumeName.equals(MediaStore.VOLUME_EXTERNAL));
+
+        File dir = mContext.getSystemService(StorageManager.class)
+                .getStorageVolume(mExternalImages).getDirectory();
+        File dcimDir = new File(dir, Environment.DIRECTORY_DCIM);
         File file = null;
         try {
             // Create file
-            file = copyResourceToFile(R.raw.scenery, DCIM_DIR, "cts" + System.nanoTime() + ".jpg");
+            file = copyResourceToFile(R.raw.scenery, dcimDir, "cts" + System.nanoTime() + ".jpg");
             final String externalPath = file.getAbsolutePath();
             assertNotNull(MediaStore.scanFile(mContentResolver, file));
 
             // Insert another file, insertedFile doesn't exist in lower file system.
             ContentValues values = new ContentValues();
-            final File insertedFile = new File(DCIM_DIR, "cts" + System.nanoTime() + ".jpg");
+            final File insertedFile = new File(dcimDir, "cts" + System.nanoTime() + ".jpg");
             values.put(Media.DATA, insertedFile.getAbsolutePath());
 
             final Uri uri = mContentResolver.insert(mExternalImages, values);
@@ -337,10 +339,15 @@
 
     @Test
     public void testUpsert() throws Exception {
+        Assume.assumeFalse(mVolumeName.equals(MediaStore.VOLUME_EXTERNAL));
+
+        File dir = mContext.getSystemService(StorageManager.class)
+                .getStorageVolume(mExternalImages).getDirectory();
+        File dcimDir = new File(dir, Environment.DIRECTORY_DCIM);
         File file = null;
         try {
             // Create file
-            file = copyResourceToFile(R.raw.scenery, DCIM_DIR, "cts" + System.nanoTime() + ".jpg");
+            file = copyResourceToFile(R.raw.scenery, dcimDir, "cts" + System.nanoTime() + ".jpg");
             final String externalPath = file.getAbsolutePath();
 
             // Verify a record exists in MediaProvider.
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
index 874d82c..479c3ab 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_ThumbnailsTest.java
@@ -16,8 +16,10 @@
 
 package android.provider.cts.media;
 
+import static android.provider.cts.ProviderTestUtils.assertColorMostlyEquals;
 import static android.provider.cts.ProviderTestUtils.assertExists;
 import static android.provider.cts.ProviderTestUtils.assertNotExists;
+import static android.provider.cts.ProviderTestUtils.extractAverageColor;
 import static android.provider.cts.media.MediaStoreTest.TAG;
 
 import static org.junit.Assert.assertEquals;
@@ -445,7 +447,7 @@
             assertTrue(thumb.getHeight() < full.getHeight());
 
             // Thumbnail should match contents
-            assertColorMostlyEquals(Color.RED, thumb.getPixel(16, 16));
+            assertColorMostlyEquals(Color.RED, extractAverageColor(thumb));
         }
 
         // Verify legacy APIs still work
@@ -463,7 +465,7 @@
                 assertTrue(thumb.getHeight() < full.getHeight());
 
                 // Thumbnail should match contents
-                assertColorMostlyEquals(Color.RED, thumb.getPixel(16, 16));
+                assertColorMostlyEquals(Color.RED, extractAverageColor(thumb));
             }
         }
 
@@ -479,7 +481,7 @@
             // Thumbnail should match updated contents
             ProviderTestUtils.waitForIdle();
             final Bitmap thumb = mContentResolver.loadThumbnail(finalUri, new Size(32, 32), null);
-            assertColorMostlyEquals(Color.BLUE, thumb.getPixel(16, 16));
+            assertColorMostlyEquals(Color.BLUE, extractAverageColor(thumb));
         }
 
         // Delete image contents
@@ -501,12 +503,4 @@
         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/media/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
index 4921586..dca7382 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
@@ -142,10 +142,6 @@
         values.put(Media.MIME_TYPE, "video/3gpp");
         values.put(Media.SIZE, numBytes);
         values.put(Media.TITLE, "testvideo");
-        long dateAdded = System.currentTimeMillis() / 1000;
-        values.put(Media.DATE_ADDED, dateAdded);
-        long dateModified = videoFile.lastModified() / 1000;
-        values.put(Media.DATE_MODIFIED, dateModified);
 
         // insert
         Uri uri = mContentResolver.insert(mExternalVideo, values);
@@ -175,9 +171,6 @@
             assertEquals("video/3gpp", c.getString(c.getColumnIndex(Media.MIME_TYPE)));
             assertEquals("testvideo", c.getString(c.getColumnIndex(Media.TITLE)));
             assertEquals(numBytes, c.getInt(c.getColumnIndex(Media.SIZE)));
-            long realDateAdded = c.getLong(c.getColumnIndex(Media.DATE_ADDED));
-            assertTrue(realDateAdded >= dateAdded);
-            assertEquals(dateModified, c.getLong(c.getColumnIndex(Media.DATE_MODIFIED)));
             assertTrue(c.isNull(c.getColumnIndex(Media.COLOR_STANDARD)));
             assertTrue(c.isNull(c.getColumnIndex(Media.COLOR_TRANSFER)));
             assertTrue(c.isNull(c.getColumnIndex(Media.COLOR_RANGE)));
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
index 31b2e7e..a2859b7 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_ThumbnailsTest.java
@@ -18,10 +18,11 @@
 
 import static android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT;
 import static android.media.MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH;
+import static android.provider.cts.ProviderTestUtils.assertColorMostlyNotEquals;
+import static android.provider.cts.ProviderTestUtils.extractAverageColor;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -228,7 +229,7 @@
         final Bitmap beforeThumb = mResolver.loadThumbnail(finalUri, new Size(64, 64), null);
         assertTrue(beforeThumb.getWidth() < full.getWidth());
         assertTrue(beforeThumb.getHeight() < full.getHeight());
-        final int beforeColor = beforeThumb.getPixel(32, 32);
+        final int beforeColor = extractAverageColor(beforeThumb);
 
         // Verify legacy APIs still work
         if (MediaStore.VOLUME_EXTERNAL.equals(mVolumeName)) {
@@ -244,7 +245,7 @@
         }
 
         // Edit video contents
-        try (InputStream from = mContext.getResources().openRawResource(R.raw.testthumbvideo);
+        try (InputStream from = mContext.getResources().openRawResource(R.raw.testvideo2);
                 OutputStream to = mResolver.openOutputStream(finalUri)) {
             FileUtils.copy(from, to);
         }
@@ -252,8 +253,8 @@
         // Thumbnail should match updated contents
         ProviderTestUtils.waitForIdle();
         final Bitmap afterThumb = mResolver.loadThumbnail(finalUri, new Size(64, 64), null);
-        final int afterColor = afterThumb.getPixel(32, 32);
-        assertNotColorMostlyEquals(beforeColor, afterColor);
+        final int afterColor = extractAverageColor(afterThumb);
+        assertColorMostlyNotEquals(beforeColor, afterColor);
 
         // Delete video contents
         mResolver.delete(finalUri, null, null);
@@ -266,13 +267,4 @@
         } catch (FileNotFoundException expected) {
         }
     }
-
-    /**
-     * Since thumbnails might be bounced through a compression pass, we're okay
-     * if they're mostly equal.
-     */
-    private static void assertNotColorMostlyEquals(int expected, int actual) {
-        assertNotEquals(Integer.toHexString(expected & 0xF0F0F0F0),
-                Integer.toHexString(actual & 0xF0F0F0F0));
-    }
 }
diff --git a/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml b/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml
index 3e8ae7b..a0b2055 100644
--- a/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml
+++ b/tests/tests/sdkextensions/CtsSdkExtensionsTestCases.xml
@@ -26,4 +26,12 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.os.ext.cts" />
     </test>
+
+    <!-- Run CtsSdkExtensionsTestCases when "com.google.android.sdkext" is on device.
+      Otherwise skip. The logic only applies to situations when CtsSdkExtensionsTestCasesdoes
+      is triggered via mts-tradefed. It is disabled for all other *TS.
+    -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.sdkext" />
+    </object>
 </configuration>
diff --git a/tests/tests/secure_element/omapi/Android.bp b/tests/tests/secure_element/omapi/Android.bp
index 925483b..d1e0dab 100644
--- a/tests/tests/secure_element/omapi/Android.bp
+++ b/tests/tests/secure_element/omapi/Android.bp
@@ -12,7 +12,30 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-android_test {
+//////////////////////////////////////////////////////////////////
+// Signed Package
+
+android_test_import {
+    name: "signed-CtsOmapiTestCases",
+    apk: "apk/signed-CtsOmapiTestCases.apk",
+
+    test_suites: [
+        "cts",
+        "vts10",
+        "general-tests",
+        "cts-instant",
+    ],
+    // Make sure the build system doesn't try to resign the APK
+    presigned: true,
+    dex_preopt: {
+        enabled: false,
+    },
+}
+
+//#################################################################
+// Unsigned Package
+
+android_test_helper_app {
     name: "CtsOmapiTestCases",
     defaults: ["cts_defaults"],
     static_libs: [
diff --git a/tests/tests/secure_element/omapi/AndroidTest.xml b/tests/tests/secure_element/omapi/AndroidTest.xml
index 26b5911..b3e6291 100644
--- a/tests/tests/secure_element/omapi/AndroidTest.xml
+++ b/tests/tests/secure_element/omapi/AndroidTest.xml
@@ -23,7 +23,7 @@
     <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="CtsOmapiTestCases.apk"/>
+        <option name="test-file-name" value="signed-CtsOmapiTestCases.apk"/>
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="android.omapi.cts"/>
diff --git a/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk b/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk
new file mode 100644
index 0000000..a6cbfd8
--- /dev/null
+++ b/tests/tests/secure_element/omapi/apk/signed-CtsOmapiTestCases.apk
Binary files differ
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 6c2ac74..ad23b07 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -25,6 +25,10 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <!-- For FileIntegrityManager -->
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
 
     <application android:usesCleartextTraffic="true">
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/security/res/raw/bug_156261521.dng b/tests/tests/security/res/raw/bug_156261521.dng
new file mode 100644
index 0000000..b838844
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_156261521.dng
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java b/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java
index 8ffe485..f463855 100644
--- a/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java
+++ b/tests/tests/security/src/android/security/cts/BitmapFactorySecurityTests.java
@@ -83,4 +83,11 @@
             fail("OOM attempting to decode BMP");
         }
     }
+
+    @SecurityTest
+    public void test_android_bug_156261521() {
+        // Previously decoding this would crash.
+        FileDescriptor exploitImage = getResource(R.raw.bug_156261521);
+        BitmapFactory.decodeFileDescriptor(exploitImage);
+    }
 }
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java
index a595730..0f5b4ed 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerCtsTestsBase.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
+import android.content.LocusId;
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageManager;
@@ -391,10 +392,23 @@
         return makeShortcut(id, "Title-" + id);
     }
 
+    /**
+     * Make a shortcut with an ID and explicit rank.
+     */
     protected ShortcutInfo makeShortcutWithRank(String id, int rank) {
         return makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank, /* locusId =*/ null);
+    }
+
+    /**
+     * Make a shortcut with an ID and a locus ID.
+     */
+    protected ShortcutInfo makeShortcutWithLocusId(String id, String locusId) {
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                new LocusId(locusId));
     }
 
     /**
@@ -403,13 +417,15 @@
     protected ShortcutInfo makeShortcut(String id, String shortLabel) {
         return makeShortcut(
                 id, shortLabel, /* activity =*/ null, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* locusId =*/ null);
     }
 
     protected ShortcutInfo makeShortcut(String id, ComponentName activity) {
         return makeShortcut(
                 id, "Title-" + id, activity, /* icon =*/ null,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* locusId =*/ null);
     }
 
     /**
@@ -418,7 +434,8 @@
     protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
         return makeShortcut(
                 id, "Title-" + id, /* activity =*/ null, icon,
-                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0,
+                /* locusId =*/ null);
     }
 
     /**
@@ -432,6 +449,19 @@
         return ret;
     }
 
+    /**
+     * Makes and array of shortcut IDs.
+     * For example, makeIds("sX", 4, 9) will return {"sX4", "sX5", "sX6", "sX7", "sX8", "sX9"}.
+     */
+    protected String[] makeIds(String prefix, int first, int last) {
+        final int len = last - first + 1;
+        final String[] ret = new String[len];
+        for (int i = 0; i < len; i++) {
+            ret[i] = prefix + (first + i);
+        }
+        return ret;
+    }
+
     protected ShortcutInfo.Builder makeShortcutBuilder(String id) {
         return new ShortcutInfo.Builder(getCurrentCallerContext(), id);
     }
@@ -440,7 +470,7 @@
      * Make a shortcut with details.
      */
     protected ShortcutInfo makeShortcut(String id, String shortLabel, ComponentName activity,
-            Icon icon, Intent intent, int rank) {
+            Icon icon, Intent intent, int rank, LocusId locusId) {
         final ShortcutInfo.Builder b = makeShortcutBuilder(id)
                 .setShortLabel(shortLabel)
                 .setRank(rank)
@@ -453,6 +483,9 @@
         if (icon != null) {
             b.setIcon(icon);
         }
+        if (locusId != null) {
+            b.setLocusId(locusId);
+        }
         return b.build();
     }
 
@@ -550,12 +583,12 @@
     }
 
     protected List<ShortcutInfo> getShortcutsAsLauncher(int flags, String packageName) {
-        return getShortcutsAsLauncher(flags, packageName, null, 0, null);
+        return getShortcutsAsLauncher(flags, packageName, null, 0, null, null);
     }
 
     protected List<ShortcutInfo> getShortcutsAsLauncher(
             int flags, String packageName, String activityName,
-            long changedSince, List<String> ids) {
+            long changedSince, List<String> ids, List<LocusId> locusIds) {
         final ShortcutQuery q = new ShortcutQuery();
         q.setQueryFlags(flags);
         if (packageName != null) {
@@ -569,6 +602,9 @@
         if (ids != null && ids.size() > 0) {
             q.setShortcutIds(ids);
         }
+        if (locusIds != null && locusIds.size() > 0) {
+            q.setLocusIds(locusIds);
+        }
         return getLauncherApps().getShortcuts(q, getUserHandle());
     }
 }
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
index 67d99fe..33b9c90 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerLauncherApiTest.java
@@ -25,6 +25,7 @@
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.retryUntil;
 import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.setDefaultLauncher;
 
+import android.content.LocusId;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Icon;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -146,6 +147,8 @@
 
         runWithCallerWithStrictMode(mPackageContext1, () -> {
             assertTrue(getManager().updateShortcuts(list(
+                    makeShortcutWithLocusId("s1", "ls1"),
+                    makeShortcutWithLocusId("s2", "ls2"),
                     makeShortcut("s3"))));
 
             setTargetActivityOverride("Launcher_manifest_2");
@@ -179,6 +182,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s3", "s4", "s5")
                     .areAllNotWithKeyFieldsOnly();
@@ -187,6 +191,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s1", "s2", "s3", "ms1", "ms21")
                     .areAllNotWithKeyFieldsOnly();
@@ -195,6 +200,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("ms1", "ms21", "ms22")
                     .areAllNotWithKeyFieldsOnly();
@@ -204,6 +210,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s3", "s4", "s5")
                     .areAllWithKeyFieldsOnly();
@@ -213,6 +220,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s3", "s4", "s5", "s1", "s2", "s3", "ms1", "ms21")
                     .areAllNotWithKeyFieldsOnly();
@@ -222,6 +230,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s1", "s2", "s3", "ms1", "ms21", "ms1", "ms21", "ms22")
                     .areAllNotWithKeyFieldsOnly();
@@ -230,6 +239,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s3", "s4", "s5", "s1", "s2", "ms1", "ms21", "ms1", "ms21", "ms22")
                     .areAllNotWithKeyFieldsOnly();
@@ -239,6 +249,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s3", "s4", "s5", "s1", "s2", "ms1", "ms21", "ms1", "ms21", "ms22")
                     .areAllWithKeyFieldsOnly();
@@ -251,6 +262,7 @@
                     mPackageContext2.getPackageName(),
                     null,
                     0,
+                    list(),
                     list()))
                     .haveIds("s2", "s3", "s4", "s5", "ms1", "ms31")
                     ;
@@ -261,6 +273,7 @@
                     mPackageContext1.getPackageName(),
                     "Launcher_manifest_2",
                     0,
+                    list(),
                     list()))
                     .haveIds("ms21", "ms22", "s1", "s5")
                     .areAllNotWithKeyFieldsOnly();
@@ -271,16 +284,29 @@
                     mPackageContext1.getPackageName(),
                     null,
                     0,
-                    list("s1", "s2", "ms1")))
+                    list("s1", "s2", "ms1"),
+                    list()))
                     .haveIds("s1", "s2", "ms1")
                     .areAllNotWithKeyFieldsOnly();
 
+            // With locus ids
+            assertWith(getShortcutsAsLauncher(
+                    FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST,
+                    mPackageContext1.getPackageName(),
+                    null,
+                    0,
+                    list(),
+                    list(new LocusId("ls1"), new LocusId("ls2"))))
+                    .haveIds("s1", "s2")
+                    .areAllNotWithKeyFieldsOnly();
+
             // With time.
             assertWith(getShortcutsAsLauncher(
                     FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST,
                     mPackageContext1.getPackageName(),
                     null,
                     time2,
+                    list(),
                     list()))
                     .haveIds("s4")
                     .areAllNotWithKeyFieldsOnly();
@@ -291,6 +317,7 @@
                     mPackageContext1.getPackageName(),
                     null,
                     time3,
+                    list(),
                     list()))
                     .isEmpty();
             assertWith(getShortcutsAsLauncher(
@@ -298,6 +325,7 @@
                     mPackageContext2.getPackageName(),
                     null,
                     time3,
+                    list(),
                     list()))
                     .isEmpty();
         });
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMaxCountTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMaxCountTest.java
index 5643cad..c19b9bc 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMaxCountTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMaxCountTest.java
@@ -34,87 +34,47 @@
     public void testNumDynamicShortcuts() {
         runWithCallerWithStrictMode(mPackageContext1, () -> {
             assertTrue(getManager().setDynamicShortcuts(list(makeShortcut("s1"))));
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1"),
-                    makeShortcut("s2"),
-                    makeShortcut("s3"),
-                    makeShortcut("s4"),
-                    makeShortcut("s5"),
-                    makeShortcut("s6"),
-                    makeShortcut("s7"),
-                    makeShortcut("s8"),
-                    makeShortcut("s9"),
-                    makeShortcut("s10")
-            )));
+
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("s", 1, 15))));
             assertWith(getManager().getDynamicShortcuts())
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds(makeIds("s", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1x"),
-                    makeShortcut("s2x"),
-                    makeShortcut("s3x"),
-                    makeShortcut("s4x"),
-                    makeShortcut("s5x"),
-                    makeShortcut("s6x"),
-                    makeShortcut("s7x"),
-                    makeShortcut("s8x"),
-                    makeShortcut("s9x"),
-                    makeShortcut("s10x")
-            )));
+
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("sx", 1, 15))));
 
             assertDynamicShortcutCountExceeded(() -> {
-                getManager().setDynamicShortcuts(list(
-                        makeShortcut("s1y"),
-                        makeShortcut("s2y"),
-                        makeShortcut("s3y"),
-                        makeShortcut("s4y"),
-                        makeShortcut("s5y"),
-                        makeShortcut("s6y"),
-                        makeShortcut("s7y"),
-                        makeShortcut("s8y"),
-                        makeShortcut("s9y"),
-                        makeShortcut("s10y"),
-                        makeShortcut("s11y")));
+                getManager().setDynamicShortcuts(makeShortcuts(makeIds("sy", 1, 16)));
             });
+
             assertWith(getManager().getDynamicShortcuts())
-                    .haveIds("s1x", "s2x", "s3x", "s4x", "s5x", "s6x", "s7x", "s8x", "s9x", "s10x")
+                    .haveIds(makeIds("sx", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
 
             assertDynamicShortcutCountExceeded(() -> {
                 getManager().addDynamicShortcuts(list(
-                        makeShortcut("s1y")));
+                        makeShortcut("sy1")));
             });
             assertWith(getManager().getDynamicShortcuts())
-                    .haveIds("s1x", "s2x", "s3x", "s4x", "s5x", "s6x", "s7x", "s8x", "s9x", "s10x")
+                    .haveIds(makeIds("sx", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
-            getManager().removeDynamicShortcuts(list("s10x"));
+            getManager().removeDynamicShortcuts(list("sx15"));
             assertTrue(getManager().addDynamicShortcuts(list(
-                    makeShortcut("s1y"))));
+                    makeShortcut("sy1"))));
 
             assertWith(getManager().getDynamicShortcuts())
-                    .haveIds("s1x", "s2x", "s3x", "s4x", "s5x", "s6x", "s7x", "s8x", "s9x", "s1y")
+                    .haveIds("sx1", "sx2", "sx3", "sx4", "sx5", "sx6", "sx7", "sx8", "sx9", "sx10",
+                            "sx11", "sx12", "sx13", "sx14", "sy1")
                     .areAllDynamic()
                     .areAllEnabled();
 
             getManager().removeAllDynamicShortcuts();
 
-            assertTrue(getManager().addDynamicShortcuts(list(
-                    makeShortcut("s1"),
-                    makeShortcut("s2"),
-                    makeShortcut("s3"),
-                    makeShortcut("s4"),
-                    makeShortcut("s5"),
-                    makeShortcut("s6"),
-                    makeShortcut("s7"),
-                    makeShortcut("s8"),
-                    makeShortcut("s9"),
-                    makeShortcut("s10")
-            )));
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("s", 1, 15))));
             assertWith(getManager().getDynamicShortcuts())
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds(makeIds("s", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
         });
@@ -156,71 +116,42 @@
         // Note since max counts is per activity, testNumDynamicShortcuts_single should just pass.
         testNumDynamicShortcuts();
 
-        // Launcher_manifest_1 has one manifest, so can only add 9 dynamic shortcuts.
+        // Launcher_manifest_1 has one manifest, so can only add 14 dynamic shortcuts.
         runWithCallerWithStrictMode(mPackageContext1, () -> {
             setTargetActivityOverride("Launcher_manifest_1");
 
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1"),
-                    makeShortcut("s2"),
-                    makeShortcut("s3"),
-                    makeShortcut("s4"),
-                    makeShortcut("s5"),
-                    makeShortcut("s6"),
-                    makeShortcut("s7"),
-                    makeShortcut("s8"),
-                    makeShortcut("s9")
-            )));
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("s", 1, 14))));
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher_manifest_1"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9")
+                    .haveIds(makeIds("s", 1, 14))
                     .areAllEnabled();
 
-            assertDynamicShortcutCountExceeded(() -> getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1x"),
-                    makeShortcut("s2x"),
-                    makeShortcut("s3x"),
-                    makeShortcut("s4x"),
-                    makeShortcut("s5x"),
-                    makeShortcut("s6x"),
-                    makeShortcut("s7x"),
-                    makeShortcut("s8x"),
-                    makeShortcut("s9x"),
-                    makeShortcut("s10x")
-            )));
+            assertDynamicShortcutCountExceeded(() -> getManager().setDynamicShortcuts(
+                    makeShortcuts(makeIds("sx", 1, 15))));
             // Not changed.
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher_manifest_1"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9")
+                    .haveIds(makeIds("s", 1, 14))
                     .areAllEnabled();
         });
 
-        // Launcher_manifest_2 has two manifests, so can only add 8.
+        // Launcher_manifest_2 has two manifests, so can only add 13.
         runWithCallerWithStrictMode(mPackageContext1, () -> {
             setTargetActivityOverride("Launcher_manifest_2");
 
-            assertTrue(getManager().addDynamicShortcuts(list(
-                    makeShortcut("s1"),
-                    makeShortcut("s2"),
-                    makeShortcut("s3"),
-                    makeShortcut("s4"),
-                    makeShortcut("s5"),
-                    makeShortcut("s6"),
-                    makeShortcut("s7"),
-                    makeShortcut("s8")
-            )));
+            assertTrue(getManager().addDynamicShortcuts(makeShortcuts(makeIds("s", 1, 13))));
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher_manifest_2"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8")
+                    .haveIds(makeIds("s", 1, 13))
                     .areAllEnabled();
 
             assertDynamicShortcutCountExceeded(() -> getManager().addDynamicShortcuts(list(
-                    makeShortcut("s1x")
+                    makeShortcut("sx1")
             )));
             // Not added.
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher_manifest_2"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8")
+                    .haveIds(makeIds("s", 1, 13))
                     .areAllEnabled();
         });
     }
@@ -228,47 +159,25 @@
     public void testChangeActivity() {
         runWithCallerWithStrictMode(mPackageContext1, () -> {
             setTargetActivityOverride("Launcher");
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1"),
-                    makeShortcut("s2"),
-                    makeShortcut("s3"),
-                    makeShortcut("s4"),
-                    makeShortcut("s5"),
-                    makeShortcut("s6"),
-                    makeShortcut("s7"),
-                    makeShortcut("s8"),
-                    makeShortcut("s9"),
-                    makeShortcut("s10")
-            )));
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("s", 1, 15))));
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds(makeIds("s", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
 
             setTargetActivityOverride("Launcher2");
+            assertTrue(getManager().addDynamicShortcuts(makeShortcuts(makeIds("sb", 1, 15))));
 
-            assertTrue(getManager().addDynamicShortcuts(list(
-                    makeShortcut("s1b"),
-                    makeShortcut("s2b"),
-                    makeShortcut("s3b"),
-                    makeShortcut("s4b"),
-                    makeShortcut("s5b"),
-                    makeShortcut("s6b"),
-                    makeShortcut("s7b"),
-                    makeShortcut("s8b"),
-                    makeShortcut("s9b"),
-                    makeShortcut("s10b")
-            )));
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds(makeIds("s", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled()
 
                     .revertToOriginalList()
                     .selectByActivity(getActivity("Launcher2"))
-                    .haveIds("s1b", "s2b", "s3b", "s4b", "s5b", "s6b", "s7b", "s8b", "s9b", "s10b")
+                    .haveIds(makeIds("sb", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
 
@@ -279,31 +188,33 @@
 
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher"))
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds(makeIds("s", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled()
 
                     .revertToOriginalList()
                     .selectByActivity(getActivity("Launcher2"))
-                    .haveIds("s1b", "s2b", "s3b", "s4b", "s5b", "s6b", "s7b", "s8b", "s9b", "s10b")
+                    .haveIds(makeIds("sb", 1, 15))
                     .areAllDynamic()
                     .areAllEnabled();
 
             // But swapping shortcuts will work.
             assertTrue(getManager().updateShortcuts(list(
                     makeShortcut("s1", getActivity("Launcher2")),
-                    makeShortcut("s1b", getActivity("Launcher"))
+                    makeShortcut("sb1", getActivity("Launcher"))
             )));
 
             assertWith(getManager().getDynamicShortcuts())
                     .selectByActivity(getActivity("Launcher"))
-                    .haveIds("s1b", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds("sb1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11",
+                            "s12", "s13", "s14", "s15")
                     .areAllDynamic()
                     .areAllEnabled()
 
                     .revertToOriginalList()
                     .selectByActivity(getActivity("Launcher2"))
-                    .haveIds("s1", "s2b", "s3b", "s4b", "s5b", "s6b", "s7b", "s8b", "s9b", "s10b")
+                    .haveIds("s1", "sb2", "sb3", "sb4", "sb5", "sb6", "sb7", "sb8", "sb9", "sb10",
+                            "sb11", "sb12", "sb13", "sb14", "sb15")
                     .areAllDynamic()
                     .areAllEnabled();
         });
@@ -311,49 +222,27 @@
 
     public void testWithPinned() {
         runWithCallerWithStrictMode(mPackageContext1, () -> {
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1"),
-                    makeShortcut("s2"),
-                    makeShortcut("s3"),
-                    makeShortcut("s4"),
-                    makeShortcut("s5"),
-                    makeShortcut("s6"),
-                    makeShortcut("s7"),
-                    makeShortcut("s8"),
-                    makeShortcut("s9"),
-                    makeShortcut("s10")
-            )));
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("s", 1, 15))));
         });
 
         setDefaultLauncher(getInstrumentation(), mLauncherContext1);
 
         runWithCallerWithStrictMode(mLauncherContext1, () -> {
             getLauncherApps().pinShortcuts(mPackageContext1.getPackageName(),
-                    list("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"),
+                    list(makeIds("s", 1, 15)),
                     getUserHandle());
         });
 
         runWithCallerWithStrictMode(mPackageContext1, () -> {
-            assertTrue(getManager().setDynamicShortcuts(list(
-                    makeShortcut("s1b"),
-                    makeShortcut("s2b"),
-                    makeShortcut("s3b"),
-                    makeShortcut("s4b"),
-                    makeShortcut("s5b"),
-                    makeShortcut("s6b"),
-                    makeShortcut("s7b"),
-                    makeShortcut("s8b"),
-                    makeShortcut("s9b"),
-                    makeShortcut("s10b")
-            )));
+            assertTrue(getManager().setDynamicShortcuts(makeShortcuts(makeIds("sb", 1, 15))));
 
             assertWith(getManager().getDynamicShortcuts())
-                    .haveIds("s1b", "s2b", "s3b", "s4b", "s5b", "s6b", "s7b", "s8b", "s9b", "s10b")
+                    .haveIds(makeIds("sb", 1, 15))
                     .areAllEnabled()
                     .areAllNotPinned();
 
             assertWith(getManager().getPinnedShortcuts())
-                    .haveIds("s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10")
+                    .haveIds(makeIds("s", 1, 15))
                     .areAllEnabled()
                     .areAllNotDynamic();
         });
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMiscTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMiscTest.java
index b3a6fa1..1d7e8fc 100644
--- a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMiscTest.java
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerMiscTest.java
@@ -34,7 +34,7 @@
     public void testMiscApis() throws Exception {
         ShortcutManager manager = getTestContext().getSystemService(ShortcutManager.class);
 
-        assertEquals(10, manager.getMaxShortcutCountPerActivity());
+        assertEquals(15, manager.getMaxShortcutCountPerActivity());
 
         // during the test, this process always considered to be in the foreground.
         assertFalse(manager.isRateLimitingActive());
diff --git a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
index 1a84f34..cddf6df 100644
--- a/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
+++ b/tests/tests/systemui/src/android/systemui/cts/WindowInsetsBehaviorTests.java
@@ -86,6 +86,7 @@
             "/sdcard/WindowInsetsBehaviorTests";
     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String ARGUMENT_KEY_FORCE_ENABLE = "force_enable_gesture_navigation";
+    private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
     private static final int STEPS = 10;
 
     // The minimum value of the system gesture exclusion limit is 200 dp. The value here should be
@@ -703,6 +704,8 @@
     public void swipeOutsideLimit_systemUiVisible_allEventsCanceled() throws Throwable {
         assumeTrue(hasSystemGestureFeature());
 
+        assumeGestureNavigationMode();
+
         final int swipeCount = 1;
         final boolean insideLimit = false;
         testSystemGestureExclusionLimit(swipeCount, insideLimit, SYSTEM_UI_FLAG_VISIBLE);
@@ -779,6 +782,14 @@
         assumeTrue("Gesture navigation required.", insets[0].left > 0);
     }
 
+    private void assumeGestureNavigationMode() {
+        // TODO: b/153032202 consider the CTS on GSI case.
+        Resources res = mTargetContext.getResources();
+        int naviMode = res.getIdentifier(NAV_BAR_INTERACTION_MODE_RES_NAME, "integer", "android");
+
+        assumeTrue("Gesture navigation required", naviMode == 2);
+    }
+
     /**
      * Set system UI visibility and wait for it is applied by the system.
      *
diff --git a/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java b/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
index c493c5b..80ef505 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BackgroundCallAudioTest.java
@@ -549,7 +549,10 @@
         call.exitBackgroundAudioProcessing(true);
         assertCallState(call, Call.STATE_SIMULATED_RINGING);
         waitOnAllHandlers(getInstrumentation());
-        assertEquals(AudioManager.MODE_RINGTONE, audioManager.getMode());
+        // We expect the audio mode to stay in CALL_SCREENING when going into simulated ringing.
+        if (doesAudioManagerSupportCallScreening) {
+            assertEquals(MODE_CALL_SCREENING, audioManager.getMode());
+        }
         assertConnectionState(connection, Connection.STATE_ACTIVE);
 
         call.answer(VideoProfile.STATE_AUDIO_ONLY);
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
index b7bd6d0..a992b9b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
@@ -407,6 +407,17 @@
             assertTrue("NID is required for registered cells", networkId != Integer.MAX_VALUE);
             assertTrue("BSID is required for registered cells", basestationId != Integer.MAX_VALUE);
         }
+
+        verifyCellIdentityCdmaLocationSanitation(cdma);
+    }
+
+    private void verifyCellIdentityCdmaLocationSanitation(CellIdentityCdma cdma) {
+        CellIdentityCdma sanitized = cdma.sanitizeLocationInfo();
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getNetworkId());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getSystemId());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getBasestationId());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getLongitude());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getLatitude());
     }
 
     private void verifyCellIdentityCdmaParcel(CellIdentityCdma cdma) {
@@ -564,6 +575,15 @@
             assertTrue("MCC is required for registered cells", nr.getMccString() != null);
             assertTrue("MNC is required for registered cells", nr.getMncString() != null);
         }
+
+        verifyCellIdentityNrLocationSanitation(nr);
+    }
+
+    private void verifyCellIdentityNrLocationSanitation(CellIdentityNr nr) {
+        CellIdentityNr sanitized = nr.sanitizeLocationInfo();
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getPci());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getTac());
+        assertEquals(CellInfo.UNAVAILABLE_LONG, sanitized.getNci());
     }
 
     private void verifyCellSignalStrengthNr(CellSignalStrengthNr nr) {
@@ -817,6 +837,16 @@
             assertTrue("MNC is required for registered cells",
                     wcdma.getMncString() != null || wcdma.getMnc() != Integer.MAX_VALUE);
         }
+
+        verifyCellIdentityWcdmaLocationSanitation(wcdma);
+    }
+
+    private void verifyCellIdentityWcdmaLocationSanitation(CellIdentityWcdma wcdma) {
+        CellIdentityWcdma sanitized = wcdma.sanitizeLocationInfo();
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getLac());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getCid());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getPsc());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getUarfcn());
     }
 
     private void verifyCellIdentityWcdmaParcel(CellIdentityWcdma wcdma) {
@@ -927,6 +957,16 @@
             assertTrue("MNC is required for registered cells",
                     gsm.getMncString() != null || gsm.getMnc() != Integer.MAX_VALUE);
         }
+
+        verifyCellIdentityGsmLocationSanitation(gsm);
+    }
+
+    private void verifyCellIdentityGsmLocationSanitation(CellIdentityGsm gms) {
+        CellIdentityGsm sanitized = gms.sanitizeLocationInfo();
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getLac());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getCid());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getArfcn());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getBsic());
     }
 
     private void verifyCellIdentityGsmParcel(CellIdentityGsm gsm) {
@@ -1041,6 +1081,16 @@
             assertTrue("MCC is required for registered cells", tdscdma.getMccString() != null);
             assertTrue("MNC is required for registered cells", tdscdma.getMncString() != null);
         }
+
+        verifyCellIdentityTdscdmaLocationSanitation(tdscdma);
+    }
+
+    private void verifyCellIdentityTdscdmaLocationSanitation(CellIdentityTdscdma tdscdma) {
+        CellIdentityTdscdma sanitized = tdscdma.sanitizeLocationInfo();
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getLac());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getCid());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getCpid());
+        assertEquals(CellInfo.UNAVAILABLE, sanitized.getUarfcn());
     }
 
     private void verifyCellIdentityTdscdmaParcel(CellIdentityTdscdma tdscdma) {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java
index a5e75c5..f5a8477 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java
@@ -15,11 +15,15 @@
  */
 package android.telephony.cts;
 
+import android.os.Parcel;
 import android.telephony.AccessNetworkConstants;
+import android.telephony.CellIdentity;
+import android.telephony.CellIdentityLte;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.TelephonyManager;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
@@ -120,7 +124,7 @@
     }
 
     @Test
-    public void testRegistrationState() {
+    public void testGetRegistrationState() {
         NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
                 .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
                 .build();
@@ -134,4 +138,110 @@
                 .build();
         assertEquals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, nri.getTransportType());
     }
+
+    @Test
+    public void testGetRegisteredPlmn() {
+        final String plmn = "12345";
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setRegisteredPlmn(plmn)
+                .build();
+        assertEquals(plmn, nri.getRegisteredPlmn());
+    }
+
+    @Test
+    public void testGetRejectCause() {
+        final int fakeRejectCause = 123;
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setRejectCause(fakeRejectCause)
+                .build();
+        assertEquals(fakeRejectCause, nri.getRejectCause());
+    }
+
+    @Test
+    public void testIsEmergencyEnabled() {
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setEmergencyOnly(true)
+                .build();
+        assertTrue(nri.isEmergencyEnabled());
+    }
+
+    @Test
+    public void testGetCellIdentity() {
+        final CellIdentity ci = new CellIdentityLte(120 /* MCC */, 260 /* MNC */, 12345 /* CI */,
+                503 /* PCI */, 54321 /* TAC */);
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setCellIdentity(ci)
+                .build();
+        assertEquals(ci, nri.getCellIdentity());
+    }
+
+    @Test
+    public void testIsRegistered() {
+        final int[] registeredStates = new int[] {NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING};
+        for (int state : registeredStates) {
+            NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                    .setRegistrationState(state)
+                    .build();
+            assertTrue(nri.isRegistered());
+        }
+
+        final int[] unregisteredStates = new int[] {
+            NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
+                NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING,
+                NetworkRegistrationInfo.REGISTRATION_STATE_DENIED,
+                NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN};
+        for (int state : unregisteredStates) {
+            NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                    .setRegistrationState(state)
+                    .build();
+            assertFalse(nri.isRegistered());
+        }
+    }
+
+    @Test
+    public void testIsSearching() {
+        final int[] isSearchingStates = new int[] {
+            NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING};
+        for (int state : isSearchingStates) {
+            NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                    .setRegistrationState(state)
+                    .build();
+            assertTrue(nri.isSearching());
+        }
+
+        final int[] isNotSearchingStates = new int[] {
+            NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING,
+                NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING,
+                NetworkRegistrationInfo.REGISTRATION_STATE_HOME,
+                NetworkRegistrationInfo.REGISTRATION_STATE_DENIED,
+                NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN};
+        for (int state : isNotSearchingStates) {
+            NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                    .setRegistrationState(state)
+                    .build();
+            assertFalse(nri.isSearching());
+        }
+    }
+
+    @Test
+    public void testParcel() {
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+                .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+                .setAvailableServices(Arrays.asList(NetworkRegistrationInfo.SERVICE_TYPE_DATA))
+                .setCellIdentity(new CellIdentityLte(120 /* MCC */, 260 /* MNC */, 12345 /* CI */,
+                            503 /* PCI */, 54321 /* TAC */))
+                .setRegisteredPlmn("12345")
+                .build();
+
+        Parcel p = Parcel.obtain();
+        nri.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        NetworkRegistrationInfo newNrs = NetworkRegistrationInfo.CREATOR.createFromParcel(p);
+        assertEquals(nri, newNrs);
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
index cf7bfef..dbb769d 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
@@ -18,6 +18,7 @@
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -384,6 +385,53 @@
         assertNotNull(smsPdu);
     }
 
+    @Test
+    public void testGetSubmitPduEncodedMessage() throws Exception {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        String destinationAddress = "18004664411";
+        String message = "This is a test message";
+
+        byte[] gsmMsg = SmsMessage.getSubmitPduEncodedMessage(true, destinationAddress,
+                message,
+                1, // Encoding code unit size. Pick ENCODING_7BIT here.
+                0, // GSM national language table. It's usually 0.
+                0, // GSM national language table. It's usually 0.
+                1, // Reference number of concatenated SMS. Pick 1 for simplicity.
+                1, // Sequence number of concatenated SMS. Pick 1 for simplicity.
+                2); // Count of messages of concatenated SMS. Pick 2 for simplicity.
+
+        // Encoded gsm message.
+        byte[] expectedGsmMsg = {65, 0, 11, -127, -127, 0, 100, 70, 20, -15, 0, 0, 29, 5, 0, 3, 1,
+                2, 1, -88, -24, -12, 28, -108, -98, -125, -62, 32, 122, 121, 78, 7, -75, -53, -13,
+                121, -8, 92, 6};
+
+        // See comments for gsmMsg.
+        byte[] cdmaMsg = SmsMessage.getSubmitPduEncodedMessage(false, destinationAddress,
+                message, 1, 0, 0, 1, 1, 2);
+
+        // Encoded cdma message.
+        byte[] expectedCdmaMsg = {0, 0, 16, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 1, 8, 10, 10,
+                4, 6, 6, 4, 4, 1, 1, 0, 0, 0, 35, 0, 3, 32, 0, 24, 1, 28, 72, -24, 40, 0, 24, 8, 16,
+                13, 71, 71, -96, -28, -92, -12, 30, 17, 3, -45, -54, 112, 61, -82, 95, -101, -49,
+                -62, -32, 48};
+
+        assertArrayEquals(expectedGsmMsg, gsmMsg);
+        assertArrayEquals(expectedCdmaMsg, cdmaMsg);
+    }
+
+    @Test
+    public void testCreateFromNativeSmsSubmitPdu() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        // Short message with status RECEIVED_READ and size 0. See 3GPP2 C.S0023 3.4.27
+        byte[] submitPdu = {1, 0};
+        SmsMessage sms = SmsMessage.createFromNativeSmsSubmitPdu(submitPdu, true);
+        assertNull(sms);
+    }
+
     private final static char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
             'A', 'B', 'C', 'D', 'E', 'F' };
 
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 d9ab2f3..af6629d 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -2232,7 +2232,7 @@
             return;
         }
         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
-            fail("This test requires two SIM cards.");
+            return;
         }
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
                 (tm) -> tm.setPreferredOpportunisticDataSubscription(
@@ -2368,7 +2368,7 @@
             return;
         }
         if (mTelephonyManager.getPhoneCount() == 2 && activeSubscriptionInfoCount != 2) {
-            fail("This test requires two SIM cards.");
+            return;
         }
 
         List<SubscriptionInfo> subscriptionInfoList =
diff --git a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
index a9097bb..2b4e3ac 100644
--- a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccManagerTest.java
@@ -17,7 +17,9 @@
 package android.telephony.euicc.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.app.PendingIntent;
@@ -39,6 +41,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -311,6 +316,125 @@
         assertEquals(EuiccManager.ERROR_OPERATION_BUSY, 10016);
     }
 
+    @Test
+    public void testSetSupportedCountries() {
+        // Get country list for restoring later.
+        List<String> originalSupportedCountry = mEuiccManager.getSupportedCountries();
+
+        List<String> expectedCountries = Arrays.asList("US", "SG");
+        // Sets supported countries
+        mEuiccManager.setSupportedCountries(expectedCountries);
+
+        // Verify supported countries are expected
+        assertEquals(expectedCountries, mEuiccManager.getSupportedCountries());
+
+        // Restore the original country list
+        mEuiccManager.setSupportedCountries(originalSupportedCountry);
+    }
+
+    @Test
+    public void testSetUnsupportedCountries() {
+        // Get country list for restoring later.
+        List<String> originalUnsupportedCountry = mEuiccManager.getUnsupportedCountries();
+
+        List<String> expectedCountries = Arrays.asList("US", "SG");
+        // Sets unsupported countries
+        mEuiccManager.setUnsupportedCountries(expectedCountries);
+
+        // Verify unsupported countries are expected
+        assertEquals(expectedCountries, mEuiccManager.getUnsupportedCountries());
+
+        // Restore the original country list
+        mEuiccManager.setUnsupportedCountries(originalUnsupportedCountry);
+    }
+
+    @Test
+    public void testIsSupportedCountry_returnsTrue_ifCountryIsOnSupportedList() {
+        // Get country list for restoring later.
+        List<String> originalSupportedCountry = mEuiccManager.getSupportedCountries();
+
+        // Sets supported countries
+        mEuiccManager.setSupportedCountries(Arrays.asList("US", "SG"));
+
+        // Verify the country is supported
+        assertTrue(mEuiccManager.isSupportedCountry("US"));
+
+        // Restore the original country list
+        mEuiccManager.setSupportedCountries(originalSupportedCountry);
+    }
+
+    @Test
+    public void testIsSupportedCountry_returnsTrue_ifCountryIsNotOnUnsupportedList() {
+        // Get country list for restoring later.
+        List<String> originalSupportedCountry = mEuiccManager.getSupportedCountries();
+        List<String> originalUnsupportedCountry = mEuiccManager.getUnsupportedCountries();
+
+        // Sets supported countries
+        mEuiccManager.setSupportedCountries(new ArrayList<>());
+        // Sets unsupported countries
+        mEuiccManager.setUnsupportedCountries(Arrays.asList("SG"));
+
+        // Verify the country is supported
+        assertTrue(mEuiccManager.isSupportedCountry("US"));
+
+        // Restore the original country list
+        mEuiccManager.setSupportedCountries(originalSupportedCountry);
+        mEuiccManager.setUnsupportedCountries(originalUnsupportedCountry);
+    }
+
+    @Test
+    public void testIsSupportedCountry_returnsFalse_ifCountryIsNotOnSupportedList() {
+        // Get country list for restoring later.
+        List<String> originalSupportedCountry = mEuiccManager.getSupportedCountries();
+
+        // Sets supported countries
+        mEuiccManager.setSupportedCountries(Arrays.asList("SG"));
+
+        // Verify the country is not supported
+        assertFalse(mEuiccManager.isSupportedCountry("US"));
+
+        // Restore the original country list
+        mEuiccManager.setSupportedCountries(originalSupportedCountry);
+    }
+
+    @Test
+    public void testIsSupportedCountry_returnsFalse_ifCountryIsOnUnsupportedList() {
+        // Get country list for restoring later.
+        List<String> originalSupportedCountry = mEuiccManager.getSupportedCountries();
+        List<String> originalUnsupportedCountry = mEuiccManager.getUnsupportedCountries();
+
+        // Sets supported countries
+        mEuiccManager.setSupportedCountries(new ArrayList<>());
+        // Sets unsupported countries
+        mEuiccManager.setUnsupportedCountries(Arrays.asList("US"));
+
+        // Verify the country is not supported
+        assertFalse(mEuiccManager.isSupportedCountry("US"));
+
+        // Restore the original country list
+        mEuiccManager.setSupportedCountries(originalSupportedCountry);
+        mEuiccManager.setUnsupportedCountries(originalUnsupportedCountry);
+    }
+
+    @Test
+    public void testIsSupportedCountry_returnsFalse_ifBothListsAreEmpty() {
+        // Get country list for restoring later.
+        List<String> originalSupportedCountry = mEuiccManager.getSupportedCountries();
+        List<String> originalUnsupportedCountry = mEuiccManager.getUnsupportedCountries();
+
+        // Sets supported countries
+        mEuiccManager.setSupportedCountries(new ArrayList<>());
+        // Sets unsupported countries
+        mEuiccManager.setUnsupportedCountries(new ArrayList<>());
+
+        // Verify the country is supported
+        assertTrue(mEuiccManager.isSupportedCountry("US"));
+
+        // Restore the original country list
+        mEuiccManager.setSupportedCountries(originalSupportedCountry);
+        mEuiccManager.setUnsupportedCountries(originalUnsupportedCountry);
+    }
+
     private Context getContext() {
         return InstrumentationRegistry.getContext();
     }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
index cddf19e..a965d7b 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsMmTelManagerTest.java
@@ -99,7 +99,11 @@
 
     @BeforeClass
     public static void beforeAllTests() {
-        assumeTrue(ImsUtils.shouldTestImsService());
+        // assumeTrue() in @BeforeClass is not supported by our test runner.
+        // Resort to the early exit.
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
 
         sTestSub = ImsUtils.getPreferredActiveSubId();
 
@@ -116,6 +120,12 @@
 
     @AfterClass
     public static void afterAllTests() {
+        // assumeTrue() in @AfterClass is not supported by our test runner.
+        // Resort to the early exit.
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
         if (sReceiver != null) {
             getContext().unregisterReceiver(sReceiver);
             sReceiver = null;
@@ -124,6 +134,8 @@
 
     @Before
     public void beforeTest() {
+        assumeTrue(ImsUtils.shouldTestImsService());
+
         if (!SubscriptionManager.isValidSubscriptionId(sTestSub)) {
             fail("This test requires that there is a SIM in the device!");
         }
diff --git a/tests/tests/tethering/AndroidTest.xml b/tests/tests/tethering/AndroidTest.xml
index d0a2bce..e752e3a 100644
--- a/tests/tests/tethering/AndroidTest.xml
+++ b/tests/tests/tethering/AndroidTest.xml
@@ -28,4 +28,8 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.tethering.cts" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.tethering" />
+    </object>
 </configuration>
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
index bbb9403..8665c7e 100644
--- a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -26,7 +26,6 @@
 import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
 import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
 import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
@@ -59,7 +58,10 @@
 import android.net.cts.util.CtsNetUtils;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.os.ResultReceiver;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import androidx.annotation.NonNull;
@@ -676,6 +678,26 @@
             mTM.requestLatestTetheringEntitlementResult(
                     TETHERING_WIFI, false, c -> c.run(), null);
         } catch (IllegalArgumentException expect) { }
+
+        // Override carrier config to ignore entitlement check.
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, false);
+        overrideCarrierConfig(bundle);
+
+        // Verify that requestLatestTetheringEntitlementResult() can get entitlement
+        // result TETHER_ERROR_NO_ERROR due to provisioning bypassed.
+        assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
+                TETHERING_WIFI, false, c -> c.run(), listener), TETHER_ERROR_NO_ERROR);
+
+        // Reset carrier config.
+        overrideCarrierConfig(null);
+    }
+
+    private void overrideCarrierConfig(PersistableBundle bundle) {
+        final CarrierConfigManager configManager = (CarrierConfigManager) mContext
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        final int subId = SubscriptionManager.getDefaultSubscriptionId();
+        configManager.overrideConfig(subId, bundle);
     }
 
     @Test
diff --git a/tests/tests/textclassifier/AndroidTest.xml b/tests/tests/textclassifier/AndroidTest.xml
index 1815643..f7e25ff 100644
--- a/tests/tests/textclassifier/AndroidTest.xml
+++ b/tests/tests/textclassifier/AndroidTest.xml
@@ -30,4 +30,9 @@
         <option name="hidden-api-checks" value="false" />
         <option name="isolated-storage" value="false" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.extservices" />
+    </object>
+
 </configuration>
diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java
index 86e63a5..92e5539 100644
--- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java
+++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerFrontendTest.java
@@ -93,6 +93,7 @@
                         .setSifStandard(AnalogFrontendSettings.SIF_BG_NICAM)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_ANALOG, settings.getType());
         assertEquals(1, settings.getFrequency());
         assertEquals(AnalogFrontendSettings.SIGNAL_TYPE_NTSC, settings.getSignalType());
         assertEquals(AnalogFrontendSettings.SIF_BG_NICAM, settings.getSifStandard());
@@ -131,6 +132,7 @@
                         .setPlpSettings(new Atsc3PlpSettings[] {plp1, plp2})
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_ATSC3, settings.getType());
         assertEquals(2, settings.getFrequency());
         assertEquals(Atsc3FrontendSettings.BANDWIDTH_BANDWIDTH_6MHZ, settings.getBandwidth());
         assertEquals(Atsc3FrontendSettings.MODULATION_MOD_QPSK, settings.getDemodOutputFormat());
@@ -161,6 +163,7 @@
                         .setModulation(AtscFrontendSettings.MODULATION_MOD_8VSB)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_ATSC, settings.getType());
         assertEquals(3, settings.getFrequency());
         assertEquals(AtscFrontendSettings.MODULATION_MOD_8VSB, settings.getModulation());
     }
@@ -180,6 +183,7 @@
                         .setSpectralInversion(DvbcFrontendSettings.SPECTRAL_INVERSION_NORMAL)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_DVBC, settings.getType());
         assertEquals(4, settings.getFrequency());
         assertEquals(DvbcFrontendSettings.MODULATION_MOD_32QAM, settings.getModulation());
         assertEquals(FrontendSettings.FEC_8_15, settings.getInnerFec());
@@ -217,6 +221,7 @@
                         .setVcmMode(DvbsFrontendSettings.VCM_MODE_MANUAL)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_DVBS, settings.getType());
         assertEquals(5, settings.getFrequency());
         assertEquals(DvbsFrontendSettings.MODULATION_MOD_ACM, settings.getModulation());
         assertEquals(3, settings.getSymbolRate());
@@ -256,6 +261,7 @@
                         .setPlpGroupId(777)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_DVBT, settings.getType());
         assertEquals(6, settings.getFrequency());
         assertEquals(DvbtFrontendSettings.TRANSMISSION_MODE_8K, settings.getTransmissionMode());
         assertEquals(DvbtFrontendSettings.BANDWIDTH_1_7MHZ, settings.getBandwidth());
@@ -287,6 +293,7 @@
                         .setRolloff(Isdbs3FrontendSettings.ROLLOFF_0_03)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_ISDBS3, settings.getType());
         assertEquals(7, settings.getFrequency());
         assertEquals(2, settings.getStreamId());
         assertEquals(IsdbsFrontendSettings.STREAM_ID_TYPE_ID, settings.getStreamIdType());
@@ -311,6 +318,7 @@
                         .setRolloff(IsdbsFrontendSettings.ROLLOFF_0_35)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_ISDBS, settings.getType());
         assertEquals(8, settings.getFrequency());
         assertEquals(3, settings.getStreamId());
         assertEquals(
@@ -336,6 +344,7 @@
                         .setServiceAreaId(10)
                         .build();
 
+        assertEquals(FrontendSettings.TYPE_ISDBT, settings.getType());
         assertEquals(9, settings.getFrequency());
         assertEquals(IsdbtFrontendSettings.MODULATION_MOD_64QAM, settings.getModulation());
         assertEquals(IsdbtFrontendSettings.BANDWIDTH_8MHZ, settings.getBandwidth());
@@ -357,6 +366,7 @@
             assertTrue(info.getSymbolRateRange().getLower() >= 0);
             assertTrue(info.getAcquireRange() > 0);
             info.getExclusiveGroupId();
+            info.getStatusCapabilities();
 
             FrontendCapabilities caps = info.getFrontendCapabilities();
             assertNotNull(caps);
diff --git a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
index 08b2c25..a63d7e3 100644
--- a/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
+++ b/tests/tests/tv/src/android/media/tv/tuner/cts/TunerTest.java
@@ -17,11 +17,13 @@
 package android.media.tv.tuner.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+
 import android.media.tv.tuner.Descrambler;
 import android.media.tv.tuner.LnbCallback;
 import android.media.tv.tuner.Lnb;
@@ -30,10 +32,20 @@
 import android.media.tv.tuner.dvr.DvrRecorder;
 import android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener;
 import android.media.tv.tuner.dvr.OnRecordStatusChangedListener;
+
+import android.media.tv.tuner.filter.AudioDescriptor;
+import android.media.tv.tuner.filter.DownloadEvent;
 import android.media.tv.tuner.filter.FilterCallback;
 import android.media.tv.tuner.filter.FilterEvent;
 import android.media.tv.tuner.filter.Filter;
+import android.media.tv.tuner.filter.IpPayloadEvent;
+import android.media.tv.tuner.filter.MediaEvent;
+import android.media.tv.tuner.filter.MmtpRecordEvent;
+import android.media.tv.tuner.filter.PesEvent;
+import android.media.tv.tuner.filter.SectionEvent;
+import android.media.tv.tuner.filter.TemiEvent;
 import android.media.tv.tuner.filter.TimeFilter;
+import android.media.tv.tuner.filter.TsRecordEvent;
 
 import android.media.tv.tuner.frontend.AnalogFrontendCapabilities;
 import android.media.tv.tuner.frontend.AnalogFrontendSettings;
@@ -53,6 +65,7 @@
 import android.media.tv.tuner.frontend.FrontendCapabilities;
 import android.media.tv.tuner.frontend.FrontendInfo;
 import android.media.tv.tuner.frontend.FrontendSettings;
+import android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpTuningInfo;
 import android.media.tv.tuner.frontend.FrontendStatus;
 import android.media.tv.tuner.frontend.Isdbs3FrontendCapabilities;
 import android.media.tv.tuner.frontend.Isdbs3FrontendSettings;
@@ -202,7 +215,14 @@
         status.getFreqOffset();
         status.getHierarchy();
         status.isRfLocked();
-        status.getAtsc3PlpTuningInfo();
+        Atsc3PlpTuningInfo[] tuningInfos = status.getAtsc3PlpTuningInfo();
+        if (tuningInfos != null) {
+            for (Atsc3PlpTuningInfo tuningInfo : tuningInfos) {
+                tuningInfo.getPlpId();
+                tuningInfo.isLocked();
+                tuningInfo.getUec();
+            }
+        }
     }
 
     @Test
@@ -291,12 +311,114 @@
     private FilterCallback getFilterCallback() {
         return new FilterCallback() {
             @Override
-            public void onFilterEvent(Filter filter, FilterEvent[] events) {}
+            public void onFilterEvent(Filter filter, FilterEvent[] events) {
+                for (FilterEvent e : events) {
+                    if (e instanceof DownloadEvent) {
+                        testDownloadEvent(filter, (DownloadEvent) e);
+                    } else if (e instanceof IpPayloadEvent) {
+                        testIpPayloadEvent(filter, (IpPayloadEvent) e);
+                    } else if (e instanceof MediaEvent) {
+                        testMediaEvent(filter, (MediaEvent) e);
+                    } else if (e instanceof MmtpRecordEvent) {
+                        testMmtpRecordEvent(filter, (MmtpRecordEvent) e);
+                    } else if (e instanceof PesEvent) {
+                        testPesEvent(filter, (PesEvent) e);
+                    } else if (e instanceof SectionEvent) {
+                        testSectionEvent(filter, (SectionEvent) e);
+                    } else if (e instanceof TemiEvent) {
+                        testTemiEvent(filter, (TemiEvent) e);
+                    } else if (e instanceof TsRecordEvent) {
+                        testTsRecordEvent(filter, (TsRecordEvent) e);
+                    }
+                }
+            }
             @Override
             public void onFilterStatusChanged(Filter filter, int status) {}
         };
     }
 
+    private void testDownloadEvent(Filter filter, DownloadEvent e) {
+        e.getItemId();
+        e.getMpuSequenceNumber();
+        e.getItemFragmentIndex();
+        e.getLastItemFragmentIndex();
+        long length = e.getDataLength();
+        if (length > 0) {
+            byte[] buffer = new byte[(int) length];
+            assertNotEquals(0, filter.read(buffer, 0, length));
+        }
+    }
+
+    private void testIpPayloadEvent(Filter filter, IpPayloadEvent e) {
+        long length = e.getDataLength();
+        if (length > 0) {
+            byte[] buffer = new byte[(int) length];
+            assertNotEquals(0, filter.read(buffer, 0, length));
+        }
+    }
+
+    private void testMediaEvent(Filter filter, MediaEvent e) {
+        e.getStreamId();
+        e.isPtsPresent();
+        e.getPts();
+        e.getDataLength();
+        e.getOffset();
+        e.getLinearBlock();
+        e.isSecureMemory();
+        e.getAvDataId();
+        e.getAudioHandle();
+        e.getMpuSequenceNumber();
+        e.isPrivateData();
+        AudioDescriptor ad = e.getExtraMetaData();
+        if (ad != null) {
+            ad.getAdFade();
+            ad.getAdPan();
+            ad.getAdVersionTextTag();
+            ad.getAdGainCenter();
+            ad.getAdGainFront();
+            ad.getAdGainSurround();
+        }
+    }
+
+    private void testMmtpRecordEvent(Filter filter, MmtpRecordEvent e) {
+        e.getScHevcIndexMask();
+        e.getDataLength();
+    }
+
+    private void testPesEvent(Filter filter, PesEvent e) {
+        e.getStreamId();
+        e.getMpuSequenceNumber();
+        long length = e.getDataLength();
+        if (length > 0) {
+            byte[] buffer = new byte[(int) length];
+            assertNotEquals(0, filter.read(buffer, 0, length));
+        }
+    }
+
+    private void testSectionEvent(Filter filter, SectionEvent e) {
+        e.getTableId();
+        e.getVersion();
+        e.getSectionNumber();
+        long length = e.getDataLength();
+        if (length > 0) {
+            byte[] buffer = new byte[(int) length];
+            assertNotEquals(0, filter.read(buffer, 0, length));
+        }
+    }
+
+    private void testTemiEvent(Filter filter, TemiEvent e) {
+        e.getPts();
+        e.getDescriptorTag();
+        e.getDescriptorData();
+    }
+
+    private void testTsRecordEvent(Filter filter, TsRecordEvent e) {
+        e.getPacketId();
+        e.getTsIndexMask();
+        e.getScIndexMask();
+        e.getDataLength();
+    }
+
     private OnRecordStatusChangedListener getRecordListener() {
         return new OnRecordStatusChangedListener() {
             @Override
@@ -496,7 +618,14 @@
             public void onAnalogSifStandardReported(int sif) {}
 
             @Override
-            public void onAtsc3PlpInfosReported(Atsc3PlpInfo[] atsc3PlpInfos) {}
+            public void onAtsc3PlpInfosReported(Atsc3PlpInfo[] atsc3PlpInfos) {
+                for (Atsc3PlpInfo info : atsc3PlpInfos) {
+                    if (info != null) {
+                        info.getPlpId();
+                        info.getLlsFlag();
+                    }
+                }
+            }
 
             @Override
             public void onHierarchyReported(int hierarchy) {}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
index db5458f..adc1b06 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
@@ -49,8 +49,10 @@
         // Cleanup old tests
         // These are removed on uninstall anyway but just in case...
         File[] toRemove = sDumpDirectory.listFiles();
-        for (File file : toRemove) {
-            deleteContentsAndDir(file);
+        if (toRemove != null && toRemove.length > 0) {
+            for (File file : toRemove) {
+                deleteContentsAndDir(file);
+            }
         }
     }
 
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 66f1cb3..86e674e 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -2928,16 +2928,7 @@
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.isFocused());
 
-        // Tab should not cause focus to leave the multiline textfield.
-        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_TAB);
-        mInstrumentation.waitForIdleSync();
-        assertTrue(mTextView.isFocused());
-
-        // Tab on the singleline TextView should.
-        mActivityRule.runOnUiThread(() -> {
-            mTextView.setSingleLine(true);
-        });
-        mInstrumentation.waitForIdleSync();
+        // Tab should
         CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_TAB);
         mInstrumentation.waitForIdleSync();
         assertFalse(mTextView.isFocused());
diff --git a/tests/tests/wifi/Android.bp b/tests/tests/wifi/Android.bp
index 22db9ad..d3ac794 100644
--- a/tests/tests/wifi/Android.bp
+++ b/tests/tests/wifi/Android.bp
@@ -26,6 +26,7 @@
     srcs: [ "src/**/*.java" ],
 
     static_libs: [
+        "androidx.test.rules",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "junit",
@@ -40,5 +41,10 @@
         "mts",
     ],
 
+
+    data: [
+        ":CtsWifiLocationTestApp",
+    ],
+
     platform_apis: true,
 }
diff --git a/tests/tests/wifi/AndroidManifest.xml b/tests/tests/wifi/AndroidManifest.xml
index 4ab0e09..0e40a37 100644
--- a/tests/tests/wifi/AndroidManifest.xml
+++ b/tests/tests/wifi/AndroidManifest.xml
@@ -29,6 +29,7 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -39,6 +40,7 @@
          (as opposed to HTTPS). -->
     <application android:usesCleartextTraffic="true">
         <uses-library android:name="android.test.runner" />
+        <activity android:name=".WaitForResultActivity" />
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/wifi/AndroidTest.xml b/tests/tests/wifi/AndroidTest.xml
index a258805..dd5246c 100644
--- a/tests/tests/wifi/AndroidTest.xml
+++ b/tests/tests/wifi/AndroidTest.xml
@@ -32,9 +32,22 @@
         <option name="run-command" value="settings put secure location_mode 3" />
         <option name="teardown-command" value="settings put secure location_mode 0" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="mkdir -p /data/local/tmp/cts/wifi" />
+        <option name="teardown-command" value="rm -rf /data/local/tmp/cts/wifi"/>
+    </target_preparer>
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+        <option name="cleanup" value="true" />
+        <option name="push" value="CtsWifiLocationTestApp.apk->/data/local/tmp/cts/wifi/CtsWifiLocationTestApp.apk" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.wifi.cts" />
         <option name="hidden-api-checks" value="false" />
         <option name="isolated-storage" value="false" />
     </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.wifi" />
+        <option name="mainline-module-package-name" value="com.google.android.tethering" />
+    </object>
 </configuration>
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp b/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp
new file mode 100644
index 0000000..bc239fa
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp
@@ -0,0 +1,26 @@
+// 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.
+
+android_test {
+    name: "CtsWifiLocationTestApp",
+
+    // Include both the 32 and 64 bit versions
+    compile_multilib: "both",
+
+    sdk_version: "test_current",
+
+    srcs: [
+        "src/**/*.java"
+    ],
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml b/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..96fb0a6
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ 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.
+  -->
+
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.net.wifi.cts.app">
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+
+    <application android:label="CtsWifiLocationTestApp">
+        <activity
+            android:name=".ScheduleJobActivity"
+            android:exported="true" />
+        <activity
+            android:name=".TriggerScanAndReturnStatusActivity"
+            android:exported="true" />
+        <service
+            android:name=".TriggerScanAndReturnStatusService"
+            android:permission="android.permission.BIND_JOB_SERVICE"
+            android:exported="true" />
+        <activity
+            android:name=".RetrieveScanResultsAndReturnStatusActivity"
+            android:exported="true" />
+        <service
+            android:name=".RetrieveScanResultsAndReturnStatusService"
+            android:permission="android.permission.BIND_JOB_SERVICE"
+            android:exported="true" />
+        <activity
+            android:name=".RetrieveConnectionInfoAndReturnStatusActivity"
+            android:exported="true" />
+        <service
+            android:name=".RetrieveConnectionInfoAndReturnStatusService"
+            android:permission="android.permission.BIND_JOB_SERVICE"
+            android:exported="true" />
+    </application>
+</manifest>
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveConnectionInfoAndReturnStatusActivity.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveConnectionInfoAndReturnStatusActivity.java
new file mode 100644
index 0000000..48505ca
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveConnectionInfoAndReturnStatusActivity.java
@@ -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.
+ */
+
+package android.net.wifi.cts.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * An activity that retrieves connection info and returns status.
+ */
+public class RetrieveConnectionInfoAndReturnStatusActivity extends Activity {
+    private static final String TAG = "RetrieveConnectionInfoAndReturnStatusActivity";
+    private static final String SCAN_STATUS_EXTRA = "android.net.wifi.cts.app.extra.STATUS";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        boolean succeeded;
+        try {
+            succeeded = !wifiManager.getConnectionInfo().getSSID().equals(WifiManager.UNKNOWN_SSID);
+        } catch (SecurityException e) {
+            succeeded = false;
+        }
+        if (succeeded) {
+            Log.v(TAG, "SSID from connection info retrieval succeeded");
+        } else {
+            Log.v(TAG, "Failed to retrieve SSID from connection info");
+        }
+        setResult(RESULT_OK, new Intent().putExtra(SCAN_STATUS_EXTRA, succeeded));
+        finish();
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveConnectionInfoAndReturnStatusService.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveConnectionInfoAndReturnStatusService.java
new file mode 100644
index 0000000..2308054
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveConnectionInfoAndReturnStatusService.java
@@ -0,0 +1,57 @@
+/*
+ * 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.net.wifi.cts.app;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.net.wifi.WifiManager;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+/**
+ * A service that retrieves scan results and returns status.
+ */
+public class RetrieveConnectionInfoAndReturnStatusService extends JobService {
+    private static final String TAG = "RetrieveConnectionInfoAndReturnStatusService";
+    private static final String RESULT_RECEIVER_EXTRA =
+            "android.net.wifi.cts.app.extra.RESULT_RECEIVER";
+
+    @Override
+    public boolean onStartJob(JobParameters jobParameters) {
+        ResultReceiver resultReceiver =
+                jobParameters.getTransientExtras().getParcelable(RESULT_RECEIVER_EXTRA);
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        boolean succeeded;
+        try {
+            succeeded = !wifiManager.getConnectionInfo().getSSID().equals(WifiManager.UNKNOWN_SSID);
+        } catch (SecurityException e) {
+            succeeded = false;
+        }
+        if (succeeded) {
+            Log.v(TAG, "SSID from connection info retrieval succeeded");
+        } else {
+            Log.v(TAG, "Failed to retrieve SSID from connection info");
+        }
+        resultReceiver.send(succeeded ? 1 : 0, null);
+        return false;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters jobParameters) {
+        return false;
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveScanResultsAndReturnStatusActivity.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveScanResultsAndReturnStatusActivity.java
new file mode 100644
index 0000000..2dd3810
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveScanResultsAndReturnStatusActivity.java
@@ -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.
+ */
+
+package android.net.wifi.cts.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * An activity that retrieves scan results and returns status.
+ */
+public class RetrieveScanResultsAndReturnStatusActivity extends Activity {
+    private static final String TAG = "RetrieveScanResultsAndReturnStatusActivity";
+    private static final String SCAN_STATUS_EXTRA = "android.net.wifi.cts.app.extra.STATUS";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        boolean succeeded;
+        try {
+            succeeded = !wifiManager.getScanResults().isEmpty();
+        } catch (SecurityException e) {
+            succeeded = false;
+        }
+        if (succeeded) {
+            Log.v(TAG, "Scan results retrieval succeeded");
+        } else {
+            Log.v(TAG, "Failed to retrieve scan results");
+        }
+        setResult(RESULT_OK, new Intent().putExtra(SCAN_STATUS_EXTRA, succeeded));
+        finish();
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveScanResultsAndReturnStatusService.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveScanResultsAndReturnStatusService.java
new file mode 100644
index 0000000..4918e39
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveScanResultsAndReturnStatusService.java
@@ -0,0 +1,57 @@
+/*
+ * 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.net.wifi.cts.app;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.net.wifi.WifiManager;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+/**
+ * A service that triggers a wifi scan and returns status.
+ */
+public class RetrieveScanResultsAndReturnStatusService extends JobService {
+    private static final String TAG = "RetrieveScanResultsAndReturnStatusService";
+    private static final String RESULT_RECEIVER_EXTRA =
+            "android.net.wifi.cts.app.extra.RESULT_RECEIVER";
+
+    @Override
+    public boolean onStartJob(JobParameters jobParameters) {
+        ResultReceiver resultReceiver =
+                jobParameters.getTransientExtras().getParcelable(RESULT_RECEIVER_EXTRA);
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        boolean succeeded;
+        try {
+            succeeded = !wifiManager.getScanResults().isEmpty();
+        } catch (SecurityException e) {
+            succeeded = false;
+        }
+        if (succeeded) {
+            Log.v(TAG, "Scan results retrieval succeeded");
+        } else {
+            Log.v(TAG, "Failed to retrieve scan results");
+        }
+        resultReceiver.send(succeeded ? 1 : 0, null);
+        return false;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters jobParameters) {
+        return false;
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.java
new file mode 100644
index 0000000..b447878
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/ScheduleJobActivity.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.net.wifi.cts.app;
+
+import android.app.Activity;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+/**
+ * An activity that can be used to schedule a job inside the app.
+ *
+ * Note: This trampoline is needed since we cannot schedule a job to an app from outside the app.
+ */
+public class ScheduleJobActivity extends Activity {
+    private static final String TAG = "ScheduleJobActivity";
+    public static final int JOB_ID = 1;
+    private static final String RESULT_RECEIVER_EXTRA =
+            "android.net.wifi.cts.app.extra.RESULT_RECEIVER";
+    private static final String SERVICE_COMPONENT_EXTRA =
+            "android.net.wifi.cts.app.extra.SERVICE_COMPONENT";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ComponentName serviceComponentName =
+                getIntent().getParcelableExtra(SERVICE_COMPONENT_EXTRA);
+        ResultReceiver resultReceiver = getIntent().getParcelableExtra(RESULT_RECEIVER_EXTRA);
+
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(RESULT_RECEIVER_EXTRA, resultReceiver);
+        JobInfo jobInfo = new JobInfo.Builder(JOB_ID, serviceComponentName)
+                .setTransientExtras(bundle)
+                .setMinimumLatency(1)
+                .setOverrideDeadline(1)
+                .build();
+        JobScheduler jobScheduler = getSystemService(JobScheduler.class);
+        jobScheduler.schedule(jobInfo);
+
+        Log.v(TAG,"Job scheduled: " + jobInfo);
+
+        finish();
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/TriggerScanAndReturnStatusActivity.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/TriggerScanAndReturnStatusActivity.java
new file mode 100644
index 0000000..a6fbdfa
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/TriggerScanAndReturnStatusActivity.java
@@ -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.
+ */
+
+package android.net.wifi.cts.app;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * An activity that triggers a wifi scan and returns status.
+ */
+public class TriggerScanAndReturnStatusActivity extends Activity {
+    private static final String TAG = "TriggerScanAndReturnStatusActivity";
+    private static final String SCAN_STATUS_EXTRA = "android.net.wifi.cts.app.extra.STATUS";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        boolean succeeded;
+        try {
+            succeeded = wifiManager.startScan();
+        } catch (SecurityException e) {
+            succeeded = false;
+        }
+        if (succeeded) {
+            Log.v(TAG, "Scan trigger succeeded");
+        } else {
+            Log.v(TAG, "Failed to trigger scan");
+        }
+        setResult(RESULT_OK, new Intent().putExtra(SCAN_STATUS_EXTRA, succeeded));
+        finish();
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/TriggerScanAndReturnStatusService.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/TriggerScanAndReturnStatusService.java
new file mode 100644
index 0000000..2f6a2ed
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/TriggerScanAndReturnStatusService.java
@@ -0,0 +1,57 @@
+/*
+ * 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.net.wifi.cts.app;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.net.wifi.WifiManager;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+/**
+ * A service that triggers a wifi scan and returns status.
+ */
+public class TriggerScanAndReturnStatusService extends JobService {
+    private static final String TAG = "TriggerScanAndReturnStatusService";
+    private static final String RESULT_RECEIVER_EXTRA =
+            "android.net.wifi.cts.app.extra.RESULT_RECEIVER";
+
+    @Override
+    public boolean onStartJob(JobParameters jobParameters) {
+        ResultReceiver resultReceiver =
+                jobParameters.getTransientExtras().getParcelable(RESULT_RECEIVER_EXTRA);
+        WifiManager wifiManager = getSystemService(WifiManager.class);
+        boolean succeeded;
+        try {
+            succeeded = wifiManager.startScan();
+        } catch (SecurityException e) {
+            succeeded = false;
+        }
+        if (succeeded) {
+            Log.v(TAG, "Scan trigger succeeded");
+        } else {
+            Log.v(TAG, "Failed to trigger scan");
+        }
+        resultReceiver.send(succeeded ? 1 : 0, null);
+        return false;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters jobParameters) {
+        return false;
+    }
+}
diff --git a/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java b/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java
index a476658..8df75b1 100644
--- a/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/aware/cts/SingleDeviceTest.java
@@ -69,7 +69,8 @@
     private static final String TAG = "WifiAwareCtsTests";
 
     // wait for Wi-Fi Aware state changes & network requests callbacks
-    static private final int WAIT_FOR_AWARE_CHANGE_SECS = 15; // 15 seconds
+    private static final int WAIT_FOR_AWARE_CHANGE_SECS = 15; // 15 seconds
+    private static final int INTERVAL_BETWEEN_TESTS_SECS = 3; // 3 seconds
     private static final int MIN_DISTANCE_MM = 1 * 1000;
     private static final int MAX_DISTANCE_MM = 3 * 1000;
     private static final byte[] PMK_VALID = "01234567890123456789012345678901".getBytes();
@@ -412,6 +413,7 @@
         }
 
         super.tearDown();
+        Thread.sleep(INTERVAL_BETWEEN_TESTS_SECS * 1000);
     }
 
     /**
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java b/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java
index 1977378..d7e4a23 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/ScanResultTest.java
@@ -299,9 +299,10 @@
             return;
         }
 
-        // This test case should run while connected to Wifi
         final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
         assertThat(wifiInfo).isNotNull();
+        assertWithMessage("Wifi should be connected!")
+                .that(wifiInfo.getBSSID()).isNotNull();
 
         ScanResult currentNetwork = null;
         for (int i = 0; i < SCAN_FIND_BSSID_MAX_RETRY_COUNT; i++) {
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WaitForResultActivity.java b/tests/tests/wifi/src/android/net/wifi/cts/WaitForResultActivity.java
new file mode 100644
index 0000000..f4f746c
--- /dev/null
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WaitForResultActivity.java
@@ -0,0 +1,132 @@
+/*
+ * 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.net.wifi.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Activity;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ResultReceiver;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An Activity that can start another Activity and wait for its result.
+ */
+public class WaitForResultActivity extends Activity {
+    private final Object mStatusLock = new Object();
+    private CountDownLatch mLatch;
+    private boolean mStatus = false;
+
+    private static final int REQUEST_CODE_WAIT_FOR_RESULT = 1;
+    private static final String WIFI_LOCATION_TEST_APP_LOCATION_STATUS_EXTRA =
+            "android.net.wifi.cts.app.extra.STATUS";
+
+    public void startActivityToWaitForResult(@NonNull ComponentName componentName) {
+        mLatch = new CountDownLatch(1);
+        synchronized (mStatusLock) {
+            mStatus = false;
+        }
+        Intent intent = new Intent()
+                .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
+                .setComponent(componentName);
+        startActivityForResult(intent, REQUEST_CODE_WAIT_FOR_RESULT);
+    }
+
+    @NonNull
+    public boolean waitForActivityResult(long timeoutMillis)
+            throws InterruptedException {
+        assertThat(mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS)).isTrue();
+        synchronized (mStatusLock) {
+            return mStatus;
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        if (requestCode == REQUEST_CODE_WAIT_FOR_RESULT) {
+            assertThat(resultCode).isEqualTo(RESULT_OK);
+            assertThat(data.hasExtra(WIFI_LOCATION_TEST_APP_LOCATION_STATUS_EXTRA)).isTrue();
+            synchronized (mStatusLock) {
+                mStatus = data.getBooleanExtra(
+                        WIFI_LOCATION_TEST_APP_LOCATION_STATUS_EXTRA, false);
+            }
+            mLatch.countDown();
+        } else {
+            super.onActivityResult(requestCode, resultCode, data);
+        }
+    }
+
+    private static final String WIFI_LOCATION_TEST_APP_PACKAGE_NAME =
+            "android.net.wifi.cts.app";
+    private static final String WIFI_LOCATION_TEST_APP_SCHEDULE_JOB_ACTIVITY =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".ScheduleJobActivity";
+    private static final String RESULT_RECEIVER_EXTRA =
+            "android.net.wifi.cts.app.extra.RESULT_RECEIVER";
+    private static final String SERVICE_COMPONENT_EXTRA =
+            "android.net.wifi.cts.app.extra.SERVICE_COMPONENT";
+
+    private static ResultReceiver convertToGeneric(ResultReceiver receiver) {
+        Parcel parcel = Parcel.obtain();
+        receiver.writeToParcel(parcel,0);
+        parcel.setDataPosition(0);
+        ResultReceiver receiverGeneric = ResultReceiver.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+        return receiverGeneric;
+    }
+
+    public void startServiceToWaitForResult(@NonNull ComponentName serviceComponent) {
+        mLatch = new CountDownLatch(1);
+        synchronized (mStatusLock) {
+            mStatus = false;
+        }
+        ResultReceiver resultReceiver = new ResultReceiver(null) {
+            @Override
+            public void onReceiveResult(int resultCode, Bundle data) {
+                synchronized (mStatusLock) {
+                    mStatus = resultCode == 1;
+                }
+                mLatch.countDown();
+            }
+        };
+        Intent intent = new Intent()
+                .setComponent(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                        WIFI_LOCATION_TEST_APP_SCHEDULE_JOB_ACTIVITY))
+                .putExtra(RESULT_RECEIVER_EXTRA, convertToGeneric(resultReceiver))
+                .putExtra(SERVICE_COMPONENT_EXTRA, serviceComponent);
+        startActivity(intent);
+    }
+
+    @NonNull
+    public boolean waitForServiceResult(long timeoutMillis)
+            throws InterruptedException {
+        assertThat(mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS)).isTrue();
+        synchronized (mStatusLock) {
+            return mStatus;
+        }
+    }
+
+}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java
new file mode 100644
index 0000000..0ca73fc
--- /dev/null
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java
@@ -0,0 +1,315 @@
+/*
+ * 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.net.wifi.cts;
+
+import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+/**
+ * Tests location sensitive APIs exposed by Wi-Fi.
+ * Ensures that permissions on these APIs are properly enforced.
+ */
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WifiLocationInfoTest {
+    private static final String TAG = "WifiLocationInfoTest";
+
+    private static final String WIFI_LOCATION_TEST_APP_APK_PATH =
+            "/data/local/tmp/cts/wifi/CtsWifiLocationTestApp.apk";
+    private static final String WIFI_LOCATION_TEST_APP_PACKAGE_NAME =
+            "android.net.wifi.cts.app";
+    private static final String WIFI_LOCATION_TEST_APP_TRIGGER_SCAN_ACTIVITY =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".TriggerScanAndReturnStatusActivity";
+    private static final String WIFI_LOCATION_TEST_APP_TRIGGER_SCAN_SERVICE =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".TriggerScanAndReturnStatusService";
+    private static final String WIFI_LOCATION_TEST_APP_RETRIEVE_SCAN_RESULTS_ACTIVITY =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".RetrieveScanResultsAndReturnStatusActivity";
+    private static final String WIFI_LOCATION_TEST_APP_RETRIEVE_SCAN_RESULTS_SERVICE =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".RetrieveScanResultsAndReturnStatusService";
+    private static final String WIFI_LOCATION_TEST_APP_RETRIEVE_CONNECTION_INFO_ACTIVITY =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".RetrieveConnectionInfoAndReturnStatusActivity";
+    private static final String WIFI_LOCATION_TEST_APP_RETRIEVE_CONNECTION_INFO_SERVICE =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".RetrieveConnectionInfoAndReturnStatusService";
+
+    private static final int DURATION_MS = 10_000;
+
+    @Rule
+    public final ActivityTestRule<WaitForResultActivity> mActivityRule =
+            new ActivityTestRule<>(WaitForResultActivity.class);
+
+    private Context mContext;
+    private WifiManager mWifiManager;
+    private boolean mWasVerboseLoggingEnabled;
+    private boolean mWasScanThrottleEnabled;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip the test if WiFi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(mContext));
+
+        mWifiManager = mContext.getSystemService(WifiManager.class);
+        assertThat(mWifiManager).isNotNull();
+
+        installApp(WIFI_LOCATION_TEST_APP_APK_PATH);
+
+        // turn on verbose logging for tests
+        mWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.isVerboseLoggingEnabled());
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.setVerboseLoggingEnabled(true));
+        // Disable scan throttling for tests.
+        mWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.isScanThrottleEnabled());
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.setScanThrottleEnabled(false));
+
+        if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true);
+        PollingCheck.check("Wifi not enabled", DURATION_MS, () -> mWifiManager.isWifiEnabled());
+        List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.getConfiguredNetworks());
+        assertWithMessage("Need at least one saved network").that(savedNetworks).isNotEmpty();
+        // Wait for wifi is to be connected
+        PollingCheck.check(
+                "Wifi not connected",
+                DURATION_MS,
+                () -> mWifiManager.getConnectionInfo().getNetworkId() != -1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (!WifiFeature.isWifiSupported(mContext)) return;
+
+        uninstallApp(WIFI_LOCATION_TEST_APP_PACKAGE_NAME);
+
+        if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true);
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.setScanThrottleEnabled(mWasScanThrottleEnabled));
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.setVerboseLoggingEnabled(mWasVerboseLoggingEnabled));
+    }
+
+    private void setWifiEnabled(boolean enable) throws Exception {
+        // now trigger the change using shell commands.
+        SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable"));
+    }
+
+    private void turnScreenOn() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "input keyevent KEYCODE_WAKEUP");
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(""
+                + "wm dismiss-keyguard");
+        // Since the screen on/off intent is ordered, they will not be sent right now.
+        Thread.sleep(2_000);
+    }
+
+    private void turnScreenOff() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "input keyevent KEYCODE_SLEEP");
+        // Since the screen on/off intent is ordered, they will not be sent right now.
+        Thread.sleep(2_000);
+    }
+
+    private void installApp(String apk) throws InterruptedException {
+        String installResult = SystemUtil.runShellCommand("pm install -r -d " + apk);
+        Thread.sleep(10_000);
+        assertThat(installResult.trim()).isEqualTo("Success");
+    }
+
+    private void uninstallApp(String pkg) throws InterruptedException {
+        String uninstallResult = SystemUtil.runShellCommand(
+                "pm uninstall " + pkg);
+        Thread.sleep(10_000);
+        assertThat(uninstallResult.trim()).isEqualTo("Success");
+    }
+
+    private void startFgActivityAndAssertStatusIs(
+            ComponentName componentName, boolean status) throws Exception {
+        turnScreenOn();
+
+        WaitForResultActivity activity = mActivityRule.getActivity();
+        activity.startActivityToWaitForResult(componentName);
+        assertThat(activity.waitForActivityResult(DURATION_MS)).isEqualTo(status);
+    }
+
+    private void startBgServiceAndAssertStatusIs(
+            ComponentName componentName, boolean status) throws Exception {
+        turnScreenOff();
+
+        WaitForResultActivity activity = mActivityRule.getActivity();
+        activity.startServiceToWaitForResult(componentName);
+        assertThat(activity.waitForServiceResult(DURATION_MS)).isEqualTo(status);
+    }
+
+    private void triggerScanFgActivityAndAssertStatusIs(boolean status) throws Exception {
+        startFgActivityAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_TRIGGER_SCAN_ACTIVITY), status);
+    }
+
+    private void triggerScanBgServiceAndAssertStatusIs(boolean status) throws Exception {
+        startBgServiceAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_TRIGGER_SCAN_SERVICE), status);
+    }
+
+    private void retrieveScanResultsFgActivityAndAssertStatusIs(boolean status) throws Exception {
+        startFgActivityAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_RETRIEVE_SCAN_RESULTS_ACTIVITY), status);
+    }
+
+    private void retrieveScanResultsBgServiceAndAssertStatusIs(boolean status) throws Exception {
+        startBgServiceAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_RETRIEVE_SCAN_RESULTS_SERVICE), status);
+    }
+
+    private void retrieveConnectionInfoFgActivityAndAssertStatusIs(boolean status)
+            throws Exception {
+        startFgActivityAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_RETRIEVE_CONNECTION_INFO_ACTIVITY), status);
+    }
+
+    private void retrieveConnectionInfoBgServiceAndAssertStatusIs(boolean status) throws Exception {
+        startBgServiceAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_RETRIEVE_CONNECTION_INFO_SERVICE), status);
+    }
+
+    @Test
+    public void testScanTriggerNotAllowedForForegroundActivityWithNoLocationPermission()
+            throws Exception {
+        triggerScanFgActivityAndAssertStatusIs(false);
+    }
+
+    @Test
+    public void testScanTriggerAllowedForForegroundActivityWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        triggerScanFgActivityAndAssertStatusIs(true);
+    }
+
+    @Test
+    public void testScanTriggerAllowedForBackgroundServiceWithBackgroundLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_BACKGROUND_LOCATION);
+        triggerScanBgServiceAndAssertStatusIs(true);
+    }
+
+    @Test
+    public void testScanTriggerNotAllowedForBackgroundServiceWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        triggerScanBgServiceAndAssertStatusIs(false);
+    }
+
+    @Test
+    public void testScanResultsRetrievalNotAllowedForForegroundActivityWithNoLocationPermission()
+            throws Exception {
+        retrieveScanResultsFgActivityAndAssertStatusIs(false);
+    }
+
+    @Test
+    public void testScanResultsRetrievalAllowedForForegroundActivityWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        retrieveScanResultsFgActivityAndAssertStatusIs(true);
+    }
+
+    @Test
+    public void testScanResultsRetrievalAllowedForBackgroundServiceWithBackgroundLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_BACKGROUND_LOCATION);
+        retrieveScanResultsBgServiceAndAssertStatusIs(true);
+    }
+
+    @Test
+    public void testScanResultsRetrievalNotAllowedForBackgroundServiceWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        retrieveScanResultsBgServiceAndAssertStatusIs(false);
+    }
+
+    @Test
+    public void testConnectionInfoRetrievalNotAllowedForForegroundActivityWithNoLocationPermission()
+            throws Exception {
+        retrieveConnectionInfoFgActivityAndAssertStatusIs(false);
+    }
+
+    @Test
+    public void testConnectionInfoRetrievalAllowedForForegroundActivityWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        retrieveConnectionInfoFgActivityAndAssertStatusIs(true);
+    }
+
+    @Test
+    public void
+        testConnectionInfoRetrievalAllowedForBackgroundServiceWithBackgroundLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_BACKGROUND_LOCATION);
+        retrieveConnectionInfoBgServiceAndAssertStatusIs(true);
+    }
+
+    @Test
+    public void
+        testConnectionInfoRetrievalNotAllowedForBackgroundServiceWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        retrieveConnectionInfoBgServiceAndAssertStatusIs(false);
+    }
+}
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
index 71831de..58be4d8 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -140,10 +140,9 @@
     // A full single scan duration is about 6-7 seconds if country code is set
     // to US. If country code is set to world mode (00), we would expect a scan
     // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here.
-    private static final int SCAN_TIMEOUT_MSEC = 9000;
-    private static final int TIMEOUT_MSEC = 6000;
-    private static final int WAIT_MSEC = 60;
+    private static final int SCAN_TEST_WAIT_DURATION_MS = 9000;
     private static final int TEST_WAIT_DURATION_MS = 10_000;
+    private static final int WAIT_MSEC = 60;
     private static final int DURATION_SCREEN_TOGGLE = 2000;
     private static final int DURATION_SETTINGS_TOGGLE = 1_000;
     private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000;
@@ -351,7 +350,7 @@
 
     private void waitForExpectedWifiState(boolean enabled) throws InterruptedException {
         synchronized (mMySync) {
-            long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+            long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS;
             int expected = (enabled ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED);
             while (System.currentTimeMillis() < timeout
                     && mMySync.expectedState != expected) {
@@ -377,7 +376,7 @@
             mMySync.expectedState = STATE_SCANNING;
             mScanResults = null;
             assertTrue(mWifiManager.startScan());
-            long timeout = System.currentTimeMillis() + SCAN_TIMEOUT_MSEC;
+            long timeout = System.currentTimeMillis() + SCAN_TEST_WAIT_DURATION_MS;
             while (System.currentTimeMillis() < timeout && mMySync.expectedState == STATE_SCANNING)
                 mMySync.wait(WAIT_MSEC);
         }
@@ -386,7 +385,7 @@
     private void waitForNetworkInfoState(NetworkInfo.State state) throws Exception {
         synchronized (mMySync) {
             if (mNetworkInfo.getState() == state) return;
-            long timeout = System.currentTimeMillis() + TIMEOUT_MSEC;
+            long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS;
             while (System.currentTimeMillis() < timeout
                     && mNetworkInfo.getState() != state)
                 mMySync.wait(WAIT_MSEC);
@@ -404,7 +403,7 @@
 
     private void ensureNotNetworkInfoState(NetworkInfo.State state) throws Exception {
         synchronized (mMySync) {
-            long timeout = System.currentTimeMillis() + TIMEOUT_MSEC + WAIT_MSEC;
+            long timeout = System.currentTimeMillis() + TEST_WAIT_DURATION_MS + WAIT_MSEC;
             while (System.currentTimeMillis() < timeout) {
                 assertNotEquals(mNetworkInfo.getState(), state);
                 mMySync.wait(WAIT_MSEC);
@@ -2077,8 +2076,8 @@
                 URL url = new URL("http://www.google.com/");
                 connection = (HttpURLConnection) url.openConnection();
                 connection.setInstanceFollowRedirects(false);
-                connection.setConnectTimeout(TIMEOUT_MSEC);
-                connection.setReadTimeout(TIMEOUT_MSEC);
+                connection.setConnectTimeout(TEST_WAIT_DURATION_MS);
+                connection.setReadTimeout(TEST_WAIT_DURATION_MS);
                 connection.setUseCaches(false);
                 InputStream stream = connection.getInputStream();
                 byte[] bytes = new byte[100];
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
index a7c4cc7..e17d022 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
@@ -70,13 +70,15 @@
     private final Object mLock = new Object();
     private final Object mUiLock = new Object();
     private WifiConfiguration mTestNetwork;
+    private TestNetworkCallback mNetworkCallback;
     private boolean mWasVerboseLoggingEnabled;
     private boolean mWasScanThrottleEnabled;
 
     private static final int DURATION = 10_000;
-    private static final int DURATION_UI_INTERACTION = 15_000;
-    private static final int DURATION_NETWORK_CONNECTION = 30_000;
+    private static final int DURATION_UI_INTERACTION = 25_000;
+    private static final int DURATION_NETWORK_CONNECTION = 60_000;
     private static final int DURATION_SCREEN_TOGGLE = 2000;
+    private static final int SCAN_RETRY_CNT_TO_FIND_MATCHING_BSSID = 3;
 
     @Override
     protected void setUp() throws Exception {
@@ -130,6 +132,10 @@
         }
         if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true);
         turnScreenOff();
+        // If there is failure, ensure we unregister the previous request.
+        if (mNetworkCallback != null) {
+            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+        }
         ShellIdentityUtils.invokeWithShellPermissions(
                 () -> mWifiManager.enableNetwork(mTestNetwork.networkId, false));
         ShellIdentityUtils.invokeWithShellPermissions(
@@ -260,7 +266,6 @@
                 try {
                     mWifiManager.registerNetworkRequestMatchCallback(
                             Executors.newSingleThreadExecutor(), networkRequestMatchCallback);
-                    // now wait for the registration callback first.
                     mUiLock.wait(DURATION_UI_INTERACTION);
                 } catch (InterruptedException e) {
                 }
@@ -271,7 +276,6 @@
             // 2. Wait for matching scan results
             synchronized (mUiLock) {
                 try {
-                    // now wait for the registration callback first.
                     mUiLock.wait(DURATION_UI_INTERACTION);
                 } catch (InterruptedException e) {
                 }
@@ -290,7 +294,6 @@
             // 4. Wait for connection success or abort.
             synchronized (mUiLock) {
                 try {
-                    // now wait for the registration callback first.
                     mUiLock.wait(DURATION_UI_INTERACTION);
                 } catch (InterruptedException e) {
                 }
@@ -318,7 +321,7 @@
         Thread uiThread = new Thread(() -> handleUiInteractions(shouldUserReject));
 
         // File the network request & wait for the callback.
-        TestNetworkCallback networkCallbackListener = new TestNetworkCallback(mLock);
+        mNetworkCallback = new TestNetworkCallback(mLock);
         synchronized (mLock) {
             try {
                 // File a request for wifi network.
@@ -327,7 +330,7 @@
                                 .addTransportType(TRANSPORT_WIFI)
                                 .setNetworkSpecifier(specifier)
                                 .build(),
-                        networkCallbackListener);
+                        mNetworkCallback);
                 // Wait for the request to reach the wifi stack before kick-starting the UI
                 // interactions.
                 Thread.sleep(100);
@@ -339,9 +342,9 @@
             }
         }
         if (shouldUserReject) {
-            assertTrue(networkCallbackListener.onUnavailableCalled);
+            assertTrue(mNetworkCallback.onUnavailableCalled);
         } else {
-            assertTrue(networkCallbackListener.onAvailableCalled);
+            assertTrue(mNetworkCallback.onAvailableCalled);
         }
 
         try {
@@ -352,7 +355,8 @@
         }
 
         // Release the request after the test.
-        mConnectivityManager.unregisterNetworkCallback(networkCallbackListener);
+        mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+        mNetworkCallback = null;
     }
 
     private void testSuccessfulConnectionWithSpecifier(WifiNetworkSpecifier specifier) {
@@ -447,25 +451,27 @@
      * this matching may pick the wrong one.
      */
     private ScanResult findScanResultMatchingSavedNetwork() {
-        // Trigger a scan to get fresh scan results.
-        TestScanResultsCallback scanResultsCallback = new TestScanResultsCallback(mLock);
-        synchronized (mLock) {
-            try {
-                mWifiManager.registerScanResultsCallback(
-                        Executors.newSingleThreadExecutor(), scanResultsCallback);
-                mWifiManager.startScan(new WorkSource(myUid()));
-                // now wait for callback
-                mLock.wait(DURATION_NETWORK_CONNECTION);
-            } catch (InterruptedException e) {
-            } finally {
-                mWifiManager.unregisterScanResultsCallback(scanResultsCallback);
+        for (int i = 0; i < SCAN_RETRY_CNT_TO_FIND_MATCHING_BSSID; i++) {
+            // Trigger a scan to get fresh scan results.
+            TestScanResultsCallback scanResultsCallback = new TestScanResultsCallback(mLock);
+            synchronized (mLock) {
+                try {
+                    mWifiManager.registerScanResultsCallback(
+                            Executors.newSingleThreadExecutor(), scanResultsCallback);
+                    mWifiManager.startScan(new WorkSource(myUid()));
+                    // now wait for callback
+                    mLock.wait(DURATION_NETWORK_CONNECTION);
+                } catch (InterruptedException e) {
+                } finally {
+                    mWifiManager.unregisterScanResultsCallback(scanResultsCallback);
+                }
             }
-        }
-        List<ScanResult> scanResults = mWifiManager.getScanResults();
-        if (scanResults == null || scanResults.isEmpty()) fail("No scan results available");
-        for (ScanResult scanResult : scanResults) {
-            if (TextUtils.equals(scanResult.SSID, removeDoubleQuotes(mTestNetwork.SSID))) {
-                return scanResult;
+            List<ScanResult> scanResults = mWifiManager.getScanResults();
+            if (scanResults == null || scanResults.isEmpty()) fail("No scan results available");
+            for (ScanResult scanResult : scanResults) {
+                if (TextUtils.equals(scanResult.SSID, removeDoubleQuotes(mTestNetwork.SSID))) {
+                    return scanResult;
+                }
             }
         }
         fail("No matching scan results found");
diff --git a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
index 554512c..4264d3f 100644
--- a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
+++ b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
@@ -145,9 +145,9 @@
 
     // Performance numbers only make sense on real devices, so skip on non-real devices
     public static boolean frankenDevice() throws IOException {
-        String systemBrand = getProperty("ro.product.system.brand");
-        String systemModel = getProperty("ro.product.system.model");
-        String systemProduct = getProperty("ro.product.system.name");
+        String systemBrand = getProperty("ro.product.system_ext.brand");
+        String systemModel = getProperty("ro.product.system_ext.model");
+        String systemProduct = getProperty("ro.product.system_ext.name");
         if (("Android".equals(systemBrand) || "generic".equals(systemBrand)) &&
             (systemModel.startsWith("AOSP on ") || systemProduct.startsWith("aosp_"))) {
             return true;