Merge "[ID] Replace "forensic" with "intrusion detection"" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 5a7f2bd..76f3e5a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3830,7 +3830,7 @@
     method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean notifyAccountAuthenticated(android.accounts.Account);
     method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public String peekAuthToken(android.accounts.Account, String);
     method @Deprecated @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
-    method @RequiresPermission(value="android.permission.MANAGE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
+    method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @RequiresPermission(value="android.permission.REMOVE_ACCOUNTS", conditional=true) public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public boolean removeAccountExplicitly(android.accounts.Account);
     method public void removeOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener);
     method @RequiresPermission(value="android.permission.AUTHENTICATE_ACCOUNTS", apis="..22") public android.accounts.AccountManagerFuture<android.accounts.Account> renameAccount(android.accounts.Account, @Size(min=1) String, android.accounts.AccountManagerCallback<android.accounts.Account>, android.os.Handler);
@@ -13809,7 +13809,7 @@
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING, android.Manifest.permission.RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
     field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
-    field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
+    field @FlaggedApi("android.permission.flags.replace_body_sensor_permission_enabled") @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS, android.health.connect.HealthPermissions.READ_HEART_RATE, android.health.connect.HealthPermissions.READ_SKIN_TEMPERATURE, android.health.connect.HealthPermissions.READ_OXYGEN_SATURATION}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
     field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff
     field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK = 2; // 0x2
@@ -21214,6 +21214,7 @@
     method public void setExtractView(android.view.View);
     method public void setExtractViewShown(boolean);
     method public void setInputView(android.view.View);
+    method @FlaggedApi("android.view.inputmethod.adaptive_handwriting_bounds") public final void setStylusHandwritingRegion(@NonNull android.graphics.Region);
     method public final void setStylusHandwritingSessionTimeout(@NonNull java.time.Duration);
     method public final boolean shouldOfferSwitchingToNextInputMethod();
     method public void showStatusIcon(@DrawableRes int);
@@ -41180,6 +41181,18 @@
     method @Deprecated public void onSendTextSms(@NonNull String, int, @NonNull String, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendTextSms(@NonNull String, int, @NonNull String, int, @NonNull android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 606; // 0x25e
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED = 610; // 0x262
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE = 603; // 0x25b
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 609; // 0x261
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN = 601; // 0x259
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 608; // 0x260
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR = 604; // 0x25c
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 611; // 0x263
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK = 607; // 0x25f
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_RETRY = 605; // 0x25d
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 602; // 0x25a
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED = 600; // 0x258
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
     field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
@@ -41187,7 +41200,38 @@
     field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 406; // 0x196
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_DATA_DISABLED = 410; // 0x19a
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_HTTP_FAILURE = 403; // 0x193
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 409; // 0x199
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INVALID_APN = 401; // 0x191
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 408; // 0x198
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_IO_ERROR = 404; // 0x194
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 411; // 0x19b
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK = 407; // 0x197
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_RETRY = 405; // 0x195
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 402; // 0x192
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_MMS_ERROR_UNSPECIFIED = 400; // 0x190
     field public static final int SEND_STATUS_OK = 0; // 0x0
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_CANCELLED = 215; // 0xd7
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ENCODING_ERROR = 212; // 0xd4
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE = 204; // 0xcc
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE = 200; // 0xc8
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED = 203; // 0xcb
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_NO_SERVICE = 202; // 0xca
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_NULL_PDU = 201; // 0xc9
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 206; // 0xce
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 205; // 0xcd
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_ARGUMENTS = 208; // 0xd0
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS = 213; // 0xd5
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_SMS_FORMAT = 210; // 0xd2
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_INVALID_STATE = 209; // 0xd1
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_NETWORK_ERROR = 211; // 0xd3
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_NETWORK_REJECT = 207; // 0xcf
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED = 214; // 0xd6
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED = 216; // 0xd8
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY = 217; // 0xd9
+    field @FlaggedApi("com.android.internal.telephony.flags.temporary_failures_in_carrier_messaging_service") public static final int SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED = 218; // 0xda
     field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
     field public static final String SERVICE_INTERFACE = "android.service.carrier.CarrierMessagingService";
   }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index f6f0ffb..c184ba5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -135,6 +135,7 @@
     field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
     field public static final String CONTROL_OEM_PAID_NETWORK_PREFERENCE = "android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE";
     field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN";
+    field @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") public static final String COPY_ACCOUNTS = "android.permission.COPY_ACCOUNTS";
     field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
     field public static final String CREATE_VIRTUAL_DEVICE = "android.permission.CREATE_VIRTUAL_DEVICE";
     field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
@@ -347,6 +348,7 @@
     field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
     field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
     field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
+    field @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") public static final String REMOVE_ACCOUNTS = "android.permission.REMOVE_ACCOUNTS";
     field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
@@ -572,6 +574,7 @@
 package android.accounts {
 
   public class AccountManager {
+    method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @NonNull @RequiresPermission(anyOf={android.Manifest.permission.COPY_ACCOUNTS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public android.accounts.AccountManagerFuture<java.lang.Boolean> copyAccountToUser(@NonNull android.accounts.Account, @NonNull android.os.UserHandle, @NonNull android.os.UserHandle, @Nullable android.accounts.AccountManagerCallback<java.lang.Boolean>, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.accounts.AccountManagerFuture<android.os.Bundle> finishSessionAsUser(android.os.Bundle, android.app.Activity, android.os.UserHandle, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
   }
 
@@ -9896,7 +9899,7 @@
     method public int getSignalStrength();
     method public int getSnr();
     method public int getSpectralInversion();
-    method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExt getStandardExt();
+    method @FlaggedApi("android.media.tv.flags.tuner_w_apis") @NonNull public android.media.tv.tuner.frontend.StandardExtension getStandardExtension();
     method @NonNull public int[] getStreamIds();
     method public int getSymbolRate();
     method @IntRange(from=0, to=65535) public int getSystemId();
@@ -9951,7 +9954,7 @@
     field public static final int FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH = 6; // 0x6
     field public static final int FRONTEND_STATUS_TYPE_SNR = 1; // 0x1
     field public static final int FRONTEND_STATUS_TYPE_SPECTRAL = 10; // 0xa
-    field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT = 47; // 0x2f
+    field @FlaggedApi("android.media.tv.flags.tuner_w_apis") public static final int FRONTEND_STATUS_TYPE_STANDARD_EXTENSION = 47; // 0x2f
     field public static final int FRONTEND_STATUS_TYPE_STREAM_IDS = 39; // 0x27
     field public static final int FRONTEND_STATUS_TYPE_SYMBOL_RATE = 7; // 0x7
     field public static final int FRONTEND_STATUS_TYPE_T2_SYSTEM_ID = 29; // 0x1d
@@ -10243,9 +10246,9 @@
     method public default void onUnlocked();
   }
 
-  @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExt {
-    method public int getDvbsStandardExt();
-    method public int getDvbtStandardExt();
+  @FlaggedApi("android.media.tv.flags.tuner_w_apis") public final class StandardExtension {
+    method public int getDvbsStandardExtension();
+    method public int getDvbtStandardExtension();
   }
 
 }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 87acbbf..72450999 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,9 +16,13 @@
 
 package android.accounts;
 
+import static android.Manifest.permission.COPY_ACCOUNTS;
+import static android.Manifest.permission.REMOVE_ACCOUNTS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED;
 
 import android.annotation.BroadcastBehavior;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -26,6 +30,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.Size;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.UserHandleAware;
@@ -1312,7 +1317,8 @@
      * {@link AccountManagerFuture} must not be used on the main thread.
      *
      * <p>This method requires the caller to have a signature match with the
-     * authenticator that manages the specified account.
+     * authenticator that manages the specified account, be a profile owner or have the
+     * {@link android.Manifest.permission#REMOVE_ACCOUNTS} permission.
      *
      * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
      * MANAGE_ACCOUNTS permission is needed for those platforms. See docs for
@@ -1344,6 +1350,8 @@
      * </ul>
      */
     @UserHandleAware
+    @RequiresPermission(value = REMOVE_ACCOUNTS, conditional = true)
+    @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
     public AccountManagerFuture<Bundle> removeAccount(final Account account,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
         return removeAccountAsUser(account, activity, callback, handler, mContext.getUser());
@@ -2019,9 +2027,15 @@
      * succeeded.
      * @hide
      */
+    @SuppressLint("SamShouldBeLast")
+    @NonNull
+    @SystemApi
+    @RequiresPermission(anyOf = {COPY_ACCOUNTS, INTERACT_ACROSS_USERS_FULL})
+    @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
     public AccountManagerFuture<Boolean> copyAccountToUser(
-            final Account account, final UserHandle fromUser, final UserHandle toUser,
-            AccountManagerCallback<Boolean> callback, Handler handler) {
+            @NonNull final Account account, @NonNull final UserHandle fromUser,
+            @NonNull final UserHandle toUser, @Nullable AccountManagerCallback<Boolean> callback,
+            @Nullable Handler handler) {
         if (account == null) throw new IllegalArgumentException("account is null");
         if (toUser == null || fromUser == null) {
             throw new IllegalArgumentException("fromUser and toUser cannot be null");
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ab75069..33ba058 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2679,62 +2679,6 @@
      */
     public static class RecentTaskInfo extends TaskInfo implements Parcelable {
         /**
-         * @hide
-         */
-        public static class PersistedTaskSnapshotData {
-            /**
-             * The bounds of the task when the last snapshot was taken, may be null if the task is
-             * not yet attached to the hierarchy.
-             * @see {@link android.window.TaskSnapshot#mTaskSize}.
-             * @hide
-             */
-            public @Nullable Point taskSize;
-
-            /**
-             * The content insets of the task when the task snapshot was taken.
-             * @see {@link android.window.TaskSnapshot#mContentInsets}.
-             * @hide
-             */
-            public @Nullable Rect contentInsets;
-
-            /**
-             * The size of the last snapshot taken, may be null if there is no associated snapshot.
-             * @see {@link android.window.TaskSnapshot#mSnapshot}.
-             * @hide
-             */
-            public @Nullable Point bufferSize;
-
-            /**
-             * Sets the data from the other data.
-             * @hide
-             */
-            public void set(PersistedTaskSnapshotData other) {
-                taskSize = other.taskSize;
-                contentInsets = other.contentInsets;
-                bufferSize = other.bufferSize;
-            }
-
-            /**
-             * Sets the data from the provided {@param snapshot}.
-             * @hide
-             */
-            public void set(TaskSnapshot snapshot) {
-                if (snapshot == null) {
-                    taskSize = null;
-                    contentInsets = null;
-                    bufferSize = null;
-                    return;
-                }
-                final HardwareBuffer buffer = snapshot.getHardwareBuffer();
-                taskSize = new Point(snapshot.getTaskSize());
-                contentInsets = new Rect(snapshot.getContentInsets());
-                bufferSize = buffer != null
-                        ? new Point(buffer.getWidth(), buffer.getHeight())
-                        : null;
-            }
-        }
-
-        /**
          * If this task is currently running, this is the identifier for it.
          * If it is not running, this will be -1.
          *
@@ -2770,24 +2714,6 @@
         @Deprecated
         public int affiliatedTaskId;
 
-        /**
-         * Information of organized child tasks.
-         *
-         * @deprecated No longer used
-         * @hide
-         */
-        @Deprecated
-        public ArrayList<RecentTaskInfo> childrenTaskInfos = new ArrayList<>();
-
-        /**
-         * Information about the last snapshot taken for this task.
-         *
-         * @deprecated No longer used
-         * @hide
-         */
-        @Deprecated
-        public PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
-
         public RecentTaskInfo() {
         }
 
@@ -2803,10 +2729,6 @@
         public void readFromParcel(Parcel source) {
             id = source.readInt();
             persistentId = source.readInt();
-            childrenTaskInfos = source.readArrayList(RecentTaskInfo.class.getClassLoader(), android.app.ActivityManager.RecentTaskInfo.class);
-            lastSnapshotData.taskSize = source.readTypedObject(Point.CREATOR);
-            lastSnapshotData.contentInsets = source.readTypedObject(Rect.CREATOR);
-            lastSnapshotData.bufferSize = source.readTypedObject(Point.CREATOR);
             super.readTaskFromParcel(source);
         }
 
@@ -2814,10 +2736,6 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(id);
             dest.writeInt(persistentId);
-            dest.writeList(childrenTaskInfos);
-            dest.writeTypedObject(lastSnapshotData.taskSize, flags);
-            dest.writeTypedObject(lastSnapshotData.contentInsets, flags);
-            dest.writeTypedObject(lastSnapshotData.bufferSize, flags);
             super.writeTaskToParcel(dest, flags);
         }
 
@@ -2884,11 +2802,6 @@
                 pw.println(" }");
             }
             pw.print("   ");
-            pw.print(" lastSnapshotData {");
-            pw.print(" taskSize=" + lastSnapshotData.taskSize);
-            pw.print(" contentInsets=" + lastSnapshotData.contentInsets);
-            pw.print(" bufferSize=" + lastSnapshotData.bufferSize);
-            pw.println(" }");
         }
     }
 
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 16444dc..6efc4ef 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -62,6 +62,7 @@
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.health.connect.HealthPermissions;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -484,21 +485,35 @@
      */
     public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_HEALTH =
             new ForegroundServiceTypePolicyInfo(
-            FOREGROUND_SERVICE_TYPE_HEALTH,
-            ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
-            ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
-            new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
-                new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH)
-            }, true),
-            new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
-                new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION),
-                new RegularPermission(Manifest.permission.BODY_SENSORS),
-                new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS),
-            }, false),
-            FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */,
-            true /* permissionEnforcementFlagDefaultValue */,
-            false /* foregroundOnlyPermission */
-    );
+                    FOREGROUND_SERVICE_TYPE_HEALTH,
+                    ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
+                    ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
+                    new ForegroundServiceTypePermissions(
+                            new ForegroundServiceTypePermission[] {
+                                new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_HEALTH)
+                            },
+                            true),
+                    new ForegroundServiceTypePermissions(getAllowedHealthPermissions(), false),
+                    FGS_TYPE_PERM_ENFORCEMENT_FLAG_HEALTH /* permissionEnforcementFlag */,
+                    true /* permissionEnforcementFlagDefaultValue */,
+                    false /* foregroundOnlyPermission */);
+
+    /** Returns the permissions needed for the policy of the health foreground service type. */
+    private static ForegroundServiceTypePermission[] getAllowedHealthPermissions() {
+        final ArrayList<ForegroundServiceTypePermission> permissions = new ArrayList<>();
+        permissions.add(new RegularPermission(Manifest.permission.ACTIVITY_RECOGNITION));
+        permissions.add(new RegularPermission(Manifest.permission.HIGH_SAMPLING_RATE_SENSORS));
+
+        if (android.permission.flags.Flags.replaceBodySensorPermissionEnabled()) {
+            permissions.add(new RegularPermission(HealthPermissions.READ_HEART_RATE));
+            permissions.add(new RegularPermission(HealthPermissions.READ_SKIN_TEMPERATURE));
+            permissions.add(new RegularPermission(HealthPermissions.READ_OXYGEN_SATURATION));
+        } else {
+            permissions.add(new RegularPermission(Manifest.permission.BODY_SENSORS));
+        }
+
+        return permissions.toArray(new ForegroundServiceTypePermission[permissions.size()]);
+    }
 
     /**
      * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING}.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ff73382..b78f111 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3257,7 +3257,7 @@
      */
     @FlaggedApi(Flags.FLAG_UI_RICH_ONGOING)
     public boolean hasPromotableCharacteristics() {
-        return isColorized()
+        return isColorizedRequested()
                 && hasTitle()
                 && !containsCustomViews()
                 && hasPromotableStyle();
@@ -4083,6 +4083,12 @@
                 flags &= ~FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY;
             }
         }
+        if (Flags.apiRichOngoing()) {
+            if ((flags & FLAG_PROMOTED_ONGOING) != 0) {
+                flagStrings.add("PROMOTED_ONGOING");
+                flags &= ~FLAG_PROMOTED_ONGOING;
+            }
+        }
 
         if (android.service.notification.Flags.notificationSilentFlag()) {
             if ((flags & FLAG_SILENT) != 0) {
@@ -7792,8 +7798,16 @@
      * @hide
      */
     public boolean isColorized() {
-        return extras.getBoolean(EXTRA_COLORIZED)
-                && (hasColorizedPermission() || isFgsOrUij());
+        return isColorizedRequested()
+                && (hasColorizedPermission() || isFgsOrUij() || isPromotedOngoing());
+    }
+
+    /**
+     * @return true if this notification has requested to be colorized, regardless of whether it
+     * meets the requirements to be displayed that way.
+     */
+    private boolean isColorizedRequested() {
+        return extras.getBoolean(EXTRA_COLORIZED);
     }
 
     /**
@@ -7807,6 +7821,19 @@
     }
 
     /**
+     * Returns whether this notification is a promoted ongoing notification.
+     *
+     * This requires the Notification.FLAG_PROMOTED_ONGOING flag to be set
+     * (which may be true once the api_rich_ongoing feature flag is enabled),
+     * and requires that the ui_rich_ongoing feature flag is enabled.
+     *
+     * @hide
+     */
+    public boolean isPromotedOngoing() {
+        return Flags.uiRichOngoing() && (flags & Notification.FLAG_PROMOTED_ONGOING) != 0;
+    }
+
+    /**
      * @return true if this is a media style notification with a media session
      *
      * @hide
@@ -11671,8 +11698,10 @@
             return points;
         }
 
-        @NonNull
-        private NotificationProgressModel createProgressModel(int defaultProgressColor,
+        /**
+         * @hide
+         */
+        public @NonNull NotificationProgressModel createProgressModel(int defaultProgressColor,
                 int backgroundColor) {
             final NotificationProgressModel model;
             if (mIndeterminate) {
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 087e246..3cffca7 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -206,11 +206,15 @@
             assets.addPresetApkKeys(extractApkKeys(collector.collectedKey()));
             return new Pair<>(assets, size);
         }
-        final var newAssetsBuilder = new AssetManager.Builder();
+        final var newAssetsBuilder = new AssetManager.Builder().setNoInit();
         for (final var asset : assets.getApkAssets()) {
-            if (!asset.isForLoader()) {
-                newAssetsBuilder.addApkAssets(asset);
+            // Skip everything that's either default, or will get added by the collector (builder
+            // doesn't check for duplicates at all).
+            if (asset.isSystem() || asset.isForLoader() || asset.isOverlay()
+                    || asset.isSharedLib()) {
+                continue;
             }
+            newAssetsBuilder.addApkAssets(asset);
         }
         for (final var key : extractApkKeys(collector.collectedKey())) {
             try {
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 4285b0a..8243d88 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -20,6 +20,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
+import android.health.connect.HealthPermissions;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Printer;
@@ -361,8 +362,10 @@
      * {@link android.Manifest.permission#FOREGROUND_SERVICE_HEALTH} and one of the following
      * permissions:
      * {@link android.Manifest.permission#ACTIVITY_RECOGNITION},
-     * {@link android.Manifest.permission#BODY_SENSORS},
      * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}.
+     * {@link android.health.connect.HealthPermissions#READ_HEART_RATE},
+     * {@link android.health.connect.HealthPermissions#READ_SKIN_TEMPERATURE},
+     * {@link android.health.connect.HealthPermissions#READ_OXYGEN_SATURATION},
      */
     @RequiresPermission(
             allOf = {
@@ -370,10 +373,13 @@
             },
             anyOf = {
                 Manifest.permission.ACTIVITY_RECOGNITION,
-                Manifest.permission.BODY_SENSORS,
                 Manifest.permission.HIGH_SAMPLING_RATE_SENSORS,
+                HealthPermissions.READ_HEART_RATE,
+                HealthPermissions.READ_SKIN_TEMPERATURE,
+                HealthPermissions.READ_OXYGEN_SATURATION,
             }
     )
+    @FlaggedApi(android.permission.flags.Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED)
     public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 1 << 8;
 
     /**
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index f23c193..6fc7d90 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -105,3 +105,12 @@
     # This flag is used to control aapt2 behavior.
     is_fixed_read_only: true
 }
+
+flag {
+    name: "resources_minor_version_support"
+    is_exported: true
+    namespace: "resource_manager"
+    description: "Feature flag for supporting minor version in Resources"
+    bug: "373535266"
+    is_fixed_read_only: true
+}
diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.java b/core/java/android/hardware/contexthub/HubEndpointInfo.java
index b1d5523..5265d56 100644
--- a/core/java/android/hardware/contexthub/HubEndpointInfo.java
+++ b/core/java/android/hardware/contexthub/HubEndpointInfo.java
@@ -156,7 +156,7 @@
         mRequiredPermissions = Arrays.asList(endpointInfo.requiredPermissions);
         mHubServiceInfos = new ArrayList<>(endpointInfo.services.length);
         for (int i = 0; i < endpointInfo.services.length; i++) {
-            mHubServiceInfos.set(i, new HubServiceInfo(endpointInfo.services[i]));
+            mHubServiceInfos.add(new HubServiceInfo(endpointInfo.services[i]));
         }
     }
 
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index dadb5c38..977c5bd 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -407,6 +407,12 @@
     private boolean mUsingCtrlShiftShortcut = false;
 
     /**
+     * Last handwriting bounds used for stylus handwriting
+     * {@link #setStylusHandwritingRegion(Region)}.
+     */
+    private Region mLastHandwritingRegion;
+
+    /**
      * Returns whether {@link InputMethodService} is responsible for rendering the back button and
      * the IME switcher button or not when the gestural navigation is enabled.
      *
@@ -1532,6 +1538,7 @@
                     return;
                 }
                 editorInfo.makeCompatible(getApplicationInfo().targetSdkVersion);
+                mLastHandwritingRegion = null;
                 getInputMethodInternal().restartInput(new RemoteInputConnection(ric, sessionId),
                         editorInfo);
             }
@@ -2840,6 +2847,7 @@
             mHandler.removeCallbacks(mFinishHwRunnable);
         }
         mFinishHwRunnable = null;
+        mLastHandwritingRegion = null;
 
         final int requestId = mHandwritingRequestId.getAsInt();
         mHandwritingRequestId = OptionalInt.empty();
@@ -3166,6 +3174,40 @@
         registerDefaultOnBackInvokedCallback();
     }
 
+    /**
+     * Sets a new stylus handwriting region as user continues to write on an editor on screen.
+     * Stylus strokes that are started within the {@code touchableRegion} are treated as
+     * continuation of handwriting and all the events outside are passed-through to the IME target
+     * app, causing stylus handwriting to finish {@link #finishStylusHandwriting()}.
+     * By default, {@link WindowManager#getMaximumWindowMetrics()} is handwritable and
+     * {@code touchableRegion} resets after each handwriting session.
+     * <p>
+     * For example, the IME can use this API to dynamically expand the stylus handwriting region on
+     * every stylus stroke as user continues to write on an editor. The region should grow around
+     * the last stroke so that a UI element below the IME window is still interactable when it is
+     * spaced sufficiently away (~2 character dimensions) from last stroke.
+     * </p>
+     * <p>
+     * Note: Setting handwriting touchable region is supported on IMEs that support stylus
+     * handwriting {@link InputMethodInfo#supportsStylusHandwriting()}.
+     * </p>
+     *
+     * @param handwritingRegion new stylus handwritable {@link Region} that can accept stylus touch.
+     */
+    @FlaggedApi(Flags.FLAG_ADAPTIVE_HANDWRITING_BOUNDS)
+    public final void setStylusHandwritingRegion(@NonNull Region handwritingRegion) {
+        if (handwritingRegion.equals(mLastHandwritingRegion)) {
+            Log.v(TAG, "Failed to set setStylusHandwritingRegion():"
+                    + " same region set twice.");
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "Setting new handwriting region for stylus handwriting "
+                    + handwritingRegion + " from last " + mLastHandwritingRegion);
+        }
+        mLastHandwritingRegion = handwritingRegion;
+    }
 
     /**
      * Registers an {@link OnBackInvokedCallback} to handle back invocation when ahead-of-time
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index 224b10d..2b0042d 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 
 import com.android.internal.util.Preconditions;
@@ -106,7 +107,9 @@
      * All timings should be in {@link SystemClock#uptimeNanos()}.
      */
     public static class Session implements Closeable {
-        private long mNativeSessionPtr;
+        /** @hide */
+        @UnsupportedAppUsage
+        public long mNativeSessionPtr;
 
         /** @hide */
         public Session(long nativeSessionPtr) {
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index b5a822b..1093503 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -418,3 +418,12 @@
     description: "Add new checkOp APIs that accept attributionTag"
     bug: "240617242"
 }
+
+flag {
+    name: "device_policy_management_role_split_create_managed_profile_enabled"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "enterprise"
+    description: "Gives the device policy management role the ability to create a managed profile using new APIs"
+    bug: "375382324"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a35c9c1..19b0c6f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -20454,6 +20454,29 @@
              * @hide
              */
             public static final String AUTO_BEDTIME_MODE = "auto_bedtime_mode";
+
+            /**
+             * Indicates that all elements of the system status tray on wear should be rendered
+             * by default wear system.
+             *
+             * @hide
+             */
+            public static final int STATUS_TRAY_CONFIGURATION_DEFAULT = 0;
+
+            /**
+             * Indicates that all elements of the system status tray on wear should be hidden.
+             *
+             * @hide
+             */
+            public static final int STATUS_TRAY_CONFIGURATION_SYSTEM_HIDDEN = 1;
+
+            /**
+             * Configuration of system status tray in wear.
+             *
+             * @hide
+             */
+            public static final String WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION =
+                    "wear_system_status_tray_configuration";
         }
     }
 
diff --git a/core/java/android/service/carrier/CarrierMessagingService.java b/core/java/android/service/carrier/CarrierMessagingService.java
index 61213e6..a825a7e 100644
--- a/core/java/android/service/carrier/CarrierMessagingService.java
+++ b/core/java/android/service/carrier/CarrierMessagingService.java
@@ -16,6 +16,7 @@
 
 package android.service.carrier;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -26,6 +27,8 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import com.android.internal.telephony.flags.Flags;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
@@ -97,16 +100,317 @@
     public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
 
     /**
-     * SMS/MMS sending failed. We should not retry via the carrier network.
+     * SMS/MMS sending failed due to an unspecified issue. Sending will not be retried via the
+     * carrier network.
+     *
+     * <p>Maps to SmsManager.RESULT_RIL_GENERIC_FAILURE for SMS and SmsManager.MMS_ERROR_UNSPECIFIED
+     * for MMS.
      */
     public static final int SEND_STATUS_ERROR = 2;
 
+    /**
+     * More precise error reasons for outbound SMS send requests. These will not be retried on the
+     * carrier network.
+     *
+     * <p>Each code maps directly to an SmsManager code (e.g. SEND_STATS_RESULT_ERROR_NULL_PDU maps
+     * to SmsManager.RESULT_ERROR_NULL_PDU).
+     */
+
+    /**
+     * Generic failure cause.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE = 200;
+
+    /**
+     * Failed because no pdu provided.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_NULL_PDU
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_NULL_PDU = 201;
+
+    /**
+     * Failed because service is currently unavailable.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_NO_SERVICE = 202;
+
+    /**
+     * Failed because we reached the sending queue limit.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED = 203;
+
+    /**
+     * Failed because FDN is enabled.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE = 204;
+
+    /**
+     * Failed because user denied the sending of this short code.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED = 205;
+
+    /**
+     * Failed because the user has denied this app ever send premium short codes.
+     *
+     * @see android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED = 206;
+
+    /**
+     * Failed because of network rejection.
+     *
+     * @see android.telephony.SmsManager.RESULT_NETWORK_REJECT
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_NETWORK_REJECT = 207;
+
+    /**
+     * Failed because of invalid arguments.
+     *
+     * @see android.telephony.SmsManager.RESULT_INVALID_ARGUMENTS
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_INVALID_ARGUMENTS = 208;
+
+    /**
+     * Failed because of an invalid state.
+     *
+     * @see android.telephony.SmsManager.RESULT_INVALID_STATE
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_INVALID_STATE = 209;
+
+    /**
+     * Failed because the sms format is not valid.
+     *
+     * @see android.telephony.SmsManager.RESULT_INVALID_SMS_FORMAT
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_INVALID_SMS_FORMAT = 210;
+
+    /**
+     * Failed because of a network error.
+     *
+     * @see android.telephony.SmsManager.RESULT_NETWORK_ERROR
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_NETWORK_ERROR = 211;
+
+    /**
+     * Failed because of an encoding error.
+     *
+     * @see android.telephony.SmsManager.RESULT_ENCODING_ERROR
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_ENCODING_ERROR = 212;
+
+    /**
+     * Failed because of an invalid smsc address
+     *
+     * @see android.telephony.SmsManager.RESULT_INVALID_SMSC_ADDRESS
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS = 213;
+
+    /**
+     * Failed because the operation is not allowed.
+     *
+     * @see android.telephony.SmsManager.RESULT_OPERATION_NOT_ALLOWED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED = 214;
+
+    /**
+     * Failed because the operation was cancelled.
+     *
+     * @see android.telephony.SmsManager.RESULT_CANCELLED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_CANCELLED = 215;
+
+    /**
+     * Failed because the request is not supported.
+     *
+     * @see android.telephony.SmsManager.RESULT_REQUEST_NOT_SUPPORTED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED = 216;
+
+    /**
+     * Failed sending during an emergency call.
+     *
+     * @see android.telephony.SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY = 217;
+
+    /**
+     * Failed to send an sms retry.
+     *
+     * @see android.telephony.SmsManager.RESULT_SMS_SEND_RETRY_FAILED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED = 218;
+
+    /**
+     * More precise error reasons for outbound MMS send requests. These will not be retried on the
+     * carrier network.
+     *
+     * <p>Each code maps directly to an SmsManager code (e.g.
+     * SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS maps to SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS).
+     */
+
+    /**
+     * Unspecific MMS error occurred during send.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_UNSPECIFIED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_UNSPECIFIED = 400;
+
+    /**
+     * ApnException occurred during MMS network setup.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_INVALID_APN
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_INVALID_APN = 401;
+
+    /**
+     * An error occurred during the MMS connection setup.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 402;
+
+    /**
+     * An error occurred during the HTTP client setup.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_HTTP_FAILURE
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_HTTP_FAILURE = 403;
+
+    /**
+     * An I/O error occurred reading the PDU.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_IO_ERROR
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_IO_ERROR = 404;
+
+    /**
+     * An error occurred while retrying sending the MMS.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_RETRY
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_RETRY = 405;
+
+    /**
+     * The carrier-dependent configuration values could not be loaded.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_CONFIGURATION_ERROR
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 406;
+
+    /**
+     * There is neither Wi-Fi nor mobile data network.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_NO_DATA_NETWORK
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK = 407;
+
+    /**
+     * The subscription id for the send is invalid.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 408;
+
+    /**
+     * The subscription id for the send is inactive.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 409;
+
+    /**
+     * Data is disabled for the MMS APN.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_DATA_DISABLED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_DATA_DISABLED = 410;
+
+    /**
+     * MMS is disabled by a carrier.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 411;
+
     /** @hide */
-    @IntDef(prefix = { "SEND_STATUS_" }, value = {
-            SEND_STATUS_OK,
-            SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
-            SEND_STATUS_ERROR
-    })
+    @IntDef(
+            prefix = {"SEND_STATUS_"},
+            value = {
+                SEND_STATUS_OK,
+                SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
+                SEND_STATUS_ERROR,
+                SEND_STATUS_RESULT_ERROR_GENERIC_FAILURE,
+                SEND_STATUS_RESULT_ERROR_NULL_PDU,
+                SEND_STATUS_RESULT_ERROR_NO_SERVICE,
+                SEND_STATUS_RESULT_ERROR_LIMIT_EXCEEDED,
+                SEND_STATUS_RESULT_ERROR_FDN_CHECK_FAILURE,
+                SEND_STATUS_RESULT_ERROR_SHORT_CODE_NOT_ALLOWED,
+                SEND_STATUS_RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED,
+                SEND_STATUS_RESULT_NETWORK_REJECT,
+                SEND_STATUS_RESULT_INVALID_ARGUMENTS,
+                SEND_STATUS_RESULT_INVALID_STATE,
+                SEND_STATUS_RESULT_INVALID_SMS_FORMAT,
+                SEND_STATUS_RESULT_NETWORK_ERROR,
+                SEND_STATUS_RESULT_ENCODING_ERROR,
+                SEND_STATUS_RESULT_INVALID_SMSC_ADDRESS,
+                SEND_STATUS_RESULT_OPERATION_NOT_ALLOWED,
+                SEND_STATUS_RESULT_CANCELLED,
+                SEND_STATUS_RESULT_REQUEST_NOT_SUPPORTED,
+                SEND_STATUS_RESULT_SMS_BLOCKED_DURING_EMERGENCY,
+                SEND_STATUS_RESULT_SMS_SEND_RETRY_FAILED,
+                SEND_STATUS_MMS_ERROR_UNSPECIFIED,
+                SEND_STATUS_MMS_ERROR_INVALID_APN,
+                SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS,
+                SEND_STATUS_MMS_ERROR_HTTP_FAILURE,
+                SEND_STATUS_MMS_ERROR_IO_ERROR,
+                SEND_STATUS_MMS_ERROR_RETRY,
+                SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR,
+                SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK,
+                SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID,
+                SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION,
+                SEND_STATUS_MMS_ERROR_DATA_DISABLED,
+                SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER
+            })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SendResult {}
 
@@ -121,16 +425,138 @@
     public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
 
     /**
-     * MMS downloading failed. We should not retry via the carrier network.
+     * MMS downloading failed due to an unspecified issue. Downloading will not be retried via the
+     * carrier network.
+     *
+     * <p>Maps to SmsManager.MMR_ERROR_UNSPECIFIED.
      */
     public static final int DOWNLOAD_STATUS_ERROR = 2;
 
+    /**
+     * More precise error reasons for inbound MMS download requests. These will not be retried on
+     * the carrier network.
+     *
+     * <p>Each code maps directly to an SmsManager code (e.g.
+     * DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS maps to
+     * SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS).
+     */
+
+    /**
+     * Unspecific MMS error occurred during download.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_UNSPECIFIED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED = 600;
+
+    /**
+     * ApnException occurred during MMS network setup.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_INVALID_APN
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN = 601;
+
+    /**
+     * An error occurred during the MMS connection setup.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS = 602;
+
+    /**
+     * An error occurred during the HTTP client setup.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_HTTP_FAILURE
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE = 603;
+
+    /**
+     * An I/O error occurred reading the PDU.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_IO_ERROR
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR = 604;
+
+    /**
+     * An error occurred while retrying downloading the MMS.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_RETRY
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_RETRY = 605;
+
+    /**
+     * The carrier-dependent configuration values could not be loaded.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_CONFIGURATION_ERROR
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR = 606;
+
+    /**
+     * There is neither Wi-Fi nor mobile data network.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_NO_DATA_NETWORK
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK = 607;
+
+    /**
+     * The subscription id for the download is invalid.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID = 608;
+
+    /**
+     * The subscription id for the download is inactive.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION = 609;
+
+    /**
+     * Data is disabled for the MMS APN.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_DATA_DISABLED
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED = 610;
+
+    /**
+     * MMS is disabled by a carrier.
+     *
+     * @see android.telephony.SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER
+     */
+    @FlaggedApi(Flags.FLAG_TEMPORARY_FAILURES_IN_CARRIER_MESSAGING_SERVICE)
+    public static final int DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER = 611;
+
     /** @hide */
-    @IntDef(prefix = { "DOWNLOAD_STATUS_" }, value = {
-            DOWNLOAD_STATUS_OK,
-            DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK,
-            DOWNLOAD_STATUS_ERROR
-    })
+    @IntDef(
+            prefix = {"DOWNLOAD_STATUS_"},
+            value = {
+                DOWNLOAD_STATUS_OK,
+                DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK,
+                DOWNLOAD_STATUS_ERROR,
+                DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED,
+                DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN,
+                DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS,
+                DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE,
+                DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR,
+                DOWNLOAD_STATUS_MMS_ERROR_RETRY,
+                DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR,
+                DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK,
+                DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID,
+                DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION,
+                DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED,
+                DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER
+            })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DownloadResult {}
 
diff --git a/core/jni/android_os_PerformanceHintManager.cpp b/core/jni/android_os_PerformanceHintManager.cpp
index aebe7ea..0f78c9e 100644
--- a/core/jni/android_os_PerformanceHintManager.cpp
+++ b/core/jni/android_os_PerformanceHintManager.cpp
@@ -88,9 +88,10 @@
                         "Failed to find required symbol "
                         "APerformanceHint_getPreferredUpdateRateNanos!");
 
-    gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+    gAPH_createSessionFn =
+            (APH_createSession)dlsym(handle_, "APerformanceHint_createSessionFromJava");
     LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
-                        "Failed to find required symbol APerformanceHint_createSession!");
+                        "Failed to find required symbol APerformanceHint_createSessionFromJava!");
 
     gAPH_updateTargetWorkDurationFn =
             (APH_updateTargetWorkDuration)dlsym(handle_,
@@ -106,9 +107,9 @@
                         "Failed to find required symbol "
                         "APerformanceHint_reportActualWorkDuration!");
 
-    gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+    gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSessionFromJava");
     LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
-                        "Failed to find required symbol APerformanceHint_closeSession!");
+                        "Failed to find required symbol APerformanceHint_closeSessionFromJava!");
 
     gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
     LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 26e63bc..8042b30 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -171,6 +171,7 @@
         "android.os.vibrator.flags-aconfig",
         "android.media.tv.flags-aconfig",
         "android.security.flags-aconfig",
+        "device_policy_aconfig_flags",
         "com.android.hardware.input.input-aconfig",
         "aconfig_trade_in_mode_flags",
         "art-aconfig-flags",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cd05a67..dae182f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2649,6 +2649,22 @@
         android:label="@string/permlab_getAccounts" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
 
+    <!-- @SystemApi Allows access to remove an account.
+         @FlaggedApi(android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.REMOVE_ACCOUNTS"
+        android:protectionLevel="signature|role"
+        android:featureFlag="android.app.admin.flags.split_create_managed_profile_enabled" />
+
+    <!-- @SystemApi Allows access to copy an account to another user.
+         @FlaggedApi(android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED)
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.COPY_ACCOUNTS"
+        android:protectionLevel="signature|role"
+        android:featureFlag="android.app.admin.flags.split_create_managed_profile_enabled" />
+
     <!-- Allows applications to call into AccountAuthenticators.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCOUNT_MANAGER"
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 75aca1b..7ce2ed8 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -23,10 +23,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.platform.test.ravenwood.RavenwoodConfig;
+import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.Objects;
@@ -39,8 +40,8 @@
     private static final String PERSIST_KEY = "persist.sys.testkey";
     private static final String NONEXIST_KEY = "doesnotexist_2341431";
 
-    @RavenwoodConfig.Config
-    public static final RavenwoodConfig mRavenwood = new RavenwoodConfig.Builder()
+    @Rule
+    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
             .setSystemPropertyMutable(KEY, null)
             .setSystemPropertyMutable(UNSET_KEY, null)
             .setSystemPropertyMutable(PERSIST_KEY, null)
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
index 5e41865..375968a 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
@@ -113,7 +113,7 @@
                     style="?android:attr/buttonBarButtonStyle"
                     android:layout_width="41dp"
                     android:layout_height="@dimen/desktop_mode_maximize_menu_button_height"
-                    android:layout_marginRight="4dp"
+                    android:layout_marginEnd="4dp"
                     android:background="@drawable/desktop_mode_maximize_menu_button_background"
                     android:importantForAccessibility="yes"
                     android:contentDescription="@string/desktop_mode_maximize_menu_snap_left_button_text"
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 7078d66..21ec84d 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -504,17 +504,15 @@
     <dimen name="desktop_mode_maximize_menu_buttons_fill_radius">4dp</dimen>
     <!-- The padding between the outline and fill of the maximize menu snap and maximize buttons. -->
     <dimen name="desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding">4dp</dimen>
-    <!-- The padding between the outline and fill of the maximize menu snap and maximize buttons. -->
-    <dimen name="desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding_bottom">8dp</dimen>
     <!-- The vertical padding between the outline and fill of the maximize menu restore button. -->
     <dimen name="desktop_mode_maximize_menu_restore_button_fill_vertical_padding">13dp</dimen>
     <!-- The horizontal padding between the outline and fill of the maximize menu restore button. -->
-    <dimen name="desktop_mode_maximize_menu_restore_button_fill_horizontal_padding">21dp</dimen>
+    <dimen name="desktop_mode_maximize_menu_restore_button_fill_horizontal_padding">15dp</dimen>
     <!-- The padding between the outline and fill of the maximize menu immersive button. -->
-    <dimen name="desktop_mode_maximize_menu_immersive_button_fill_padding">4dp</dimen>
+    <dimen name="desktop_mode_maximize_menu_immersive_button_fill_padding">0dp</dimen>
 
     <!-- The corner radius of the maximize menu. -->
-    <dimen name="desktop_mode_maximize_menu_corner_radius">8dp</dimen>
+    <dimen name="desktop_mode_maximize_menu_corner_radius">16dp</dimen>
 
     <!-- The radius of the Maximize menu shadow. -->
     <dimen name="desktop_mode_maximize_menu_shadow_radius">8dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 012579a..468c345 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -318,7 +318,7 @@
     <!-- Maximize menu maximize button string. -->
     <string name="desktop_mode_maximize_menu_maximize_text">Maximize Screen</string>
     <!-- Maximize menu snap buttons string. -->
-    <string name="desktop_mode_maximize_menu_snap_text">Snap Screen</string>
+    <string name="desktop_mode_maximize_menu_snap_text">Resize</string>
     <!-- Snap resizing non-resizable string. -->
     <string name="desktop_mode_non_resizable_snap_text">App can\'t be moved here</string>
     <!-- Accessibility text for the Maximize Menu's immersive button [CHAR LIMIT=NONE] -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 603a9ec..b82496e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1327,7 +1327,11 @@
 
     /** Promote the provided bubble from the overflow view. */
     public void promoteBubbleFromOverflow(Bubble bubble) {
-        mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
+        if (isShowingAsBubbleBar()) {
+            mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_REMOVE_BACK_TO_BAR);
+        } else {
+            mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
+        }
         ProtoLog.d(WM_SHELL_BUBBLES, "promoteBubbleFromOverflow=%s", bubble.getKey());
         bubble.setInflateSynchronously(mInflateSynchronously);
         bubble.setShouldAutoExpand(true);
@@ -1350,11 +1354,7 @@
         if (BubbleOverflow.KEY.equals(key)) {
             mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
             mLayerView.showExpandedView(mBubbleData.getOverflow());
-            if (wasExpanded) {
-                mLogger.log(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED);
-            } else {
-                mLogger.log(BubbleLogger.Event.BUBBLE_BAR_EXPANDED);
-            }
+            mLogger.log(BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_SELECTED);
             return;
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 4de9dfa..2945691 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -759,7 +759,9 @@
                 if (b != null) {
                     b.stopInflation();
                 }
-                mLogger.logOverflowRemove(b, reason);
+                if (!mPositioner.isShowingInBubbleBar()) {
+                    mLogger.logStackOverflowRemove(b, reason);
+                }
                 mOverflowBubbles.remove(b);
                 mStateChange.bubbleRemoved(b, reason);
                 mStateChange.removedOverflowBubble = b;
@@ -802,6 +804,27 @@
             setNewSelectedIndex(indexToRemove);
         }
         maybeSendDeleteIntent(reason, bubbleToRemove);
+
+        if (mPositioner.isShowingInBubbleBar()) {
+            logBubbleBarBubbleRemoved(bubbleToRemove, reason);
+        }
+    }
+
+    private void logBubbleBarBubbleRemoved(Bubble bubble, @DismissReason int reason) {
+        switch (reason) {
+            case Bubbles.DISMISS_NOTIF_CANCEL:
+                mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_CANCELED);
+                break;
+            case Bubbles.DISMISS_TASK_FINISHED:
+                mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_ACTIVITY_FINISH);
+                break;
+            case Bubbles.DISMISS_BLOCKED:
+            case Bubbles.DISMISS_NO_LONGER_BUBBLE:
+                mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED);
+                break;
+            default:
+                // skip logging other events
+        }
     }
 
     private void setNewSelectedIndex(int indexOfSelected) {
@@ -862,7 +885,7 @@
             return;
         }
         ProtoLog.d(WM_SHELL_BUBBLES, "overflowBubble=%s", bubble.getKey());
-        mLogger.logOverflowAdd(bubble, reason);
+        mLogger.logOverflowAdd(bubble, mPositioner.isShowingInBubbleBar(), reason);
         if (mOverflowBubbles.isEmpty()) {
             mStateChange.showOverflowChanged = true;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
index 3663073..347df33 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleLogger.java
@@ -182,10 +182,12 @@
     }
 
     /**
+     * Log when a bubble is removed from overflow in stack view
+     *
      * @param b Bubble removed from overflow
      * @param r Reason that bubble was removed
      */
-    public void logOverflowRemove(Bubble b, @Bubbles.DismissReason int r) {
+    public void logStackOverflowRemove(Bubble b, @Bubbles.DismissReason int r) {
         if (r == Bubbles.DISMISS_NOTIF_CANCEL) {
             log(b, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_CANCEL);
         } else if (r == Bubbles.DISMISS_GROUP_CANCELLED) {
@@ -201,13 +203,19 @@
      * @param b Bubble added to overflow
      * @param r Reason that bubble was added to overflow
      */
-    public void logOverflowAdd(Bubble b, @Bubbles.DismissReason int r) {
-        if (r == Bubbles.DISMISS_AGED) {
-            log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
-        } else if (r == Bubbles.DISMISS_USER_GESTURE) {
-            log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
-        } else if (r == Bubbles.DISMISS_RELOAD_FROM_DISK) {
-            log(b, Event.BUBBLE_OVERFLOW_RECOVER);
+    public void logOverflowAdd(Bubble b, boolean bubbleBar, @Bubbles.DismissReason int r) {
+        if (bubbleBar) {
+            if (r == Bubbles.DISMISS_AGED) {
+                log(b, Event.BUBBLE_BAR_OVERFLOW_ADD_AGED);
+            }
+        } else {
+            if (r == Bubbles.DISMISS_AGED) {
+                log(b, Event.BUBBLE_OVERFLOW_ADD_AGED);
+            } else if (r == Bubbles.DISMISS_USER_GESTURE) {
+                log(b, Event.BUBBLE_OVERFLOW_ADD_USER_GESTURE);
+            } else if (r == Bubbles.DISMISS_RELOAD_FROM_DISK) {
+                log(b, Event.BUBBLE_OVERFLOW_RECOVER);
+            }
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index c386c93..068b2d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -830,6 +830,13 @@
         mShowingInBubbleBar = showingInBubbleBar;
     }
 
+    /**
+     * Whether bubbles ar showing in the bubble bar from launcher.
+     */
+    boolean isShowingInBubbleBar() {
+        return mShowingInBubbleBar;
+    }
+
     public void setBubbleBarLocation(BubbleBarLocation location) {
         mBubbleBarLocation = location;
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index dab30b0..0f21756 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -88,6 +88,7 @@
 import com.android.wm.shell.splitscreen.StageTaskListener;
 
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.function.Consumer;
 
 /**
@@ -139,15 +140,21 @@
     private final Rect mTempRect = new Rect();
     private final Rect mRootBounds = new Rect();
     private final Rect mDividerBounds = new Rect();
-    // Bounds1 final position should be always at top or left
-    private final Rect mBounds1 = new Rect();
-    // Bounds2 final position should be always at bottom or right
-    private final Rect mBounds2 = new Rect();
+    /**
+     * A list of stage bounds, kept in order from top/left to bottom/right. These are the sizes of
+     * the app surfaces, not necessarily the same as the size of the rendered content.
+     * See {@link #mContentBounds}.
+     */
+    private final List<Rect> mStageBounds = List.of(new Rect(), new Rect());
+    /**
+     * A list of app content bounds, kept in order from top/left to bottom/right. These are the
+     * sizes of the rendered app contents, not necessarily the same as the size of the drawn app
+     * surfaces. See {@link #mStageBounds}.
+     */
+    private final List<Rect> mContentBounds = List.of(new Rect(), new Rect());
     // The temp bounds outside of display bounds for side stage when split screen inactive to avoid
     // flicker next time active split screen.
     private final Rect mInvisibleBounds = new Rect();
-    private final Rect mWinBounds1 = new Rect();
-    private final Rect mWinBounds2 = new Rect();
     private final SplitLayoutHandler mSplitLayoutHandler;
     private final SplitWindowManager mSplitWindowManager;
     private final DisplayController mDisplayController;
@@ -233,26 +240,26 @@
         mDividerWindowWidth = mDividerSize + 2 * mDividerInsets;
     }
 
-    /** Gets bounds of the primary split with screen based coordinate. */
-    public Rect getBounds1() {
-        return new Rect(mBounds1);
+    /** Gets the bounds of the top/left app in screen-based coordinates. */
+    public Rect getTopLeftBounds() {
+        return mStageBounds.getFirst();
     }
 
-    /** Gets bounds of the primary split with parent based coordinate. */
-    public Rect getRefBounds1() {
-        Rect outBounds = getBounds1();
+    /** Gets the bounds of the bottom/right app in screen-based coordinates. */
+    public Rect getBottomRightBounds() {
+        return mStageBounds.getLast();
+    }
+
+    /** Gets the bounds of the top/left app in parent-based coordinates. */
+    public Rect getTopLeftRefBounds() {
+        Rect outBounds = getTopLeftBounds();
         outBounds.offset(-mRootBounds.left, -mRootBounds.top);
         return outBounds;
     }
 
-    /** Gets bounds of the secondary split with screen based coordinate. */
-    public Rect getBounds2() {
-        return new Rect(mBounds2);
-    }
-
-    /** Gets bounds of the secondary split with parent based coordinate. */
-    public Rect getRefBounds2() {
-        final Rect outBounds = getBounds2();
+    /** Gets the bounds of the bottom/right app in parent-based coordinates. */
+    public Rect getBottomRightRefBounds() {
+        Rect outBounds = getBottomRightBounds();
         outBounds.offset(-mRootBounds.left, -mRootBounds.top);
         return outBounds;
     }
@@ -274,31 +281,42 @@
         return outBounds;
     }
 
-    /** Gets bounds of the primary split with screen based coordinate on the param Rect. */
-    public void getBounds1(Rect rect) {
-        rect.set(mBounds1);
+    /** Copies the top/left bounds to the provided Rect (screen-based coordinates). */
+    public void copyTopLeftBounds(Rect rect) {
+        rect.set(getTopLeftBounds());
     }
 
-    /** Gets bounds of the primary split with parent based coordinate on the param Rect. */
-    public void getRefBounds1(Rect rect) {
-        getBounds1(rect);
+    /** Copies the top/left bounds to the provided Rect (parent-based coordinates). */
+    public void copyTopLeftRefBounds(Rect rect) {
+        copyTopLeftBounds(rect);
         rect.offset(-mRootBounds.left, -mRootBounds.top);
     }
 
-    /** Gets bounds of the secondary split with screen based coordinate on the param Rect. */
-    public void getBounds2(Rect rect) {
-        rect.set(mBounds2);
+    /** Copies the bottom/right bounds to the provided Rect (screen-based coordinates). */
+    public void copyBottomRightBounds(Rect rect) {
+        rect.set(getBottomRightBounds());
     }
 
-    /** Gets bounds of the secondary split with parent based coordinate on the param Rect. */
-    public void getRefBounds2(Rect rect) {
-        getBounds2(rect);
+    /** Copies the bottom/right bounds to the provided Rect (parent-based coordinates). */
+    public void copyBottomRightRefBounds(Rect rect) {
+        copyBottomRightBounds(rect);
         rect.offset(-mRootBounds.left, -mRootBounds.top);
     }
 
-    /** Gets root bounds of the whole split layout on the param Rect. */
-    public void getRootBounds(Rect rect) {
-        rect.set(mRootBounds);
+    /**
+     * Gets the content bounds of the top/left app (the bounds of where the app contents would be
+     * drawn). Might be larger than the available surface space.
+     */
+    public Rect getTopLeftContentBounds() {
+        return mContentBounds.getFirst();
+    }
+
+    /**
+     * Gets the content bounds of the bottom/right app (the bounds of where the app contents would
+     * be drawn). Might be larger than the available surface space.
+     */
+    public Rect getBottomRightContentBounds() {
+        return mContentBounds.getLast();
     }
 
     /** Gets bounds of divider window with screen based coordinate on the param Rect. */
@@ -340,8 +358,10 @@
      */
     public float getDividerPositionAsFraction() {
         return Math.min(1f, Math.max(0f, mIsLeftRightSplit
-                ? (float) ((mBounds1.right + mBounds2.left) / 2f) / mBounds2.right
-                : (float) ((mBounds1.bottom + mBounds2.top) / 2f) / mBounds2.bottom));
+                ? (float) ((getTopLeftBounds().right + getBottomRightBounds().left) / 2f)
+                        / getBottomRightBounds().right
+                : (float) ((getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f)
+                        / getBottomRightBounds().bottom));
     }
 
     private void updateInvisibleRect() {
@@ -435,7 +455,8 @@
     }
 
     private void updateBounds(int position) {
-        updateBounds(position, mBounds1, mBounds2, mDividerBounds, true /* setEffectBounds */);
+        updateBounds(position, getTopLeftBounds(), getBottomRightBounds(), mDividerBounds,
+                true /* setEffectBounds */);
     }
 
     /** Updates recording bounds of divider window and both of the splits. */
@@ -638,8 +659,8 @@
         updateBounds(mDividerPosition);
         mWinToken1 = null;
         mWinToken2 = null;
-        mWinBounds1.setEmpty();
-        mWinBounds2.setEmpty();
+        getTopLeftContentBounds().setEmpty();
+        getBottomRightContentBounds().setEmpty();
     }
 
     /**
@@ -835,7 +856,8 @@
                 insets.left != 0 || insets.top != 0 || insets.right != 0 || insets.bottom != 0;
 
         final int dividerPos = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(
-                mIsLeftRightSplit ? mBounds2.width() : mBounds2.height()).position;
+                mIsLeftRightSplit ? getBottomRightBounds().width() : getBottomRightBounds().height()
+        ).position;
         final Rect endBounds1 = new Rect();
         final Rect endBounds2 = new Rect();
         final Rect endDividerBounds = new Rect();
@@ -847,12 +869,12 @@
         endBounds2.offset(-mRootBounds.left, -mRootBounds.top);
         endDividerBounds.offset(-mRootBounds.left, -mRootBounds.top);
 
-        ValueAnimator animator1 = moveSurface(t, topLeftStage, getRefBounds1(), endBounds1,
+        ValueAnimator animator1 = moveSurface(t, topLeftStage, getTopLeftRefBounds(), endBounds1,
                 -insets.left, -insets.top, true /* roundCorners */, true /* isGoingBehind */,
                 shouldVeil);
-        ValueAnimator animator2 = moveSurface(t, bottomRightStage, getRefBounds2(), endBounds2,
-                insets.left, insets.top, true /* roundCorners */, false /* isGoingBehind */,
-                shouldVeil);
+        ValueAnimator animator2 = moveSurface(t, bottomRightStage, getBottomRightRefBounds(),
+                endBounds2, insets.left, insets.top, true /* roundCorners */,
+                false /* isGoingBehind */, shouldVeil);
         ValueAnimator animator3 = moveSurface(t, null /* stage */, getRefDividerBounds(),
                 endDividerBounds, 0 /* offsetX */, 0 /* offsetY */, false /* roundCorners */,
                 false /* isGoingBehind */, false /* addVeil */);
@@ -1059,10 +1081,10 @@
             // Resets layer of divider bar to make sure it is always on top.
             t.setLayer(dividerLeash, Integer.MAX_VALUE);
         }
-        getRefBounds1(mTempRect);
+        copyTopLeftRefBounds(mTempRect);
         t.setPosition(leash1, mTempRect.left, mTempRect.top)
                 .setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
-        getRefBounds2(mTempRect);
+        copyBottomRightRefBounds(mTempRect);
         t.setPosition(leash2, mTempRect.left, mTempRect.top)
                 .setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
 
@@ -1084,15 +1106,17 @@
     public boolean applyTaskChanges(WindowContainerTransaction wct,
             ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) {
         boolean boundsChanged = false;
-        if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
-            setTaskBounds(wct, task1, mBounds1);
-            mWinBounds1.set(mBounds1);
+        if (!getTopLeftBounds().equals(getTopLeftContentBounds())
+                || !task1.token.equals(mWinToken1)) {
+            setTaskBounds(wct, task1, getTopLeftBounds());
+            getTopLeftContentBounds().set(getTopLeftBounds());
             mWinToken1 = task1.token;
             boundsChanged = true;
         }
-        if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) {
-            setTaskBounds(wct, task2, mBounds2);
-            mWinBounds2.set(mBounds2);
+        if (!getBottomRightBounds().equals(getBottomRightContentBounds())
+                || !task2.token.equals(mWinToken2)) {
+            setTaskBounds(wct, task2, getBottomRightBounds());
+            getBottomRightContentBounds().set(getBottomRightBounds());
             mWinToken2 = task2.token;
             boundsChanged = true;
         }
@@ -1129,22 +1153,22 @@
     public void applyLayoutOffsetTarget(WindowContainerTransaction wct, int offsetX, int offsetY,
             ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
         if (offsetX == 0 && offsetY == 0) {
-            wct.setBounds(taskInfo1.token, mBounds1);
+            wct.setBounds(taskInfo1.token, getTopLeftBounds());
             wct.setScreenSizeDp(taskInfo1.token,
                     SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
 
-            wct.setBounds(taskInfo2.token, mBounds2);
+            wct.setBounds(taskInfo2.token, getBottomRightBounds());
             wct.setScreenSizeDp(taskInfo2.token,
                     SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
         } else {
-            getBounds1(mTempRect);
+            copyTopLeftBounds(mTempRect);
             mTempRect.offset(offsetX, offsetY);
             wct.setBounds(taskInfo1.token, mTempRect);
             wct.setScreenSizeDp(taskInfo1.token,
                     taskInfo1.configuration.screenWidthDp,
                     taskInfo1.configuration.screenHeightDp);
 
-            getBounds2(mTempRect);
+            copyBottomRightBounds(mTempRect);
             mTempRect.offset(offsetX, offsetY);
             wct.setBounds(taskInfo2.token, mTempRect);
             wct.setScreenSizeDp(taskInfo2.token,
@@ -1162,9 +1186,9 @@
         pw.println(innerPrefix + "mFreezeDividerWindow=" + mFreezeDividerWindow);
         pw.println(innerPrefix + "mDimNonImeSide=" + mDimNonImeSide);
         pw.println(innerPrefix + "mDividerPosition=" + mDividerPosition);
-        pw.println(innerPrefix + "bounds1=" + mBounds1.toShortString());
+        pw.println(innerPrefix + "bounds1=" + getTopLeftBounds().toShortString());
         pw.println(innerPrefix + "dividerBounds=" + mDividerBounds.toShortString());
-        pw.println(innerPrefix + "bounds2=" + mBounds2.toShortString());
+        pw.println(innerPrefix + "bounds2=" + getBottomRightBounds().toShortString());
     }
 
     /** Handles layout change event. */
@@ -1274,15 +1298,16 @@
             }
 
             final boolean topLeftShrink = isLeftRightSplit
-                    ? position < mWinBounds1.right : position < mWinBounds1.bottom;
+                    ? position < getTopLeftContentBounds().right
+                    : position < getTopLeftContentBounds().bottom;
             if (topLeftShrink) {
                 mShrinkSide = isLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP;
-                mContentBounds.set(mWinBounds1);
-                mSurfaceBounds.set(mBounds1);
+                mContentBounds.set(getTopLeftContentBounds());
+                mSurfaceBounds.set(getTopLeftBounds());
             } else {
                 mShrinkSide = isLeftRightSplit ? DOCKED_RIGHT : DOCKED_BOTTOM;
-                mContentBounds.set(mWinBounds2);
-                mSurfaceBounds.set(mBounds2);
+                mContentBounds.set(getBottomRightContentBounds());
+                mSurfaceBounds.set(getBottomRightBounds());
             }
 
             if (mDismissingSide != DOCKED_INVALID) {
@@ -1334,12 +1359,12 @@
                     case DOCKED_TOP:
                     case DOCKED_LEFT:
                         targetLeash = leash1;
-                        mTempRect.set(mBounds1);
+                        mTempRect.set(getTopLeftBounds());
                         break;
                     case DOCKED_BOTTOM:
                     case DOCKED_RIGHT:
                         targetLeash = leash2;
-                        mTempRect.set(mBounds2);
+                        mTempRect.set(getBottomRightBounds());
                         break;
                 }
             } else if (mParallaxType == PARALLAX_ALIGN_CENTER) {
@@ -1347,12 +1372,12 @@
                     case DOCKED_TOP:
                     case DOCKED_LEFT:
                         targetLeash = leash1;
-                        mTempRect.set(mBounds1);
+                        mTempRect.set(getTopLeftBounds());
                         break;
                     case DOCKED_BOTTOM:
                     case DOCKED_RIGHT:
                         targetLeash = leash2;
-                        mTempRect.set(mBounds2);
+                        mTempRect.set(getBottomRightBounds());
                         break;
                 }
             }
@@ -1530,7 +1555,7 @@
         private int getTargetYOffset() {
             final int desireOffset = Math.abs(mEndImeTop - mStartImeTop);
             // Make sure to keep at least 30% visible for the top split.
-            final int maxOffset = (int) (mBounds1.height() * ADJUSTED_SPLIT_FRACTION_MAX);
+            final int maxOffset = (int) (getTopLeftBounds().height() * ADJUSTED_SPLIT_FRACTION_MAX);
             return -Math.min(desireOffset, maxOffset);
         }
 
@@ -1580,11 +1605,11 @@
                     t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
                 }
 
-                getRefBounds1(mTempRect);
+                copyTopLeftRefBounds(mTempRect);
                 mTempRect.offset(0, mYOffsetForIme);
                 t.setPosition(leash1, mTempRect.left, mTempRect.top);
 
-                getRefBounds2(mTempRect);
+                copyBottomRightRefBounds(mTempRect);
                 mTempRect.offset(0, mYOffsetForIme);
                 t.setPosition(leash2, mTempRect.left, mTempRect.top);
                 adjusted = true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 6fc6eb7..a0bdd9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -1668,6 +1668,13 @@
                     transition, wct, task.displayId
                 )
             }
+        } else if (taskRepository.isActiveTask(task.taskId)) {
+            // If a freeform task receives a request for a fullscreen launch, apply the same
+            // changes we do for similar transitions. The task not having WINDOWING_MODE_UNDEFINED
+            // set when needed can interfere with future split / multi-instance transitions.
+            return WindowContainerTransaction().also { wct ->
+                addMoveToFullscreenChanges(wct, task)
+            }
         }
         return null
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index 319bfac..e4f8333 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -173,6 +173,10 @@
         return mKeyguardShowing;
     }
 
+    public boolean isKeyguardAnimating() {
+        return !mStartedTransitions.isEmpty();
+    }
+
     @Override
     public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
         mDreamToken = taskInfo.getActivityType() == ACTIVITY_TYPE_DREAM ? taskInfo.token : null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index f07ae44..45ecfa9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1709,8 +1709,8 @@
     }
 
     void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
-        outTopOrLeftBounds.set(mSplitLayout.getBounds1());
-        outBottomOrRightBounds.set(mSplitLayout.getBounds2());
+        outTopOrLeftBounds.set(mSplitLayout.getTopLeftBounds());
+        outBottomOrRightBounds.set(mSplitLayout.getBottomRightBounds());
     }
 
     private void runForActiveStages(Consumer<StageTaskListener> consumer) {
@@ -1857,8 +1857,11 @@
             return;
         }
         mRecentTasks.ifPresent(recentTasks -> {
-            Rect topLeftBounds = mSplitLayout.getBounds1();
-            Rect bottomRightBounds = mSplitLayout.getBounds2();
+            Rect topLeftBounds = new Rect();
+            mSplitLayout.copyTopLeftBounds(topLeftBounds);
+            Rect bottomRightBounds = new Rect();
+            mSplitLayout.copyBottomRightBounds(bottomRightBounds);
+
             int sideStageTopTaskId;
             int mainStageTopTaskId;
             if (enableFlexibleSplit()) {
@@ -2392,7 +2395,7 @@
         boolean updated = layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo,
                 bottomRightStage.mRootTaskInfo);
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateWindowBounds: topLeftStage=%s bottomRightStage=%s",
-                layout.getBounds1(), layout.getBounds2());
+                layout.getTopLeftBounds(), layout.getBottomRightBounds());
         return updated;
     }
 
@@ -2420,7 +2423,7 @@
                 applyResizingOffset);
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN,
                 "updateSurfaceBounds: topLeftStage=%s bottomRightStage=%s",
-                layout.getBounds1(), layout.getBounds2());
+                layout.getTopLeftBounds(), layout.getBottomRightBounds());
     }
 
     @Override
@@ -2541,12 +2544,12 @@
 
     private Rect getSideStageBounds() {
         return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
-                ? mSplitLayout.getBounds1() : mSplitLayout.getBounds2();
+                ? mSplitLayout.getTopLeftBounds() : mSplitLayout.getBottomRightBounds();
     }
 
     private Rect getMainStageBounds() {
         return mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT
-                ? mSplitLayout.getBounds2() : mSplitLayout.getBounds1();
+                ? mSplitLayout.getBottomRightBounds() : mSplitLayout.getTopLeftBounds();
     }
 
     /**
@@ -2559,11 +2562,11 @@
             // Split Layout doesn't actually keep track of the bounds based on the stage,
             // it only knows that bounds1 is leftTop position and bounds2 is bottomRight position
             // We'll then assume this method is to get bounds of bottomRight stage
-            mSplitLayout.getBounds2(rect);
+            mSplitLayout.copyBottomRightBounds(rect);
         }  else if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
-            mSplitLayout.getBounds1(rect);
+            mSplitLayout.copyTopLeftBounds(rect);
         } else {
-            mSplitLayout.getBounds2(rect);
+            mSplitLayout.copyBottomRightBounds(rect);
         }
     }
 
@@ -2577,12 +2580,12 @@
             // Split Layout doesn't actually keep track of the bounds based on the stage,
             // it only knows that bounds1 is leftTop position and bounds2 is bottomRight position
             // We'll then assume this method is to get bounds of topLeft stage
-            mSplitLayout.getBounds1(rect);
+            mSplitLayout.copyTopLeftBounds(rect);
         } else {
             if (mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT) {
-                mSplitLayout.getBounds2(rect);
+                mSplitLayout.copyBottomRightBounds(rect);
             } else {
-                mSplitLayout.getBounds1(rect);
+                mSplitLayout.copyTopLeftBounds(rect);
             }
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 17483dd..92d1f9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -370,7 +370,8 @@
         if (mRecentsHandler != null) {
             if (mSplitHandler.isSplitScreenVisible()) {
                 return this::setRecentsTransitionDuringSplit;
-            } else if (mKeyguardHandler.isKeyguardShowing()) {
+            } else if (mKeyguardHandler.isKeyguardShowing()
+                    && !mKeyguardHandler.isKeyguardAnimating()) {
                 return this::setRecentsTransitionDuringKeyguard;
             } else if (mDesktopTasksController != null
                     // Check on the default display. Recents/gesture nav is only available there
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
index fd4d568..8cdbe26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
@@ -117,6 +117,11 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Mixed transition for Recents during"
                 + " Keyguard #%d", info.getDebugId());
 
+        if (!mKeyguardHandler.isKeyguardShowing() || mKeyguardHandler.isKeyguardAnimating()) {
+            ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Cancel mixed transition because "
+                    + "keyguard state was changed #%d", info.getDebugId());
+            return false;
+        }
         if (mInfo == null) {
             mInfo = info;
             mFinishT = finishTransaction;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index 62be2c7..456f2c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -664,6 +664,8 @@
         }
 
         private fun bindMoreActionsPill(style: MenuStyle) {
+            moreActionsPill.background.setTint(style.backgroundColor)
+
             arrayOf(
                 screenshotBtn to SHOULD_SHOW_SCREENSHOT_BUTTON,
                 newWindowBtn to shouldShowNewWindowButton,
@@ -674,7 +676,6 @@
                 val shouldShow = it.second
                 button.apply {
                     isGone = !shouldShow
-                    background.setTint(style.backgroundColor)
                     setTextColor(style.textColor)
                     compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
index 4bb1e7b..11a7cf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
@@ -70,6 +70,7 @@
 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
 import com.android.wm.shell.windowdecor.common.OPACITY_12
 import com.android.wm.shell.windowdecor.common.OPACITY_40
+import com.android.wm.shell.windowdecor.common.OPACITY_60
 import com.android.wm.shell.windowdecor.common.withAlpha
 import java.util.function.Supplier
 
@@ -310,8 +311,6 @@
             .desktop_mode_maximize_menu_immersive_button_fill_padding)
         private val maximizeFillPaddingDefault = context.resources.getDimensionPixelSize(R.dimen
             .desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding)
-        private val maximizeFillPaddingBottom = context.resources.getDimensionPixelSize(R.dimen
-            .desktop_mode_maximize_menu_snap_and_maximize_buttons_fill_padding_bottom)
         private val maximizeRestoreFillPaddingVertical = context.resources.getDimensionPixelSize(
             R.dimen.desktop_mode_maximize_menu_restore_button_fill_vertical_padding)
         private val maximizeRestoreFillPaddingHorizontal = context.resources.getDimensionPixelSize(
@@ -320,7 +319,7 @@
             maximizeFillPaddingDefault,
             maximizeFillPaddingDefault,
             maximizeFillPaddingDefault,
-            maximizeFillPaddingBottom
+            maximizeFillPaddingDefault
         )
         private val maximizeRestoreFillPaddingRect = Rect(
             maximizeRestoreFillPaddingHorizontal,
@@ -684,7 +683,7 @@
                     inactiveSnapSideColor = colorScheme.outlineVariant.toArgb(),
                     semiActiveSnapSideColor = colorScheme.primary.toArgb().withAlpha(OPACITY_40),
                     activeSnapSideColor = colorScheme.primary.toArgb(),
-                    inactiveStrokeColor = colorScheme.outlineVariant.toArgb(),
+                    inactiveStrokeColor = colorScheme.outlineVariant.toArgb().withAlpha(OPACITY_60),
                     activeStrokeColor = colorScheme.primary.toArgb(),
                     inactiveBackgroundColor = menuBackgroundColor,
                     activeBackgroundColor = colorScheme.primary.toArgb().withAlpha(OPACITY_12)
@@ -753,7 +752,8 @@
             val activeStrokeAndFill = colorScheme.primary.toArgb()
             val activeBackground = colorScheme.primary.toArgb().withAlpha(OPACITY_12)
             val activeDrawable = createMaximizeOrImmersiveButtonDrawable(
-                strokeAndFillColor = activeStrokeAndFill,
+                strokeColor = activeStrokeAndFill,
+                fillColor = activeStrokeAndFill,
                 backgroundColor = activeBackground,
                 // Add a mask with the menu background's color because the active background color is
                 // semi transparent, otherwise the transparency will reveal the stroke/fill color
@@ -770,7 +770,8 @@
                 addState(
                     StateSet.WILD_CARD,
                     createMaximizeOrImmersiveButtonDrawable(
-                        strokeAndFillColor = colorScheme.outlineVariant.toArgb(),
+                        strokeColor = colorScheme.outlineVariant.toArgb().withAlpha(OPACITY_60),
+                        fillColor = colorScheme.outlineVariant.toArgb(),
                         backgroundColor = colorScheme.surfaceContainerLow.toArgb(),
                         backgroundMask = null, // not needed because the bg color is fully opaque
                         fillPadding = fillPadding,
@@ -780,7 +781,8 @@
         }
 
         private fun createMaximizeOrImmersiveButtonDrawable(
-            @ColorInt strokeAndFillColor: Int,
+            @ColorInt strokeColor: Int,
+            @ColorInt fillColor: Int,
             @ColorInt backgroundColor: Int,
             @ColorInt backgroundMask: Int?,
             fillPadding: Rect,
@@ -794,7 +796,7 @@
                     null /* inset */,
                     null /* innerRadii */
                 )
-                paint.color = strokeAndFillColor
+                paint.color = strokeColor
                 paint.style = Paint.Style.FILL
             })
             // Second layer, a mask for the next (background) layer if needed because of
@@ -829,7 +831,7 @@
                     null /* inset */,
                     null /* innerRadii */
                 )
-                paint.color = strokeAndFillColor
+                paint.color = fillColor
                 paint.style = Paint.Style.FILL
             })
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
index f7cfbfa..c5057aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ThemeUtils.kt
@@ -52,6 +52,7 @@
 const val OPACITY_15 = 38
 const val OPACITY_40 = 102
 const val OPACITY_55 = 140
+const val OPACITY_60 = 153
 const val OPACITY_65 = 166
 
 /**
diff --git a/libs/WindowManager/Shell/tests/OWNERS b/libs/WindowManager/Shell/tests/OWNERS
index 65e50f8..19829e7 100644
--- a/libs/WindowManager/Shell/tests/OWNERS
+++ b/libs/WindowManager/Shell/tests/OWNERS
@@ -6,6 +6,7 @@
 lbill@google.com
 madym@google.com
 hwwang@google.com
+gabiyev@google.com
 chenghsiuchang@google.com
 atsjenk@google.com
 jorgegil@google.com
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index 88dc548..0cc8b0c 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -50,6 +50,7 @@
 import android.tools.flicker.config.desktopmode.Components.DESKTOP_MODE_APP
 import android.tools.flicker.config.desktopmode.Components.DESKTOP_WALLPAPER
 import android.tools.flicker.config.desktopmode.Components.NON_RESIZABLE_APP
+import android.tools.flicker.config.desktopmode.Components.SIMPLE_APP
 import android.tools.flicker.extractors.ITransitionMatcher
 import android.tools.flicker.extractors.ShellTransitionScenarioExtractor
 import android.tools.flicker.extractors.TaggedCujTransitionMatcher
@@ -444,5 +445,25 @@
                         AppWindowOnTopAtEnd(LAUNCHER),
                     ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING })
             )
+        val OPEN_UNLIMITED_APPS =
+            FlickerConfigEntry(
+                scenarioId = ScenarioId("OPEN_UNLIMITED_APPS"),
+                extractor =
+                ShellTransitionScenarioExtractor(
+                    transitionMatcher =
+                    object : ITransitionMatcher {
+                        override fun findAll(
+                            transitions: Collection<Transition>
+                        ): Collection<Transition> {
+                                return transitions.filter { it.type == TransitionType.OPEN }
+                        }
+                    }
+                ),
+                assertions =
+                        listOf(
+                            AppWindowBecomesVisible(DESKTOP_MODE_APP),
+                            AppWindowIsVisibleAlways(SIMPLE_APP)
+                        ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+            )
     }
 }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt
new file mode 100644
index 0000000..0a39846
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/OpenUnlimitedApps.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.OPEN_UNLIMITED_APPS
+import com.android.wm.shell.scenarios.OpenUnlimitedApps
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Open many apps on the device without the window limit.
+ *
+ * Assert that the desktop task limit is not triggered.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenUnlimitedApps : OpenUnlimitedApps() {
+    @ExpectedScenarios(["OPEN_UNLIMITED_APPS"])
+    @Test
+    override fun openUnlimitedApps() = super.openUnlimitedApps()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(OPEN_UNLIMITED_APPS)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
deleted file mode 100644
index 85e6a8d..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/Android.bp
+++ /dev/null
@@ -1,38 +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 {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
-    name: "WMShellFlickerTestsMediaProjection",
-    defaults: ["WMShellFlickerTestsDefault"],
-    manifest: "AndroidManifest.xml",
-    test_config_template: "AndroidTestTemplate.xml",
-    srcs: ["src/**/*.kt"],
-    static_libs: [
-        "WMShellFlickerTestsBase",
-        "WMShellScenariosMediaProjection",
-        "WMShellTestUtils",
-    ],
-    data: ["trace_config/*"],
-}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
deleted file mode 100644
index 74b0daf..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidManifest.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT 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.wm.shell.flicker">
-
-    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
-    <!-- Read and write traces from external storage -->
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-    <!-- Allow the test to write directly to /sdcard/ -->
-    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
-    <!-- Write secure settings -->
-    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <!-- Capture screen contents -->
-    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
-    <!-- Enable / Disable tracing !-->
-    <uses-permission android:name="android.permission.DUMP" />
-    <!-- Run layers trace -->
-    <uses-permission android:name="android.permission.HARDWARE_TEST"/>
-    <!-- Capture screen recording -->
-    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
-    <!-- Workaround grant runtime permission exception from b/152733071 -->
-    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
-    <uses-permission android:name="android.permission.READ_LOGS"/>
-    <!-- Force-stop test apps -->
-    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
-    <!-- Control test app's media session -->
-    <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
-    <!-- ATM.removeRootTasksWithActivityTypes() -->
-    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
-    <!-- Enable bubble notification-->
-    <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
-    <!-- Allow the test to connect to perfetto trace processor -->
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
-    <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
-
-    <!-- Allow the test to write directly to /sdcard/ and connect to trace processor -->
-    <application android:requestLegacyExternalStorage="true"
-                 android:networkSecurityConfig="@xml/network_security_config"
-                 android:largeHeap="true">
-        <uses-library android:name="android.test.runner"/>
-
-        <service android:name=".NotificationListener"
-                 android:exported="true"
-                 android:label="WMShellTestsNotificationListenerService"
-                 android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
-            <intent-filter>
-                <action android:name="android.service.notification.NotificationListenerService" />
-            </intent-filter>
-        </service>
-
-        <service android:name="com.android.wm.shell.flicker.utils.MediaProjectionService"
-            android:foregroundServiceType="mediaProjection"
-            android:label="WMShellTestsMediaProjectionService"
-            android:enabled="true">
-        </service>
-
-        <!-- (b/197936012) Remove startup provider due to test timeout issue -->
-        <provider
-            android:name="androidx.startup.InitializationProvider"
-            android:authorities="${applicationId}.androidx-startup"
-            tools:node="remove" />
-    </application>
-
-    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.wm.shell.flicker"
-                     android:label="WindowManager Shell Flicker Tests">
-    </instrumentation>
-</manifest>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
deleted file mode 100644
index 40dbbac..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/AndroidTestTemplate.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<configuration description="Runs WindowManager Shell Flicker Tests {MODULE}">
-    <option name="test-tag" value="FlickerTests"/>
-    <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
-    <option name="isolated-storage" value="false"/>
-
-    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
-        <!-- disable DeprecatedTargetSdk warning -->
-        <option name="run-command" value="setprop debug.wm.disable_deprecated_target_sdk_dialog 1"/>
-        <!-- keeps the screen on during tests -->
-        <option name="screen-always-on" value="on"/>
-        <!-- prevents the phone from restarting -->
-        <option name="force-skip-system-props" value="true"/>
-        <!-- set WM tracing verbose level to all -->
-        <option name="run-command" value="cmd window tracing level all"/>
-        <!-- set WM tracing to frame (avoid incomplete states) -->
-        <option name="run-command" value="cmd window tracing frame"/>
-        <!-- disable betterbug as it's log collection dialogues cause flakes in e2e tests -->
-        <option name="run-command" value="pm disable com.google.android.internal.betterbug"/>
-        <!-- ensure lock screen mode is swipe -->
-        <option name="run-command" value="locksettings set-disabled false"/>
-        <!-- restart launcher to activate TAPL -->
-        <option name="run-command"
-                value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher"/>
-        <!-- Increase trace size: 20mb for WM and 80mb for SF -->
-        <option name="run-command" value="cmd window tracing size 20480"/>
-        <option name="run-command" value="su root service call SurfaceFlinger 1029 i32 81920"/>
-    </target_preparer>
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="test-user-token" value="%TEST_USER%"/>
-        <option name="run-command" value="rm -rf /data/user/%TEST_USER%/files/*"/>
-        <option name="run-command" value="settings put secure show_ime_with_hard_keyboard 1"/>
-        <option name="run-command" value="settings put system show_touches 1"/>
-        <option name="run-command" value="settings put system pointer_location 1"/>
-        <option name="teardown-command"
-                value="settings delete secure show_ime_with_hard_keyboard"/>
-        <option name="teardown-command" value="settings delete system show_touches"/>
-        <option name="teardown-command" value="settings delete system pointer_location"/>
-        <option name="teardown-command"
-                value="cmd overlay enable com.android.internal.systemui.navbar.gestural"/>
-    </target_preparer>
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="cleanup-apks" value="true"/>
-        <option name="test-file-name" value="{MODULE}.apk"/>
-        <option name="test-file-name" value="FlickerTestApp.apk"/>
-    </target_preparer>
-
-    <!-- Needed for pushing the trace config file -->
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="push-file"
-                key="trace_config.textproto"
-                value="/data/misc/perfetto-traces/trace_config.textproto"
-        />
-        <!--Install the content provider automatically when we push some file in sdcard folder.-->
-        <!--Needed to avoid the installation during the test suite.-->
-        <option name="push-file" key="trace_config.textproto" value="/sdcard/sample.textproto"/>
-    </target_preparer>
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
-        <option name="package" value="{PACKAGE}"/>
-        <option name="shell-timeout" value="6600s"/>
-        <option name="test-timeout" value="6000s"/>
-        <option name="hidden-api-checks" value="false"/>
-        <option name="device-listeners" value="android.device.collectors.PerfettoListener"/>
-        <!-- PerfettoListener related arguments -->
-        <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/>
-        <option name="instrumentation-arg"
-                key="perfetto_config_file"
-                value="trace_config.textproto"
-        />
-        <option name="instrumentation-arg" key="per_run" value="true"/>
-        <option name="instrumentation-arg" key="perfetto_persist_pid_track" value="true"/>
-    </test>
-    <!-- Needed for pulling the collected trace config on to the host -->
-    <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="pull-pattern-keys" value="perfetto_file_path"/>
-        <option name="directory-keys"
-                value="/data/user/0/com.android.wm.shell.flicker/files"/>
-        <option name="collect-on-run-ended-only" value="true"/>
-        <option name="clean-up" value="true"/>
-    </metrics_collector>
-</configuration>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
deleted file mode 100644
index 4bd9ca0..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/res/xml/network_security_config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2023 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<network-security-config>
-    <domain-config cleartextTrafficPermitted="true">
-        <domain includeSubdomains="true">localhost</domain>
-    </domain-config>
-</network-security-config>
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto b/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
deleted file mode 100644
index 9f2e497..0000000
--- a/libs/WindowManager/Shell/tests/e2e/mediaprojection/flicker-service/trace_config/trace_config.textproto
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# proto-message: TraceConfig
-
-# Enable periodic flushing of the trace buffer into the output file.
-write_into_file: true
-
-# Writes the userspace buffer into the file every 1s.
-file_write_period_ms: 2500
-
-# See b/126487238 - we need to guarantee ordering of events.
-flush_period_ms: 30000
-
-# The trace buffers needs to be big enough to hold |file_write_period_ms| of
-# trace data. The trace buffer sizing depends on the number of trace categories
-# enabled and the device activity.
-
-# RSS events
-buffers: {
-  size_kb: 63488
-  fill_policy: RING_BUFFER
-}
-
-data_sources {
-  config {
-    name: "linux.process_stats"
-    target_buffer: 0
-    # polled per-process memory counters and process/thread names.
-    # If you don't want the polled counters, remove the "process_stats_config"
-    # section, but keep the data source itself as it still provides on-demand
-    # thread/process naming for ftrace data below.
-    process_stats_config {
-      scan_all_processes_on_start: true
-    }
-  }
-}
-
-data_sources: {
-  config {
-    name: "linux.ftrace"
-    ftrace_config {
-      ftrace_events: "ftrace/print"
-      ftrace_events: "task/task_newtask"
-      ftrace_events: "task/task_rename"
-      atrace_categories: "ss"
-      atrace_categories: "wm"
-      atrace_categories: "am"
-      atrace_categories: "aidl"
-      atrace_categories: "input"
-      atrace_categories: "binder_driver"
-      atrace_categories: "sched_process_exit"
-      atrace_apps: "com.android.server.wm.flicker.testapp"
-      atrace_apps: "com.android.systemui"
-      atrace_apps: "com.android.wm.shell.flicker.service"
-      atrace_apps: "com.google.android.apps.nexuslauncher"
-    }
-  }
-}
-
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt
new file mode 100644
index 0000000..2b9772d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionFromSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionFromSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionFromSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionFromSplitScreenTest() : StartAppMediaProjectionFromSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt
new file mode 100644
index 0000000..e92297b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionInSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionInSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionInSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionInSplitScreenTest() : StartAppMediaProjectionInSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt
new file mode 100644
index 0000000..3f810759
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjection
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjection]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionTest() : StartAppMediaProjection()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt
new file mode 100644
index 0000000..1975cc7
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartAppMediaProjectionWithExtraIntentTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartAppMediaProjectionWithExtraIntent
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartAppMediaProjectionWithExtraIntent]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartAppMediaProjectionWithExtraIntentTest : StartAppMediaProjectionWithExtraIntent()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt
new file mode 100644
index 0000000..943033c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionFromSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjectionFromSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjectionFromSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionFromSplitScreenTest() : StartRecentAppMediaProjectionFromSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt
new file mode 100644
index 0000000..6facfd5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionInSplitScreenTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjectionInSplitScreen
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjectionInSplitScreen]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionInSplitScreenTest() : StartRecentAppMediaProjectionInSplitScreen()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt
new file mode 100644
index 0000000..bab0905
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/functional/StartRecentAppMediaProjectionTest.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.functional
+
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.StartRecentAppMediaProjection
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/* Functional test for [StartRecentAppMediaProjection]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class StartRecentAppMediaProjectionTest() : StartRecentAppMediaProjection()
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt
new file mode 100644
index 0000000..fe2c578
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session.
+ *
+ * This is for testing that the requested app is opened as expected upon selecting it from the app
+ * selector, so capture can proceed as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjection {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(initialRotation.value)
+        testApp.launchViaIntent(wmHelper)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt
new file mode 100644
index 0000000..3beece8
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionFromSplitScreen.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session, while the HOST app is in
+ * split screen
+ *
+ * This is for testing that the requested app is opened as expected upon selecting it from the app
+ * selector, so capture can proceed as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionFromSplitScreen {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val simpleApp = SimpleAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.workspace.switchToOverview().dismissAllTasks()
+
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(initialRotation.value)
+        SplitScreenUtils.enterSplit(wmHelper, tapl, device, simpleApp, testApp, initialRotation)
+        SplitScreenUtils.waitForSplitComplete(wmHelper, simpleApp, testApp)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt
new file mode 100644
index 0000000..d3186ae
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionInSplitScreen.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session, while the TARGET app is in
+ * split screen (next to the host app)
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionInSplitScreen {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.workspace.switchToOverview().dismissAllTasks()
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(initialRotation.value)
+        SplitScreenUtils.enterSplit(wmHelper, tapl, device, targetApp, testApp, initialRotation)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        testApp.startSingleAppMediaProjection(wmHelper, targetApp)
+
+        wmHelper
+            .StateSyncBuilder()
+            .withAppTransitionIdle()
+            .withWindowSurfaceAppeared(targetApp)
+            .withWindowSurfaceAppeared(testApp)
+            .waitForAndVerify()
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+        targetApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt
new file mode 100644
index 0000000..0b2a1ca
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithExtraIntent.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session but launches an intent to
+ * return to the home screen, before the intent for opening the requested app to capture.
+ *
+ * This is for testing that even if a different intent interrupts the process the launching the
+ * requested capture target, the MediaProjection process isn't interrupted and the device is still
+ * interactive.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartAppMediaProjectionWithExtraIntent {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.setEnableRotation(true)
+        testApp.launchViaIntent(wmHelper)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        testApp.startSingleAppMediaProjectionWithExtraIntent(wmHelper, targetApp)
+
+        // Check we can still interact with device after
+        tapl.workspace.switchToAllApps().getAppIcon(targetApp.appName).launch(targetApp.packageName)
+
+        wmHelper
+            .StateSyncBuilder()
+            .withAppTransitionIdle()
+            .withWindowSurfaceAppeared(targetApp)
+            .waitForAndVerify()
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt
new file mode 100644
index 0000000..30e0e4a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjection.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents.
+ *
+ * This is for testing that the app is started from recents and capture proceeds as expected.
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjection {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(initialRotation.value)
+        targetApp.open()
+        testApp.launchViaIntent(wmHelper)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt
new file mode 100644
index 0000000..f1dcf1f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionFromSplitScreen.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents while the HOST
+ * app is in split screen.
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjectionFromSplitScreen {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val simpleApp = SimpleAppHelper(instrumentation)
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.workspace.switchToOverview().dismissAllTasks()
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(initialRotation.value)
+        targetApp.open()
+        SplitScreenUtils.enterSplit(wmHelper, tapl, device, simpleApp, testApp, initialRotation)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        // The app we want to open for PSS will be the second item in the carousel,
+        // because the first will be the app open in split screen alongside the MediaProjection app
+        testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp, recentTasksIndex = 1)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt
new file mode 100644
index 0000000..0a6992f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/mediaprojection/scenarios/src/com/android/wm/shell/scenarios/StartRecentAppMediaProjectionInSplitScreen.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.scenarios
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.device.apphelpers.CalculatorAppHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.StartMediaProjectionAppHelper
+import com.android.wm.shell.Utils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+/**
+ * Test scenario which requests an a single-app MediaProjection session from recents while the
+ * TARGET app is in split screen (with host app).
+ *
+ * This is for testing that the split pair isn't broken, and capture still proceeds as expected
+ */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class StartRecentAppMediaProjectionInSplitScreen {
+
+    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    val tapl = LauncherInstrumentation()
+    val wmHelper = WindowManagerStateHelper(instrumentation)
+    val device = UiDevice.getInstance(instrumentation)
+
+    private val initialRotation = Rotation.ROTATION_0
+    private val targetApp = CalculatorAppHelper(instrumentation)
+    private val testApp = StartMediaProjectionAppHelper(instrumentation)
+
+    @Rule
+    @JvmField
+    val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, initialRotation)
+
+    @Before
+    fun setup() {
+        tapl.workspace.switchToOverview().dismissAllTasks()
+        tapl.setEnableRotation(true)
+        tapl.setExpectedRotation(initialRotation.value)
+        SplitScreenUtils.enterSplit(wmHelper, tapl, device, targetApp, testApp, initialRotation)
+    }
+
+    @Test
+    open fun startMediaProjection() {
+        testApp.startSingleAppMediaProjectionFromRecents(wmHelper, targetApp)
+
+        wmHelper
+            .StateSyncBuilder()
+            .withAppTransitionIdle()
+            .withWindowSurfaceAppeared(targetApp)
+            .withWindowSurfaceAppeared(testApp)
+            .waitForAndVerify()
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+        targetApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
index f9706969..8c2bdad 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/MediaProjectionUtils.kt
@@ -17,7 +17,11 @@
 package com.android.wm.shell.flicker.utils
 
 object MediaProjectionUtils {
-    const val REQUEST_CODE: Int = 99
+    // Request code for the normal media projection request
+    const val REQUEST_CODE_NORMAL: Int = 11
+    // Request code for the media projection request which will include an extra intent to open
+    // home screen before starting requested app
+    const val REQUEST_CODE_EXTRA_INTENT: Int = 12
     const val MSG_START_FOREGROUND_DONE: Int = 1
     const val MSG_SERVICE_DESTROYED: Int = 2
     const val EXTRA_MESSENGER: String = "messenger"
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
index 6fa3788..ce640b5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java
@@ -47,6 +47,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.bubbles.BubbleData.TimeSource;
 import com.android.wm.shell.common.ShellExecutor;
@@ -102,6 +103,7 @@
 
     private BubbleData mBubbleData;
     private TestableBubblePositioner mPositioner;
+    private UiEventLoggerFake mUiEventLogger;
 
     @Mock
     private TimeSource mTimeSource;
@@ -112,8 +114,6 @@
     @Mock
     private PendingIntent mDeleteIntent;
     @Mock
-    private BubbleLogger mBubbleLogger;
-    @Mock
     private BubbleEducationController mEducationController;
     @Mock
     private ShellExecutor mMainExecutor;
@@ -196,10 +196,12 @@
                 mock(Icon.class),
                 mMainExecutor, mBgExecutor);
 
+        mUiEventLogger = new UiEventLoggerFake();
+
         mPositioner = new TestableBubblePositioner(mContext,
                 mContext.getSystemService(WindowManager.class));
-        mBubbleData = new BubbleData(getContext(), mBubbleLogger, mPositioner, mEducationController,
-                mMainExecutor, mBgExecutor);
+        mBubbleData = new BubbleData(getContext(), new BubbleLogger(mUiEventLogger), mPositioner,
+                mEducationController, mMainExecutor, mBgExecutor);
 
         // Used by BubbleData to set lastAccessedTime
         when(mTimeSource.currentTimeMillis()).thenReturn(1000L);
@@ -297,6 +299,82 @@
     }
 
     @Test
+    public void testRemoveBubbleFromBubbleBar_notifCancelled_logEvent() {
+        mPositioner.setShowingInBubbleBar(true);
+
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        mBubbleData.setListener(mListener);
+
+        mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NOTIF_CANCEL);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_CANCELED.getId());
+    }
+
+    @Test
+    public void testRemoveBubbleFromBubbleBar_taskFinished_logEvent() {
+        mPositioner.setShowingInBubbleBar(true);
+
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        mBubbleData.setListener(mListener);
+
+        mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_TASK_FINISHED);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                BubbleLogger.Event.BUBBLE_BAR_BUBBLE_ACTIVITY_FINISH.getId());
+    }
+
+    @Test
+    public void testRemoveBubbleFromBubbleBar_notifBlocked_logEvent() {
+        mPositioner.setShowingInBubbleBar(true);
+
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        mBubbleData.setListener(mListener);
+
+        mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_BLOCKED);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED.getId());
+    }
+
+    @Test
+    public void testRemoveBubbleFromBubbleBar_noLongerBubble_logEvent() {
+        mPositioner.setShowingInBubbleBar(true);
+
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        mBubbleData.setListener(mListener);
+
+        mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_NO_LONGER_BUBBLE);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                BubbleLogger.Event.BUBBLE_BAR_BUBBLE_REMOVED_BLOCKED.getId());
+    }
+
+    @Test
+    public void testRemoveBubbleFromBubbleBar_addToOverflow_logEvent() {
+        mPositioner.setShowingInBubbleBar(true);
+
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        mBubbleData.setListener(mListener);
+
+        mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_AGED);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(1);
+        assertThat(mUiEventLogger.eventId(0)).isEqualTo(
+                BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_ADD_AGED.getId());
+    }
+
+    @Test
+    public void testRemoveBubble_notifCancelled_noLog() {
+        mPositioner.setShowingInBubbleBar(false);
+
+        sendUpdatedEntryAtTime(mEntryA1, 1000);
+        mBubbleData.setListener(mListener);
+
+        mBubbleData.dismissBubbleWithKey(mEntryA1.getKey(), Bubbles.DISMISS_BLOCKED);
+        assertThat(mUiEventLogger.numLogs()).isEqualTo(0);
+    }
+
+    @Test
     public void ifSuppress_hideFlyout() {
         // Setup
         mBubbleData.setListener(mListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 5f58265..289fd2d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -36,6 +36,8 @@
 import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
 import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Rational;
@@ -46,6 +48,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.wm.shell.Flags;
 import com.android.wm.shell.MockSurfaceControlHelper;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -67,6 +70,8 @@
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
@@ -81,7 +86,13 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
+@DisableFlags(Flags.FLAG_ENABLE_PIP2)
 public class PipTaskOrganizerTest extends ShellTestCase {
+    @ClassRule
+    public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
+
     private PipTaskOrganizer mPipTaskOrganizer;
 
     @Mock private DisplayController mMockDisplayController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 9600351..b123f4d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -42,11 +42,14 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.wm.shell.Flags;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
@@ -74,6 +77,8 @@
 import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -88,7 +93,11 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
+@DisableFlags(Flags.FLAG_ENABLE_PIP2)
 public class PipControllerTest extends ShellTestCase {
+    @ClassRule public static final SetFlagsRule.ClassRule mClassRule = new SetFlagsRule.ClassRule();
+    @Rule public final SetFlagsRule mSetFlagsRule = mClassRule.createSetFlagsRule();
+
     private PipController mPipController;
     private ShellInit mShellInit;
     private ShellController mShellController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index 66dcef6..d13a888 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -53,8 +53,8 @@
         doReturn(dividerBounds).when(out).getDividerBounds();
         doReturn(dividerBounds).when(out).getRefDividerBounds();
         doReturn(leash).when(out).getDividerLeash();
-        doReturn(bounds1).when(out).getBounds1();
-        doReturn(bounds2).when(out).getBounds2();
+        doReturn(bounds1).when(out).getTopLeftBounds();
+        doReturn(bounds2).when(out).getBottomRightBounds();
         return out;
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 2d102fb..4f6f3c6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -141,8 +141,8 @@
                 Optional.empty()));
         mDividerLeash = new SurfaceControl.Builder().setName("fakeDivider").build();
 
-        when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
-        when(mSplitLayout.getBounds2()).thenReturn(mBounds2);
+        when(mSplitLayout.getTopLeftBounds()).thenReturn(mBounds1);
+        when(mSplitLayout.getBottomRightBounds()).thenReturn(mBounds2);
         when(mSplitLayout.getRootBounds()).thenReturn(mRootBounds);
         when(mSplitLayout.isLeftRightSplit()).thenReturn(false);
         when(mSplitLayout.applyTaskChanges(any(), any(), any())).thenReturn(true);
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index fb58a69..b72e066 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -84,6 +84,7 @@
     // this value is only valid after the GPU has been initialized and there is a valid graphics
     // context or if you are using the HWUI_NULL_GPU
     int maxTextureSize() const;
+    bool hasMaxTextureSize() const { return mMaxTextureSize > 0; }
     sk_sp<SkColorSpace> getWideColorSpace() const { return mWideColorSpace; }
     SkColorType getWideColorType() {
         static std::once_flag kFlag;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 2c23864..4801bd1 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -186,7 +186,7 @@
     // If we are not a layer OR we cannot be rendered (eg, view was detached)
     // we need to destroy any Layers we may have had previously
     if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable()) ||
-        CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) ||
+        CC_UNLIKELY(properties().getWidth() <= 0) || CC_UNLIKELY(properties().getHeight() <= 0) ||
         CC_UNLIKELY(!properties().fitsOnLayer())) {
         if (CC_UNLIKELY(hasLayer())) {
             this->setLayerSurface(nullptr);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index b1ad8b2..4dc5700 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -545,7 +545,8 @@
     bool fitsOnLayer() const {
         const DeviceInfo* deviceInfo = DeviceInfo::get();
         return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize() &&
-               mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+               mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize() &&
+               mPrimitiveFields.mWidth > 0 && mPrimitiveFields.mHeight > 0;
     }
 
     bool promotedToLayer() const {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8ec0430..b36b8be 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -418,6 +418,11 @@
                                 RenderNode* target) {
     mRenderThread.removeFrameCallback(this);
 
+    // Make sure we have a valid device info
+    if (!DeviceInfo::get()->hasMaxTextureSize()) {
+        (void)mRenderThread.requireGrContext();
+    }
+
     // If the previous frame was dropped we don't need to hold onto it, so
     // just keep using the previous frame's structure instead
     const auto reason = wasSkipped(mCurrentFrameInfo);
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
index 3e8e057..6ec042c 100644
--- a/libs/hwui/tests/unit/RenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
@@ -40,7 +40,11 @@
     props.setLeftTopRightBottom(0, 0, maxTextureSize + 1, maxTextureSize + 1);
     ASSERT_FALSE(props.fitsOnLayer());
 
-    // Too small, but still 'fits'. Not fitting is an error case, so don't report empty as such.
+    // Too small, we can't create a layer for a 0 width or height
     props.setLeftTopRightBottom(0, 0, 100, 0);
-    ASSERT_TRUE(props.fitsOnLayer());
+    ASSERT_FALSE(props.fitsOnLayer());
+
+    // Can't create a negative-sized layer
+    props.setLeftTopRightBottom(0, 0, -100, 300);
+    ASSERT_FALSE(props.fitsOnLayer());
 }
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
index aaedf21..1c85c7b 100644
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ b/media/java/android/media/quality/IMediaQualityManager.aidl
@@ -21,6 +21,7 @@
 import android.media.quality.IPictureProfileCallback;
 import android.media.quality.ISoundProfileCallback;
 import android.media.quality.ParamCapability;
+import android.media.quality.PictureProfileHandle;
 import android.media.quality.PictureProfile;
 import android.media.quality.SoundProfile;
 
@@ -38,6 +39,7 @@
     List<String> getPictureProfilePackageNames();
     List<String> getPictureProfileAllowList();
     void setPictureProfileAllowList(in List<String> packages);
+    PictureProfileHandle getPictureProfileHandle(in String id);
 
     SoundProfile createSoundProfile(in SoundProfile pp);
     void updateSoundProfile(in String id, in SoundProfile pp);
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 28fe9b6..43e884a 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -271,6 +271,17 @@
         }
     }
 
+    /**
+     * Gets picture profile handle by profile ID.
+     * @hide
+     */
+    public PictureProfileHandle getPictureProfileHandle(String id) {
+        try {
+            return mService.getPictureProfileHandle(id);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
      * Creates a picture profile and store it in the system.
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index 898a8bf..4de7123 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -63,7 +63,7 @@
             FRONTEND_STATUS_TYPE_DVBT_CELL_IDS, FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO,
             FRONTEND_STATUS_TYPE_IPTV_CONTENT_URL, FRONTEND_STATUS_TYPE_IPTV_PACKETS_LOST,
             FRONTEND_STATUS_TYPE_IPTV_PACKETS_RECEIVED, FRONTEND_STATUS_TYPE_IPTV_WORST_JITTER_MS,
-            FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS, FRONTEND_STATUS_TYPE_STANDARD_EXT})
+            FRONTEND_STATUS_TYPE_IPTV_AVERAGE_JITTER_MS, FRONTEND_STATUS_TYPE_STANDARD_EXTENSION})
     @Retention(RetentionPolicy.SOURCE)
     public @interface FrontendStatusType {}
 
@@ -317,7 +317,7 @@
      * Standard extension.
      */
     @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
-    public static final int FRONTEND_STATUS_TYPE_STANDARD_EXT =
+    public static final int FRONTEND_STATUS_TYPE_STANDARD_EXTENSION =
             android.hardware.tv.tuner.FrontendStatusType.STANDARD_EXT;
 
     /** @hide */
@@ -567,7 +567,7 @@
     private Long mIptvPacketsReceived;
     private Integer mIptvWorstJitterMs;
     private Integer mIptvAverageJitterMs;
-    private StandardExt mStandardExt;
+    private StandardExtension mStandardExtension;
 
     // Constructed and fields set by JNI code.
     private FrontendStatus() {
@@ -1298,12 +1298,12 @@
      */
     @NonNull
     @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
-    public StandardExt getStandardExt() {
+    public StandardExtension getStandardExtension() {
         TunerVersionChecker.checkHigherOrEqualVersionTo(
-                TunerVersionChecker.TUNER_VERSION_4_0, "StandardExt status");
-        if (mStandardExt == null) {
-            throw new IllegalStateException("StandardExt status is empty");
+                TunerVersionChecker.TUNER_VERSION_4_0, "StandardExtension status");
+        if (mStandardExtension == null) {
+            throw new IllegalStateException("StandardExtension status is empty");
         }
-        return mStandardExt;
+        return mStandardExtension;
     }
 }
diff --git a/media/java/android/media/tv/tuner/frontend/StandardExt.java b/media/java/android/media/tv/tuner/frontend/StandardExtension.java
similarity index 74%
rename from media/java/android/media/tv/tuner/frontend/StandardExt.java
rename to media/java/android/media/tv/tuner/frontend/StandardExtension.java
index 4907272..8bff3dd 100644
--- a/media/java/android/media/tv/tuner/frontend/StandardExt.java
+++ b/media/java/android/media/tv/tuner/frontend/StandardExtension.java
@@ -29,16 +29,16 @@
  */
 @SystemApi
 @FlaggedApi(Flags.FLAG_TUNER_W_APIS)
-public final class StandardExt {
-    private final int mDvbsStandardExt;
-    private final int mDvbtStandardExt;
+public final class StandardExtension {
+    private final int mDvbsStandardExtension;
+    private final int mDvbtStandardExtension;
 
     /**
      * Private constructor called by JNI only.
      */
-    private StandardExt(int dvbsStandardExt, int dvbtStandardExt) {
-        mDvbsStandardExt = dvbsStandardExt;
-        mDvbtStandardExt = dvbtStandardExt;
+    private StandardExtension(int dvbsStandardExtension, int dvbtStandardExtension) {
+        mDvbsStandardExtension = dvbsStandardExtension;
+        mDvbtStandardExtension = dvbtStandardExtension;
     }
 
     /**
@@ -50,11 +50,11 @@
      * @see android.media.tv.tuner.frontend.DvbsFrontendSettings
      */
     @DvbsFrontendSettings.Standard
-    public int getDvbsStandardExt() {
-        if (mDvbsStandardExt == FrontendDvbsStandard.UNDEFINED) {
+    public int getDvbsStandardExtension() {
+        if (mDvbsStandardExtension == FrontendDvbsStandard.UNDEFINED) {
             throw new IllegalStateException("No DVB-S standard transition");
         }
-        return mDvbsStandardExt;
+        return mDvbsStandardExtension;
     }
 
     /**
@@ -66,10 +66,10 @@
      * @see android.media.tv.tuner.frontend.DvbtFrontendSettings
      */
     @DvbtFrontendSettings.Standard
-    public int getDvbtStandardExt() {
-        if (mDvbtStandardExt == FrontendDvbtStandard.UNDEFINED) {
+    public int getDvbtStandardExtension() {
+        if (mDvbtStandardExtension == FrontendDvbtStandard.UNDEFINED) {
             throw new IllegalStateException("No DVB-T standard transition");
         }
-        return mDvbtStandardExt;
+        return mDvbtStandardExtension;
     }
 }
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 80ca4f2..2fe069a 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -2940,10 +2940,10 @@
                 break;
             }
             case FrontendStatus::Tag::standardExt: {
-                jfieldID field = env->GetFieldID(clazz, "mStandardExt",
-                        "Landroid/media/tv/tuner/frontend/StandardExt;");
+                jfieldID field = env->GetFieldID(clazz, "mStandardExtension",
+                        "Landroid/media/tv/tuner/frontend/StandardExtension;");
                 ScopedLocalRef standardExtClazz(env,
-                        env->FindClass("android/media/tv/tuner/frontend/StandardExt"));
+                        env->FindClass("android/media/tv/tuner/frontend/StandardExtension"));
                 jmethodID initStandardExt = env->GetMethodID(standardExtClazz.get(), "<init>",
                         "(II)V");
 
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 2d1fbf9..6b41ddd 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -363,6 +363,7 @@
     APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream
     APerformanceHint_notifyWorkloadIncrease; # introduced=36
     APerformanceHint_notifyWorkloadReset; # introduced=36
+    APerformanceHint_borrowSessionFromJava; # introduced=36
     AWorkDuration_create; # introduced=VanillaIceCream
     AWorkDuration_release; # introduced=VanillaIceCream
     AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream
@@ -383,6 +384,8 @@
     APerformanceHint_setUseFMQForTesting;
     APerformanceHint_getRateLimiterPropertiesForTesting;
     APerformanceHint_setUseNewLoadHintBehaviorForTesting;
+    APerformanceHint_closeSessionFromJava;
+    APerformanceHint_createSessionFromJava;
     extern "C++" {
         ASurfaceControl_registerSurfaceStatsListener*;
         ASurfaceControl_unregisterSurfaceStatsListener*;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index e2fa94d..bc1945e 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -36,6 +36,7 @@
 #include <cutils/trace.h>
 #include <fmq/AidlMessageQueue.h>
 #include <inttypes.h>
+#include <jni_wrappers.h>
 #include <performance_hint_private.h>
 #include <utils/SystemClock.h>
 
@@ -137,10 +138,14 @@
 
     APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
                                            int64_t initialTargetWorkDurationNanos,
-                                           hal::SessionTag tag = hal::SessionTag::APP);
+                                           hal::SessionTag tag = hal::SessionTag::APP,
+                                           bool isJava = false);
+    APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
+
     int64_t getPreferredRateNanos() const;
     FMQWrapper& getFMQWrapper();
     bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
+    void initJava(JNIEnv* _Nonnull env);
 
 private:
     // Necessary to create an empty binder object
@@ -161,13 +166,16 @@
     FMQWrapper mFMQWrapper;
     double mHintBudget = kMaxLoadHintsPerInterval;
     int64_t mLastBudgetReplenish = 0;
+    bool mJavaInitialized = false;
+    jclass mJavaSessionClazz;
+    jfieldID mJavaSessionNativePtr;
 };
 
 struct APerformanceHintSession {
 public:
     APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
                             std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
-                            int64_t targetDurationNanos,
+                            int64_t targetDurationNanos, bool isJava,
                             std::optional<hal::SessionConfig> sessionConfig);
     APerformanceHintSession() = delete;
     ~APerformanceHintSession();
@@ -181,6 +189,7 @@
     int getThreadIds(int32_t* const threadIds, size_t* size);
     int setPreferPowerEfficiency(bool enabled);
     int reportActualWorkDuration(AWorkDuration* workDuration);
+    bool isJava();
 
 private:
     friend struct APerformanceHintManager;
@@ -203,6 +212,8 @@
     std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
     // Cached samples
     std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
+    // Is this session backing an SDK wrapper object
+    const bool mIsJava;
     std::string mSessionName;
     static int64_t sIDCounter GUARDED_BY(sHintMutex);
     // The most recent set of thread IDs
@@ -299,7 +310,7 @@
 
 APerformanceHintSession* APerformanceHintManager::createSession(
         const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
-        hal::SessionTag tag) {
+        hal::SessionTag tag, bool isJava) {
     std::vector<int32_t> tids(threadIds, threadIds + size);
     std::shared_ptr<IHintSession> session;
     ndk::ScopedAStatus ret;
@@ -312,7 +323,7 @@
         return nullptr;
     }
     auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
-                                           initialTargetWorkDurationNanos,
+                                           initialTargetWorkDurationNanos, isJava,
                                            sessionConfig.id == -1
                                                    ? std::nullopt
                                                    : std::make_optional<hal::SessionConfig>(
@@ -324,6 +335,18 @@
     return out;
 }
 
+APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
+                                                                     jobject sessionObj) {
+    initJava(env);
+    LOG_ALWAYS_FATAL_IF(!env->IsInstanceOf(sessionObj, mJavaSessionClazz),
+                        "Wrong java type passed to APerformanceHint_getSessionFromJava");
+    APerformanceHintSession* out = reinterpret_cast<APerformanceHintSession*>(
+            env->GetLongField(sessionObj, mJavaSessionNativePtr));
+    LOG_ALWAYS_FATAL_IF(out == nullptr, "Java-wrapped native hint session is nullptr");
+    LOG_ALWAYS_FATAL_IF(!out->isJava(), "Unmanaged native hint session returned from Java SDK");
+    return out;
+}
+
 int64_t APerformanceHintManager::getPreferredRateNanos() const {
     return mPreferredRateNanos;
 }
@@ -332,13 +355,23 @@
     return mFMQWrapper;
 }
 
+void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
+    if (mJavaInitialized) {
+        return;
+    }
+    jclass sessionClazz = FindClassOrDie(env, "android/os/PerformanceHintManager$Session");
+    mJavaSessionClazz = MakeGlobalRefOrDie(env, sessionClazz);
+    mJavaSessionNativePtr = GetFieldIDOrDie(env, mJavaSessionClazz, "mNativeSessionPtr", "J");
+    mJavaInitialized = true;
+}
+
 // ===================================== APerformanceHintSession implementation
 
 constexpr int kNumEnums = enum_size<hal::SessionHint>();
 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
                                                  std::shared_ptr<IHintSession> session,
                                                  int64_t preferredRateNanos,
-                                                 int64_t targetDurationNanos,
+                                                 int64_t targetDurationNanos, bool isJava,
                                                  std::optional<hal::SessionConfig> sessionConfig)
       : mHintManager(hintManager),
         mHintSession(std::move(session)),
@@ -347,6 +380,7 @@
         mFirstTargetMetTimestamp(0),
         mLastTargetMetTimestamp(0),
         mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
+        mIsJava(isJava),
         mSessionConfig(sessionConfig) {
     if (sessionConfig->id > INT32_MAX) {
         ALOGE("Session ID too large, must fit 32-bit integer");
@@ -401,6 +435,10 @@
     return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
 }
 
+bool APerformanceHintSession::isJava() {
+    return mIsJava;
+}
+
 int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
                                        const char*) {
     std::scoped_lock lock(sHintMutex);
@@ -826,6 +864,22 @@
                                   static_cast<hal::SessionTag>(tag));
 }
 
+APerformanceHintSession* APerformanceHint_createSessionFromJava(
+        APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
+        int64_t initialTargetWorkDurationNanos) {
+    VALIDATE_PTR(manager)
+    VALIDATE_PTR(threadIds)
+    return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
+                                  hal::SessionTag::APP, true);
+}
+
+APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env,
+                                                                    jobject sessionObj) {
+    VALIDATE_PTR(env)
+    VALIDATE_PTR(sessionObj)
+    return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
+}
+
 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
     VALIDATE_PTR(manager)
     return manager->getPreferredRateNanos();
@@ -846,6 +900,16 @@
 
 void APerformanceHint_closeSession(APerformanceHintSession* session) {
     VALIDATE_PTR(session)
+    if (session->isJava()) {
+        LOG_ALWAYS_FATAL("%s: Java-owned PerformanceHintSession cannot be closed in native",
+                         __FUNCTION__);
+        return;
+    }
+    delete session;
+}
+
+void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session) {
+    VALIDATE_PTR(session)
     delete session;
 }
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index c90ba82..32d4580 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -464,5 +464,14 @@
         ));
         VALIDATORS.put(Global.HEARING_DEVICE_LOCAL_AMBIENT_VOLUME, ANY_STRING_VALIDATOR);
         VALIDATORS.put(Global.HEARING_DEVICE_LOCAL_NOTIFICATION, ANY_STRING_VALIDATOR);
+        VALIDATORS.put(
+                Global.Wearable.WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION,
+                new DiscreteValueValidator(
+                        new String[] {
+                                String.valueOf(
+                                        Global.Wearable.STATUS_TRAY_CONFIGURATION_DEFAULT),
+                                String.valueOf(
+                                        Global.Wearable.STATUS_TRAY_CONFIGURATION_SYSTEM_HIDDEN)
+                        }));
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 603a911..03fea37 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2434,28 +2434,40 @@
                 context.checkCallingOrSelfPermission(
                 Manifest.permission.WRITE_DEVICE_CONFIG)
                 == PackageManager.PERMISSION_GRANTED;
-        boolean isRoot = Binder.getCallingUid() == Process.ROOT_UID;
+        // Only the shell user and tests request the allowlist permission; this is used to force
+        // the WRITE_ALLOWLISTED_DEVICE_CONFIG path to log any flags that need to be allowlisted.
+        boolean isRestrictedShell = android.security.Flags.protectDeviceConfigFlags()
+                && hasAllowlistPermission;
 
-        if (isRoot) {
-            return;
-        }
-
-        if (hasWritePermission) {
+        if (!isRestrictedShell && hasWritePermission) {
             assertCallingUserDenyList(flags);
         } else if (hasAllowlistPermission) {
             for (String flag : flags) {
                 boolean namespaceAllowed = false;
-                for (String allowlistedPrefix : WritableNamespacePrefixes.ALLOWLIST) {
-                    if (flag.startsWith(allowlistedPrefix)) {
+                if (isRestrictedShell) {
+                    int delimiterIndex = flag.indexOf("/");
+                    String flagNamespace;
+                    if (delimiterIndex != -1) {
+                        flagNamespace = flag.substring(0, delimiterIndex);
+                    } else {
+                        flagNamespace = flag;
+                    }
+                    if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) {
                         namespaceAllowed = true;
-                        break;
+                    }
+                } else {
+                    for (String allowlistedPrefix : WritableNamespacePrefixes.ALLOWLIST) {
+                        if (flag.startsWith(allowlistedPrefix)) {
+                            namespaceAllowed = true;
+                            break;
+                        }
                     }
                 }
 
                 if (!namespaceAllowed && !DeviceConfig.getAdbWritableFlags().contains(flag)) {
-                    throw new SecurityException("Permission denial for flag '"
-                        + flag
-                        + "'; allowlist permission granted, but must add flag to the allowlist.");
+                    Slog.wtf(LOG_TAG, "Permission denial for flag '" + flag
+                            + "'; allowlist permission granted, but must add flag to the "
+                            + "allowlist");
                 }
             }
             assertCallingUserDenyList(flags);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
new file mode 100644
index 0000000..d835c5f
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespaces.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.providers.settings;
+
+import android.util.ArraySet;
+
+import java.util.Arrays;
+import java.util.Set;
+
+/**
+ * Contains the list of namespaces in which any flag can be written by adb without root
+ * permissions.
+ * <p>
+ * A security review is required for any namespace that's added to this list. To add to
+ * the list, create a change and tag the OWNER. In the commit message, include a
+ * description of the flag's functionality, and a justification for why it needs to be
+ * allowlisted.
+ */
+final class WritableNamespaces {
+    public static final Set<String> ALLOWLIST =
+            new ArraySet<String>(Arrays.asList(
+                    "exo"
+            ));
+}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9de7faf..a62b7fd 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -635,7 +635,8 @@
                     Settings.Global.Wearable.WEAR_MEDIA_SESSIONS_PACKAGE,
                     Settings.Global.Wearable.WEAR_POWER_ANOMALY_SERVICE_ENABLED,
                     Settings.Global.Wearable.CONNECTIVITY_KEEP_DATA_ON,
-                    Settings.Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE);
+                    Settings.Global.Wearable.PHONE_SWITCHING_REQUEST_SOURCE,
+                    Settings.Global.Wearable.WEAR_SYSTEM_STATUS_TRAY_CONFIGURATION);
 
     private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
              newHashSet(
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0df47ef..b8b5ed8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -242,6 +242,8 @@
     <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.COPY_ACCOUNTS" />
+    <uses-permission android:name="android.permission.REMOVE_ACCOUNTS" />
     <uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
     <uses-permission android:name="android.permission.FRAME_STATS" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 67666c3d..c82c63c7 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1798,3 +1798,17 @@
       purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "gsf_bouncer"
+    namespace: "systemui"
+    description: "Applies GSF font styles to Bouncer surfaces."
+    bug: "379364381"
+}
+
+flag {
+    name: "gsf_quick_settings"
+    namespace: "systemui"
+    description: "Applies GSF font styles to Quick Settings surfaces."
+    bug: "379364381"
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index b3fd097..4bccac1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -430,14 +430,6 @@
                     check(transitionStates.size == 1)
                     check(transitionStates[0] is TransitionState.Idle)
                     transitionStates = listOf(transition)
-                } else if (currentState == transition.replacedTransition) {
-                    // Replace the transition.
-                    transitionStates =
-                        transitionStates.subList(0, transitionStates.lastIndex) + transition
-
-                    // Make sure it is removed from the finishedTransitions set if it was already
-                    // finished.
-                    finishedTransitions.remove(currentState)
                 } else {
                     // Append the new transition.
                     transitionStates = transitionStates + transition
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
index b87cc5c..3622369 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/InterruptionHandlerTest.kt
@@ -132,6 +132,9 @@
         assertThat(state.currentTransitions)
             .comparingElementsUsing(FromToCurrentTriple)
             .containsExactly(
+                // Initial transition, A => B.
+                Triple(SceneA, SceneB, SceneB),
+
                 // Initial transition reversed, B back to A.
                 Triple(SceneA, SceneB, SceneA),
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
index 13f2c72..4e64c50 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -17,22 +17,23 @@
 package com.android.systemui.biometrics.domain.interactor
 
 import android.graphics.Rect
-import android.hardware.fingerprint.FingerprintManager
 import android.view.MotionEvent
 import android.view.Surface
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.authController
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
 import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
-import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -44,29 +45,25 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class UdfpsOverlayInteractorTest : SysuiTestCase() {
 
     @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
 
-    private lateinit var testScope: TestScope
+    private val kosmos = testKosmos()
 
-    @Mock private lateinit var fingerprintManager: FingerprintManager
-    @Mock private lateinit var authController: AuthController
+    private val testScope: TestScope = kosmos.testScope
+
+    private val authController: AuthController = kosmos.authController
     @Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback>
 
     @Mock private lateinit var udfpsOverlayParams: UdfpsOverlayParams
     @Mock private lateinit var overlayBounds: Rect
-    @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
 
     private lateinit var underTest: UdfpsOverlayInteractor
 
-    @Before
-    fun setUp() {
-        testScope = TestScope(StandardTestDispatcher())
-    }
-
     @Test
     fun testShouldInterceptTouch() =
         testScope.runTest {
@@ -107,15 +104,26 @@
             assertThat(udfpsOverlayParams()).isEqualTo(firstParams)
         }
 
+    @Test
+    fun testPaddingIsNeverNegative() =
+        testScope.runTest {
+            context.orCreateTestableResources.addOverride(R.dimen.pixel_pitch, 60.0f)
+            createUdfpsOverlayInteractor()
+            val padding by collectLastValue(underTest.iconPadding)
+            runCurrent()
+
+            verify(authController).addCallback(authControllerCallback.capture())
+
+            // Simulate the first empty udfps overlay params value.
+            authControllerCallback.value.onUdfpsLocationChanged(UdfpsOverlayParams())
+            runCurrent()
+
+            assertThat(padding).isEqualTo(0)
+            context.orCreateTestableResources.removeOverride(R.dimen.pixel_pitch)
+        }
+
     private fun createUdfpsOverlayInteractor() {
-        underTest =
-            UdfpsOverlayInteractor(
-                context,
-                authController,
-                selectedUserInteractor,
-                fingerprintManager,
-                testScope.backgroundScope
-            )
+        underTest = kosmos.udfpsOverlayInteractor
         testScope.runCurrent()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
index c39c3fe..2d54337 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.ui.viewmodel.fakeDeviceEntryIconViewModelTransition
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
 import com.android.systemui.shade.shadeTestUtil
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -43,6 +44,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.After
 import org.junit.Before
 import org.junit.runner.RunWith
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
@@ -84,6 +86,12 @@
     @Before
     fun setup() {
         underTest = kosmos.deviceEntryUdfpsAccessibilityOverlayViewModel
+        overrideResource(R.integer.udfps_padding_debounce_duration, 0)
+    }
+
+    @After
+    fun teardown() {
+        mContext.orCreateTestableResources.removeOverride(R.integer.udfps_padding_debounce_duration)
     }
 
     @Test
@@ -118,6 +126,7 @@
             runCurrent()
             assertThat(visible).isFalse()
         }
+
     fun fpNotRunning_overlayNotVisible() =
         testScope.runTest {
             val visible by collectLastValue(underTest.visible)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
index b0959e4..d42b538 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModelTest.kt
@@ -27,10 +27,13 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -43,6 +46,16 @@
     private val underTest: DeviceEntryForegroundViewModel =
         kosmos.deviceEntryForegroundIconViewModel
 
+    @Before
+    fun setup() {
+        context.orCreateTestableResources.addOverride(R.integer.udfps_padding_debounce_duration, 0)
+    }
+
+    @After
+    fun teardown() {
+        context.orCreateTestableResources.removeOverride(R.integer.udfps_padding_debounce_duration)
+    }
+
     @Test
     fun aodIconColorWhite() =
         testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 2e074da..48deee5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -2532,6 +2532,64 @@
             assertThat(isAlternateBouncerVisible).isFalse()
         }
 
+    @Test
+    fun replacesLockscreenSceneOnBackStack_whenFaceUnlocked_fromShade_noAlternateBouncer() =
+        testScope.runTest {
+            val transitionState =
+                prepareState(
+                    isDeviceUnlocked = false,
+                    initialSceneKey = Scenes.Lockscreen,
+                    authenticationMethod = AuthenticationMethodModel.Pin,
+                )
+            underTest.start()
+
+            val isUnlocked by
+                collectLastValue(
+                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+                )
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val backStack by collectLastValue(sceneBackInteractor.backStack)
+            val isAlternateBouncerVisible by
+                collectLastValue(kosmos.alternateBouncerInteractor.isVisible)
+            assertThat(isUnlocked).isFalse()
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(isAlternateBouncerVisible).isFalse()
+
+            // Change to shade.
+            sceneInteractor.changeScene(Scenes.Shade, "")
+            transitionState.value = ObservableTransitionState.Idle(Scenes.Shade)
+            runCurrent()
+            assertThat(isUnlocked).isFalse()
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+            assertThat(isAlternateBouncerVisible).isFalse()
+
+            // Show the alternate bouncer.
+            kosmos.alternateBouncerInteractor.forceShow()
+            kosmos.sysuiStatusBarStateController.leaveOpen = true // leave shade open
+            runCurrent()
+            assertThat(isUnlocked).isFalse()
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+            assertThat(isAlternateBouncerVisible).isTrue()
+
+            // Simulate race condition by hiding the alternate bouncer *before* the face unlock:
+            kosmos.alternateBouncerInteractor.hide()
+            runCurrent()
+            assertThat(isUnlocked).isFalse()
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Lockscreen)
+            assertThat(isAlternateBouncerVisible).isFalse()
+
+            // Trigger a face unlock.
+            updateFaceAuthStatus(isSuccess = true)
+            runCurrent()
+            assertThat(isUnlocked).isTrue()
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
+            assertThat(backStack?.asIterable()?.first()).isEqualTo(Scenes.Gone)
+            assertThat(isAlternateBouncerVisible).isFalse()
+        }
+
     private fun TestScope.emulateSceneTransition(
         transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
         toScene: SceneKey,
@@ -2768,15 +2826,16 @@
     }
 
     private fun updateFaceAuthStatus(isSuccess: Boolean) {
-        if (isSuccess) {
-            kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
-                SuccessFaceAuthenticationStatus(
-                    successResult = Mockito.mock(FaceManager.AuthenticationResult::class.java)
-                )
-            )
-        } else {
-            kosmos.fakeDeviceEntryFaceAuthRepository.setAuthenticationStatus(
-                FailedFaceAuthenticationStatus()
+        with(kosmos.fakeDeviceEntryFaceAuthRepository) {
+            isAuthenticated.value = isSuccess
+            setAuthenticationStatus(
+                if (isSuccess) {
+                    SuccessFaceAuthenticationStatus(
+                        successResult = Mockito.mock(FaceManager.AuthenticationResult::class.java)
+                    )
+                } else {
+                    FailedFaceAuthenticationStatus()
+                }
             )
         }
     }
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 813bb9c..8cab155 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -2056,6 +2056,9 @@
     <!-- UDFPS view attributes -->
     <!-- UDFPS icon size in microns/um -->
     <dimen name="udfps_icon_size" format="float">6000</dimen>
+    <!-- Limits the updates to at most one update per debounce duration to avoid too many
+         updates due to quick changes to padding.   -->
+    <integer name="udfps_padding_debounce_duration">100</integer>
     <!-- Microns/ums (1000 um = 1mm) per pixel for the given device. If unspecified, UI that
          relies on this value will not be sized correctly. -->
     <item name="pixel_pitch" format="float" type="dimen">-1</item>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
index abbbd73..9763295 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -36,8 +36,10 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
+import kotlin.math.max
 
 /** Encapsulates business logic for interacting with the UDFPS overlay. */
 @SysUISingleton
@@ -124,8 +126,9 @@
         udfpsOverlayParams.map { params ->
             val sensorWidth = params.nativeSensorBounds.right - params.nativeSensorBounds.left
             val nativePadding = (sensorWidth - iconSize) / 2
-            (nativePadding * params.scaleFactor).toInt()
-        }
+            // padding can be negative when udfpsOverlayParams has not been initialized yet.
+            max(0, (nativePadding * params.scaleFactor).toInt())
+        }.distinctUntilChanged()
 
     companion object {
         private const val TAG = "UdfpsOverlayInteractor"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 5065fcb..1965252 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -31,8 +31,10 @@
 import javax.inject.Inject
 import kotlin.math.roundToInt
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.debounce
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
@@ -40,6 +42,7 @@
 import kotlinx.coroutines.flow.onStart
 
 /** Models the UI state for the device entry icon foreground view (displayed icon). */
+@OptIn(FlowPreview::class)
 @ExperimentalCoroutinesApi
 @SysUISingleton
 class DeviceEntryForegroundViewModel
@@ -97,7 +100,7 @@
     private val padding: Flow<Int> =
         deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported ->
             if (udfpsSupported) {
-                udfpsOverlayInteractor.iconPadding
+                udfpsOverlayInteractor.iconPadding.debounce(udfpsPaddingDebounceDuration.toLong())
             } else {
                 configurationInteractor.scaleForResolution.map { scale ->
                     (context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) * scale)
@@ -120,6 +123,9 @@
             )
         }
 
+    private val udfpsPaddingDebounceDuration: Int
+        get() = context.resources.getInteger(R.integer.udfps_padding_debounce_duration)
+
     data class ForegroundIconViewModel(
         val type: DeviceEntryIconView.IconType,
         val useAodVariant: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index cb57c67..0a80a19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -126,7 +126,7 @@
     val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
     val resources = resources()
     val uiState = remember(state, resources) { state.toUiState(resources) }
-    val colors = TileDefaults.getColorForState(uiState)
+    val colors = TileDefaults.getColorForState(uiState, iconOnly)
     val hapticsViewModel: TileHapticsViewModel? =
         rememberViewModel(traceName = "TileHapticsViewModel") {
             tileHapticsViewModelFactoryProvider.getHapticsViewModelFactory()?.create(tile)
@@ -365,22 +365,24 @@
         )
 
     @Composable
-    fun getColorForState(uiState: TileUiState): TileColors {
+    fun getColorForState(uiState: TileUiState, iconOnly: Boolean): TileColors {
         return when (uiState.state) {
             STATE_ACTIVE -> {
-                if (uiState.handlesSecondaryClick) {
+                if (uiState.handlesSecondaryClick && !iconOnly) {
                     activeDualTargetTileColors()
                 } else {
                     activeTileColors()
                 }
             }
+
             STATE_INACTIVE -> {
-                if (uiState.handlesSecondaryClick) {
+                if (uiState.handlesSecondaryClick && !iconOnly) {
                     inactiveDualTargetTileColors()
                 } else {
                     inactiveTileColors()
                 }
             }
+
             else -> unavailableTileColors()
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index 35b1b96..ab3862b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -81,7 +81,7 @@
                             // additional
                             // guidance on how to auto add your tile
                             throw UnsupportedOperationException(
-                                "Turning on tile is not supported now"
+                                "Turning on tile is not supported now. Tile spec: $tileSpec"
                             )
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 9125d7e..066fe1b 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -430,8 +430,13 @@
                                             "mechanism: ${deviceUnlockStatus.deviceUnlockSource}"
                                 else -> null
                             }
-                        // Not on lockscreen or bouncer, so remain in the current scene.
-                        else -> null
+                        // Not on lockscreen or bouncer, so remain in the current scene but since
+                        // unlocked, replace the Lockscreen scene from the bottom of the navigation
+                        // back stack with the Gone scene.
+                        else -> {
+                            replaceLockscreenSceneOnBackStack()
+                            null
+                        }
                     }
                 }
                 .collect { (targetSceneKey, loggingReason) ->
@@ -440,17 +445,19 @@
         }
     }
 
-    /** If the [Scenes.Lockscreen] is on the backstack, replaces it with [Scenes.Gone]. */
+    /**
+     * If the [Scenes.Lockscreen] is on the bottom of the navigation backstack, replaces it with
+     * [Scenes.Gone].
+     */
     private fun replaceLockscreenSceneOnBackStack() {
         sceneBackInteractor.updateBackStack { stack ->
             val list = stack.asIterable().toMutableList()
-            check(list.last() == Scenes.Lockscreen) {
-                "The bottommost/last SceneKey of the back stack isn't" +
-                    " the Lockscreen scene like expected. The back" +
-                    " stack is $stack."
+            if (list.lastOrNull() == Scenes.Lockscreen) {
+                list[list.size - 1] = Scenes.Gone
+                sceneStackOf(*list.toTypedArray())
+            } else {
+                stack
             }
-            list[list.size - 1] = Scenes.Gone
-            sceneStackOf(*list.toTypedArray())
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 856333e..aad8b4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -2707,6 +2707,44 @@
                 eq(BubbleLogger.Event.BUBBLE_BAR_EXPANDED));
     }
 
+    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+    @Test
+    public void testEventLogging_bubbleBar_openOverflow() {
+        mBubbleProperties.mIsBubbleBarEnabled = true;
+        mPositioner.setIsLargeScreen(true);
+        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+        mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+        mEntryListener.onEntryAdded(mRow);
+
+        clearInvocations(mBubbleLogger);
+        mBubbleController.expandStackAndSelectBubbleFromLauncher(BubbleOverflow.KEY, 0);
+        verify(mBubbleLogger).log(BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_SELECTED);
+        verifyNoMoreInteractions(mBubbleLogger);
+    }
+
+    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+    @Test
+    public void testEventLogging_bubbleBar_fromOverflowToBar() {
+        mBubbleProperties.mIsBubbleBarEnabled = true;
+        mPositioner.setIsLargeScreen(true);
+        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+        mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+        mEntryListener.onEntryAdded(mRow);
+
+        // Dismiss the bubble so it's in the overflow
+        mBubbleController.removeBubble(
+                mRow.getKey(), Bubbles.DISMISS_USER_GESTURE);
+        Bubble overflowBubble = mBubbleData.getOverflowBubbleWithKey(mRow.getKey());
+        assertThat(overflowBubble).isNotNull();
+
+        // Promote overflow bubble and check that it is logged
+        mBubbleController.promoteBubbleFromOverflow(overflowBubble);
+        verify(mBubbleLogger).log(eqBubbleWithKey(overflowBubble.getKey()),
+                eq(BubbleLogger.Event.BUBBLE_BAR_OVERFLOW_REMOVE_BACK_TO_BAR));
+    }
+
     /** Creates a bubble using the userId and package. */
     private Bubble createBubble(int userId, String pkg) {
         final UserHandle userHandle = new UserHandle(userId);
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 619c8e3..7ca9239 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -142,33 +142,31 @@
         }
 
         /**
-         * Configure the given system property as immutable for the duration of the test.
-         * Read access to the key is allowed, and write access will fail. When {@code value} is
-         * {@code null}, the value is left as undefined.
-         *
-         * All properties in the {@code debug.*} namespace are automatically mutable, with no
-         * developer action required.
-         *
-         * Has no effect on non-Ravenwood environments.
+         * @deprecated Use {@link RavenwoodRule.Builder#setSystemPropertyImmutable(String, Object)}
          */
+        @Deprecated
         public Builder setSystemPropertyImmutable(@NonNull String key,
                 @Nullable Object value) {
+            return this;
+        }
+
+        /**
+         * @deprecated Use {@link RavenwoodRule.Builder#setSystemPropertyMutable(String, Object)}
+         */
+        @Deprecated
+        public Builder setSystemPropertyMutable(@NonNull String key,
+                @Nullable Object value) {
+            return this;
+        }
+
+        Builder setSystemPropertyImmutableReal(@NonNull String key,
+                @Nullable Object value) {
             mConfig.mSystemProperties.setValue(key, value);
             mConfig.mSystemProperties.setAccessReadOnly(key);
             return this;
         }
 
-        /**
-         * Configure the given system property as mutable for the duration of the test.
-         * Both read and write access to the key is allowed, and its value will be reset between
-         * each test. When {@code value} is {@code null}, the value is left as undefined.
-         *
-         * All properties in the {@code debug.*} namespace are automatically mutable, with no
-         * developer action required.
-         *
-         * Has no effect on non-Ravenwood environments.
-         */
-        public Builder setSystemPropertyMutable(@NonNull String key,
+        Builder setSystemPropertyMutableReal(@NonNull String key,
                 @Nullable Object value) {
             mConfig.mSystemProperties.setValue(key, value);
             mConfig.mSystemProperties.setAccessReadWrite(key);
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index f7acd90..5681a90 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -152,7 +152,7 @@
          * Has no effect on non-Ravenwood environments.
          */
         public Builder setSystemPropertyImmutable(@NonNull String key, @Nullable Object value) {
-            mBuilder.setSystemPropertyImmutable(key, value);
+            mBuilder.setSystemPropertyImmutableReal(key, value);
             return this;
         }
 
@@ -167,7 +167,7 @@
          * Has no effect on non-Ravenwood environments.
          */
         public Builder setSystemPropertyMutable(@NonNull String key, @Nullable Object value) {
-            mBuilder.setSystemPropertyMutable(key, value);
+            mBuilder.setSystemPropertyMutableReal(key, value);
             return this;
         }
 
diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
index dbeca82a..2d3782f 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -16,6 +16,8 @@
 
 package com.android.server.companion.securechannel;
 
+import static android.security.attestationverification.AttestationVerificationManager.FLAG_FAILURE_UNKNOWN;
+
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Build;
@@ -67,7 +69,7 @@
     private D2DConnectionContextV1 mConnectionContext;
 
     private String mAlias;
-    private int mVerificationResult;
+    private int mVerificationResult = FLAG_FAILURE_UNKNOWN;
     private boolean mPskVerified;
 
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 679c7ac..3ce6451 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -16,6 +16,10 @@
 
 package com.android.server.accounts;
 
+import static android.Manifest.permission.COPY_ACCOUNTS;
+import static android.Manifest.permission.REMOVE_ACCOUNTS;
+import static android.app.admin.flags.Flags.splitCreateManagedProfileEnabled;
+
 import android.Manifest;
 import android.accounts.AbstractAccountAuthenticator;
 import android.accounts.Account;
@@ -1739,9 +1743,11 @@
     public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
             final int userFrom, int userTo) {
         int callingUid = Binder.getCallingUid();
-        if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
+        if (isCrossUser(callingUid, UserHandle.USER_ALL)
+                && !hasCopyAccountsPermission()) {
             throw new SecurityException("Calling copyAccountToUser requires "
-                    + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+                    + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL
+                    + " or " + COPY_ACCOUNTS);
         }
         final UserAccounts fromAccounts = getUserAccounts(userFrom);
         final UserAccounts toAccounts = getUserAccounts(userTo);
@@ -1793,6 +1799,12 @@
         }
     }
 
+    private boolean hasCopyAccountsPermission() {
+        return splitCreateManagedProfileEnabled()
+                && mContext.checkCallingOrSelfPermission(COPY_ACCOUNTS)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public boolean accountAuthenticated(final Account account) {
         final int callingUid = Binder.getCallingUid();
@@ -2346,7 +2358,8 @@
         UserHandle user = UserHandle.of(userId);
         if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
                 && !isSystemUid(callingUid)
-                && !isProfileOwner(callingUid)) {
+                && !isProfileOwner(callingUid)
+                && !hasRemoveAccountsPermission()) {
             String msg = String.format(
                     "uid %s cannot remove accounts of type: %s",
                     callingUid,
@@ -2408,6 +2421,12 @@
         }
     }
 
+    private boolean hasRemoveAccountsPermission() {
+        return splitCreateManagedProfileEnabled()
+                && mContext.checkCallingOrSelfPermission(REMOVE_ACCOUNTS)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public boolean removeAccountExplicitly(Account account) {
         final int callingUid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index ef5296e..78c4f74 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -257,6 +257,7 @@
         "wear_systems",
         "wear_sysui",
         "wear_system_managed_surfaces",
+        "wear_watchfaces",
         "window_surfaces",
         "windowing_frontend",
         "xr",
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 00bab8a..8495b6c 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -28,6 +28,7 @@
 import android.media.quality.MediaQualityContract;
 import android.media.quality.ParamCapability;
 import android.media.quality.PictureProfile;
+import android.media.quality.PictureProfileHandle;
 import android.media.quality.SoundProfile;
 import android.os.PersistableBundle;
 import android.util.Log;
@@ -249,6 +250,11 @@
         }
 
         @Override
+        public PictureProfileHandle getPictureProfileHandle(String id) {
+            return null;
+        }
+
+        @Override
         public SoundProfile createSoundProfile(SoundProfile pp) {
             // TODO: implement
             return pp;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 4857b02e..70a8f56 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -344,6 +344,11 @@
     private ActivityRecord mTopResumedActivity;
 
     /**
+     * Cached value of the topmost resumed activity that reported to the client.
+     */
+    private ActivityRecord mLastReportedTopResumedActivity;
+
+    /**
      * Flag indicating whether we're currently waiting for the previous top activity to handle the
      * loss of the state and report back before making new activity top resumed.
      */
@@ -2287,15 +2292,13 @@
      * sent to the new top resumed activity.
      */
     ActivityRecord updateTopResumedActivityIfNeeded(String reason) {
-        if (!readyToResume()) {
-            return mTopResumedActivity;
-        }
         final ActivityRecord prevTopActivity = mTopResumedActivity;
         final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
         if (topRootTask == null || topRootTask.getTopResumedActivity() == prevTopActivity) {
             if (topRootTask == null) {
                 // There's no focused task and there won't have any resumed activity either.
                 scheduleTopResumedActivityStateLossIfNeeded();
+                mTopResumedActivity = null;
             }
             if (mService.isSleepingLocked()) {
                 // There won't be a next resumed activity. The top process should still be updated
@@ -2339,25 +2342,27 @@
 
     /** Schedule current top resumed activity state loss */
     private void scheduleTopResumedActivityStateLossIfNeeded() {
-        if (mTopResumedActivity == null) {
+        if (mLastReportedTopResumedActivity == null) {
             return;
         }
 
         // mTopResumedActivityWaitingForPrev == true at this point would mean that an activity
         // before the prevTopActivity one hasn't reported back yet. So server never sent the top
         // resumed state change message to prevTopActivity.
-        if (!mTopResumedActivityWaitingForPrev
-                && mTopResumedActivity.scheduleTopResumedActivityChanged(false /* onTop */)) {
-            scheduleTopResumedStateLossTimeout(mTopResumedActivity);
+        if (!mTopResumedActivityWaitingForPrev && readyToResume()
+                && mLastReportedTopResumedActivity.scheduleTopResumedActivityChanged(
+                        false /* onTop */)) {
+            scheduleTopResumedStateLossTimeout(mLastReportedTopResumedActivity);
             mTopResumedActivityWaitingForPrev = true;
+            mLastReportedTopResumedActivity = null;
         }
-        mTopResumedActivity = null;
     }
 
     /** Schedule top resumed state change if previous top activity already reported back. */
     private void scheduleTopResumedActivityStateIfNeeded() {
-        if (mTopResumedActivity != null && !mTopResumedActivityWaitingForPrev) {
+        if (mTopResumedActivity != null && !mTopResumedActivityWaitingForPrev && readyToResume()) {
             mTopResumedActivity.scheduleTopResumedActivityChanged(true /* onTop */);
+            mLastReportedTopResumedActivity = mTopResumedActivity;
         }
     }
 
@@ -2611,6 +2616,10 @@
      */
     void endDeferResume() {
         mDeferResumeCount--;
+        if (readyToResume() && mLastReportedTopResumedActivity != null
+                && mTopResumedActivity != mLastReportedTopResumedActivity) {
+            scheduleTopResumedActivityStateLossIfNeeded();
+        }
     }
 
     /** @return True if resume can be called. */
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 81a04af..f0e12fe 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -2025,22 +2025,9 @@
         // Fill in some deprecated values.
         rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
         rti.persistentId = rti.taskId;
-        rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
         if (!getTasksAllowed) {
             Task.trimIneffectiveInfo(tr, rti);
         }
-
-        // Fill in organized child task info for the task created by organizer.
-        if (tr.mCreatedByOrganizer) {
-            for (int i = tr.getChildCount() - 1; i >= 0; i--) {
-                final Task childTask = tr.getChildAt(i).asTask();
-                if (childTask != null && childTask.isOrganized()) {
-                    final ActivityManager.RecentTaskInfo cti = new ActivityManager.RecentTaskInfo();
-                    childTask.fillTaskInfo(cti, true /* stripExtras */, tda);
-                    rti.childrenTaskInfos.add(cti);
-                }
-            }
-        }
         return rti;
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e8ae280..9504fc7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -128,7 +128,6 @@
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
@@ -256,9 +255,6 @@
     private static final String ATTR_MIN_HEIGHT = "min_height";
     private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
     private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
-    private static final String ATTR_LAST_SNAPSHOT_TASK_SIZE = "last_snapshot_task_size";
-    private static final String ATTR_LAST_SNAPSHOT_CONTENT_INSETS = "last_snapshot_content_insets";
-    private static final String ATTR_LAST_SNAPSHOT_BUFFER_SIZE = "last_snapshot_buffer_size";
 
     // How long to wait for all background Activities to redraw following a call to
     // convertToTranslucent().
@@ -472,10 +468,6 @@
     // NOTE: This value needs to be persisted with each task
     private TaskDescription mTaskDescription;
 
-    // Information about the last snapshot that should be persisted with the task to allow SystemUI
-    // to layout without loading all the task snapshots
-    final PersistedTaskSnapshotData mLastTaskSnapshotData;
-
     /** @see #setCanAffectSystemUiFlags */
     private boolean mCanAffectSystemUiFlags = true;
 
@@ -635,14 +627,13 @@
             ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
             boolean _autoRemoveRecents, int _userId, int _effectiveUid,
             String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
-            TaskDescription _lastTaskDescription, PersistedTaskSnapshotData _lastSnapshotData,
-            int taskAffiliation, int prevTaskId, int nextTaskId, int callingUid,
-            String callingPackage, @Nullable String callingFeatureId, int resizeMode,
-            boolean supportsPictureInPicture, boolean _realActivitySuspended,
-            boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
-            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
-            boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear,
-            boolean _removeWithTaskOrganizer) {
+            TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
+            int nextTaskId, int callingUid, String callingPackage,
+            @Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
+            boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
+            ActivityInfo info, IVoiceInteractionSession _voiceSession,
+            IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer, IBinder _launchCookie,
+            boolean _deferTaskAppear, boolean _removeWithTaskOrganizer) {
         super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */);
 
         mTaskId = _taskId;
@@ -652,9 +643,6 @@
         mTaskDescription = _lastTaskDescription != null
                 ? _lastTaskDescription
                 : new TaskDescription();
-        mLastTaskSnapshotData = _lastSnapshotData != null
-                ? _lastSnapshotData
-                : new PersistedTaskSnapshotData();
         affinityIntent = _affinityIntent;
         affinity = _affinity;
         rootAffinity = _rootAffinity;
@@ -3111,7 +3099,6 @@
     }
 
     void onSnapshotChanged(TaskSnapshot snapshot) {
-        mLastTaskSnapshotData.set(snapshot);
         mAtmService.getTaskChangeNotificationController().notifyTaskSnapshotChanged(
                 mTaskId, snapshot);
     }
@@ -3990,19 +3977,6 @@
         out.attributeInt(null, ATTR_MIN_HEIGHT, mMinHeight);
         out.attributeInt(null, ATTR_PERSIST_TASK_VERSION, PERSIST_TASK_VERSION);
 
-        if (mLastTaskSnapshotData.taskSize != null) {
-            out.attribute(null, ATTR_LAST_SNAPSHOT_TASK_SIZE,
-                    mLastTaskSnapshotData.taskSize.flattenToString());
-        }
-        if (mLastTaskSnapshotData.contentInsets != null) {
-            out.attribute(null, ATTR_LAST_SNAPSHOT_CONTENT_INSETS,
-                    mLastTaskSnapshotData.contentInsets.flattenToString());
-        }
-        if (mLastTaskSnapshotData.bufferSize != null) {
-            out.attribute(null, ATTR_LAST_SNAPSHOT_BUFFER_SIZE,
-                    mLastTaskSnapshotData.bufferSize.flattenToString());
-        }
-
         if (affinityIntent != null) {
             out.startTag(null, TAG_AFFINITYINTENT);
             affinityIntent.saveToXml(out);
@@ -4069,7 +4043,6 @@
         int taskId = INVALID_TASK_ID;
         final int outerDepth = in.getDepth();
         TaskDescription taskDescription = new TaskDescription();
-        PersistedTaskSnapshotData lastSnapshotData = new PersistedTaskSnapshotData();
         int taskAffiliation = INVALID_TASK_ID;
         int prevTaskId = INVALID_TASK_ID;
         int nextTaskId = INVALID_TASK_ID;
@@ -4176,15 +4149,6 @@
                 case ATTR_PERSIST_TASK_VERSION:
                     persistTaskVersion = Integer.parseInt(attrValue);
                     break;
-                case ATTR_LAST_SNAPSHOT_TASK_SIZE:
-                    lastSnapshotData.taskSize = Point.unflattenFromString(attrValue);
-                    break;
-                case ATTR_LAST_SNAPSHOT_CONTENT_INSETS:
-                    lastSnapshotData.contentInsets = Rect.unflattenFromString(attrValue);
-                    break;
-                case ATTR_LAST_SNAPSHOT_BUFFER_SIZE:
-                    lastSnapshotData.bufferSize = Point.unflattenFromString(attrValue);
-                    break;
                 default:
                     if (!attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
                         Slog.w(TAG, "Task: Unknown attribute=" + attrName);
@@ -4278,7 +4242,6 @@
                 .setLastTimeMoved(lastTimeOnTop)
                 .setNeverRelinquishIdentity(neverRelinquishIdentity)
                 .setLastTaskDescription(taskDescription)
-                .setLastSnapshotData(lastSnapshotData)
                 .setTaskAffiliation(taskAffiliation)
                 .setPrevAffiliateTaskId(prevTaskId)
                 .setNextAffiliateTaskId(nextTaskId)
@@ -6444,7 +6407,6 @@
         private long mLastTimeMoved;
         private boolean mNeverRelinquishIdentity;
         private TaskDescription mLastTaskDescription;
-        private PersistedTaskSnapshotData mLastSnapshotData;
         private int mTaskAffiliation;
         private int mPrevAffiliateTaskId = INVALID_TASK_ID;
         private int mNextAffiliateTaskId = INVALID_TASK_ID;
@@ -6672,11 +6634,6 @@
             return this;
         }
 
-        private Builder setLastSnapshotData(PersistedTaskSnapshotData lastSnapshotData) {
-            mLastSnapshotData = lastSnapshotData;
-            return this;
-        }
-
         private Builder setOrigActivity(ComponentName origActivity) {
             mOrigActivity = origActivity;
             return this;
@@ -6825,7 +6782,7 @@
             return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
                     mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
                     mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
-                    mNeverRelinquishIdentity, mLastTaskDescription, mLastSnapshotData,
+                    mNeverRelinquishIdentity, mLastTaskDescription,
                     mTaskAffiliation, mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid,
                     mCallingPackage, mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
                     mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 0918965..c42aa37 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -788,9 +788,7 @@
                 deferResume = false;
                 // Already calls ensureActivityConfig
                 mService.mRootWindowContainer.ensureActivitiesVisible();
-                if (!mService.mRootWindowContainer.resumeFocusedTasksTopActivities()) {
-                    mService.mTaskSupervisor.updateTopResumedActivityIfNeeded("endWCT-effects");
-                }
+                mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
             } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
                 for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
                     haveConfigChanges.valueAt(i).forAllActivities(r -> {
@@ -816,10 +814,6 @@
             mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
             if (deferResume) {
                 mService.mTaskSupervisor.endDeferResume();
-                // Transient launching the Recents via HIERARCHY_OP_TYPE_PENDING_INTENT directly
-                // resume the Recents activity with no TRANSACT_EFFECTS_LIFECYCLE. Explicitly
-                // checks if the top resumed activity should be updated after defer-resume ended.
-                mService.mTaskSupervisor.updateTopResumedActivityIfNeeded("endWCT");
             }
             mService.continueWindowLayout();
         }
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 5bb6b19..d087155 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -194,7 +194,13 @@
                 () -> assertThat(mActivity.hideImeWithWindowInsetsController()).isTrue(),
                 true /* expected */,
                 false /* inputViewStarted */);
-        assertThat(mInputMethodService.isInputViewShown()).isFalse();
+        if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) {
+            // The IME visibility is only sent at the end of the animation. Therefore, we have to
+            // wait until the visibility was sent to the server and the IME window hidden.
+            eventually(() -> assertThat(mInputMethodService.isInputViewShown()).isFalse());
+        } else {
+            assertThat(mInputMethodService.isInputViewShown()).isFalse();
+        }
     }
 
     /**
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
index 0d5d277..ed927c6 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/WakelockPowerStatsCollectorTest.java
@@ -26,8 +26,7 @@
 import android.os.Process;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
-import android.platform.test.ravenwood.RavenwoodConfig;
-import android.platform.test.ravenwood.RavenwoodConfig.Config;
+import android.platform.test.ravenwood.RavenwoodRule;
 
 import com.android.internal.os.PowerStats;
 import com.android.server.power.feature.flags.Flags;
@@ -39,10 +38,9 @@
 
 public class WakelockPowerStatsCollectorTest {
 
-    @Config
-    public static final RavenwoodConfig sConfig =
-            new RavenwoodConfig.Builder()
-                    .setProvideMainThread(true)
+    @Rule
+    public final RavenwoodRule mRule =
+            new RavenwoodRule.Builder()
                     .setSystemPropertyImmutable(
                             "persist.sys.com.android.server.power.feature.flags."
                                     + "framework_wakelock_info-override",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 704c1b8..e6b4bc9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -17178,8 +17178,6 @@
     @Test
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testSetCanBePromoted_granted() throws Exception {
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         // qualifying posted notification
         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -17254,8 +17252,6 @@
     @Test
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception {
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         // qualifying posted notification
         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -17285,8 +17281,6 @@
     @Test
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testSetCanBePromoted_revoked() throws Exception {
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         // start from true state
         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
 
@@ -17350,8 +17344,6 @@
     @Test
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception {
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         // start from true state
         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
 
@@ -17387,8 +17379,6 @@
     public void testPostPromotableNotification() throws Exception {
         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
         assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue();
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
 
         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -17415,8 +17405,6 @@
     @Test
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testPostPromotableNotification_noPermission() throws Exception {
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId())
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
@@ -17444,8 +17432,6 @@
     @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
     public void testPostPromotableNotification_unimportantNotification() throws Exception {
         mBinderService.setCanBePromoted(mPkg, mUid, true, true);
-        mContext.getTestablePermissions().setPermission(
-                android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED);
         Notification n = new Notification.Builder(mContext, mMinChannel.getId())
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
                 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG"))
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 7f260f8..70f57eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -357,6 +357,25 @@
         assertEquals(activity1.app, mAtm.mTopApp);
     }
 
+    @Test
+    public void testTopResumedActivity_deferResume() {
+        final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+        activity2.setState(ActivityRecord.State.RESUMED, "test");
+        assertEquals(activity2.app, mAtm.mTopApp);
+        reset(activity2);
+
+        // Verify that no top-resumed activity changes to the client while defer-resume enabled.
+        mSupervisor.beginDeferResume();
+        activity1.getTask().moveToFront("test");
+        activity1.setState(ActivityRecord.State.RESUMED, "test");
+        verify(activity2, never()).scheduleTopResumedActivityChanged(eq(false));
+
+        // Verify that the change is scheduled to the client after defer-resumed disabled
+        mSupervisor.endDeferResume();
+        verify(activity2).scheduleTopResumedActivityChanged(eq(false));
+    }
+
     /**
      * We need to launch home again after user unlocked for those displays that do not have
      * encryption aware home app.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index df17cd1..7ed8283 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -496,24 +496,6 @@
     }
 
     @Test
-    public void testAppendOrganizedChildTaskInfo() {
-        final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build();
-        root.mCreatedByOrganizer = true;
-        // Add organized and non-organized child.
-        final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build();
-        final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build();
-        doReturn(true).when(child1).isOrganized();
-        doReturn(false).when(child2).isOrganized();
-        mRecentTasks.add(root);
-
-        // Make sure only organized child will be appended.
-        final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
-        final List<RecentTaskInfo> childrenTaskInfos = infos.get(0).childrenTaskInfos;
-        assertEquals(childrenTaskInfos.size(), 1);
-        assertEquals(childrenTaskInfos.get(0).taskId, child1.mTaskId);
-    }
-
-    @Test
     public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
         // There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
         // FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
@@ -1420,46 +1402,6 @@
     }
 
     @Test
-    public void testLastSnapshotData_snapshotSaved() {
-        final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), new Point(80, 80));
-        final Task task1 = createTaskBuilder(".Task").build();
-        task1.onSnapshotChanged(snapshot);
-
-        mRecentTasks.add(task1);
-        final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
-        final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
-                infos.get(0).lastSnapshotData;
-        assertTrue(lastSnapshotData.taskSize.equals(100, 100));
-        assertTrue(lastSnapshotData.bufferSize.equals(80, 80));
-    }
-
-    @Test
-    public void testLastSnapshotData_noBuffer() {
-        final Task task1 = createTaskBuilder(".Task").build();
-        final TaskSnapshot snapshot = createSnapshot(new Point(100, 100), null);
-        task1.onSnapshotChanged(snapshot);
-
-        mRecentTasks.add(task1);
-        final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
-        final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
-                infos.get(0).lastSnapshotData;
-        assertTrue(lastSnapshotData.taskSize.equals(100, 100));
-        assertNull(lastSnapshotData.bufferSize);
-    }
-
-    @Test
-    public void testLastSnapshotData_notSet() {
-        final Task task1 = createTaskBuilder(".Task").build();
-
-        mRecentTasks.add(task1);
-        final List<RecentTaskInfo> infos = getRecentTasks(0 /* flags */);
-        final RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
-                infos.get(0).lastSnapshotData;
-        assertNull(lastSnapshotData.taskSize);
-        assertNull(lastSnapshotData.bufferSize);
-    }
-
-    @Test
     public void testCreateRecentTaskInfo_detachedTask() {
         final Task task = createTaskBuilder(".Task").build();
         final ComponentName componentName = getUniqueComponentName();
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
index 69fde01..9e48848 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/StartMediaProjectionAppHelper.kt
@@ -65,10 +65,45 @@
             .waitForAndVerify()
     }
 
+    fun startSingleAppMediaProjectionWithExtraIntent(
+        wmHelper: WindowManagerStateHelper,
+        targetApp: StandardAppHelper
+    ) {
+        clickStartMediaProjectionWithExtraIntentButton()
+        chooseSingleAppOption()
+        startScreenSharing()
+        selectTargetApp(targetApp.appName)
+        wmHelper
+            .StateSyncBuilder()
+            .withAppTransitionIdle()
+            .withHomeActivityVisible()
+            .waitForAndVerify()
+    }
+
+    fun startSingleAppMediaProjectionFromRecents(
+        wmHelper: WindowManagerStateHelper,
+        targetApp: StandardAppHelper,
+        recentTasksIndex: Int = 0,
+    ) {
+        clickStartMediaProjectionButton()
+        chooseSingleAppOption()
+        startScreenSharing()
+        selectTargetAppRecent(recentTasksIndex)
+        wmHelper
+            .StateSyncBuilder()
+            .withAppTransitionIdle()
+            .withWindowSurfaceAppeared(targetApp)
+            .waitForAndVerify()
+    }
+
     private fun clickStartMediaProjectionButton() {
         findObject(By.res(packageName, START_MEDIA_PROJECTION_BUTTON_ID)).also { it.click() }
     }
 
+    private fun clickStartMediaProjectionWithExtraIntentButton() {
+        findObject(By.res(packageName, START_MEDIA_PROJECTION_NEW_INTENT_BUTTON_ID)).also { it.click() }
+    }
+
     private fun chooseEntireScreenOption() {
         findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
 
@@ -92,6 +127,13 @@
         findObject(By.text(targetAppName)).also { it.click() }
     }
 
+    private fun selectTargetAppRecent(recentTasksIndex: Int) {
+        // Scroll to to find target app to launch then click app icon it to start capture
+        val recentsTasksRecycler =
+            findObject(By.res(SYSTEMUI_PACKAGE, MEDIA_PROJECTION_RECENT_TASKS))
+        recentsTasksRecycler.children[recentTasksIndex].also{ it.click() }
+    }
+
     private fun chooseSingleAppOption() {
         findObject(By.res(SCREEN_SHARE_OPTIONS_PATTERN)).also { it.click() }
 
@@ -116,8 +158,10 @@
         const val TIMEOUT: Long = 5000L
         const val ACCEPT_RESOURCE_ID: String = "android:id/button1"
         const val START_MEDIA_PROJECTION_BUTTON_ID: String = "button_start_mp"
+        const val START_MEDIA_PROJECTION_NEW_INTENT_BUTTON_ID: String = "button_start_mp_new_intent"
         val SCREEN_SHARE_OPTIONS_PATTERN: Pattern =
             Pattern.compile("$SYSTEMUI_PACKAGE:id/screen_share_mode_(options|spinner)")
+        const val MEDIA_PROJECTION_RECENT_TASKS: String = "media_projection_recent_tasks_recycler"
         const val ENTIRE_SCREEN_STRING_RES_NAME: String =
             "screen_share_permission_dialog_option_entire_screen"
         const val SINGLE_APP_STRING_RES_NAME: String =
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
index 46f01e6..c34d200 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
@@ -16,17 +16,27 @@
 -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
     android:orientation="vertical"
     android:background="@android:color/holo_orange_light">
 
     <Button
         android:id="@+id/button_start_mp"
-        android:layout_width="500dp"
-        android:layout_height="500dp"
+        android:layout_margin="16dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:gravity="center_vertical|center_horizontal"
         android:text="Start Media Projection"
         android:textAppearance="?android:attr/textAppearanceLarge"/>
 
+    <Button
+        android:id="@+id/button_start_mp_new_intent"
+        android:layout_margin="16dp"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical|center_horizontal"
+        android:text="Start Media Projection with extra intent"
+        android:textAppearance="?android:attr/textAppearanceLarge"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
index a24a482..b29b874 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/StartMediaProjectionActivity.java
@@ -19,7 +19,8 @@
 import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.EXTRA_MESSENGER;
 import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_SERVICE_DESTROYED;
 import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.MSG_START_FOREGROUND_DONE;
-import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE_NORMAL;
+import static com.android.wm.shell.flicker.utils.MediaProjectionUtils.REQUEST_CODE_EXTRA_INTENT;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -71,13 +72,17 @@
         setContentView(R.layout.activity_start_media_projection);
 
         Button startMediaProjectionButton = findViewById(R.id.button_start_mp);
+        Button startMediaProjectionButton2 = findViewById(R.id.button_start_mp_new_intent);
         startMediaProjectionButton.setOnClickListener(v ->
-                startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE));
+                startActivityForResult(mService.createScreenCaptureIntent(), REQUEST_CODE_NORMAL));
+        startMediaProjectionButton2.setOnClickListener(v ->
+                startActivityForResult(mService.createScreenCaptureIntent(),
+                        REQUEST_CODE_EXTRA_INTENT));
     }
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode != REQUEST_CODE) {
+        if (requestCode != REQUEST_CODE_NORMAL && requestCode != REQUEST_CODE_EXTRA_INTENT) {
             throw new IllegalStateException("Unknown request code: " + requestCode);
         }
         if (resultCode != RESULT_OK) {
@@ -85,6 +90,11 @@
         }
         Log.d(TAG, "onActivityResult");
         startMediaProjectionService(resultCode, data);
+        if (requestCode == REQUEST_CODE_EXTRA_INTENT) {
+            Intent startMain = new Intent(Intent.ACTION_MAIN);
+            startMain.addCategory(Intent.CATEGORY_HOME);
+            startActivity(startMain);
+        }
     }
 
     private void startMediaProjectionService(int resultCode, Intent resultData) {
@@ -122,7 +132,7 @@
                 displayBounds.width(), displayBounds.height(), PixelFormat.RGBA_8888, 1);
 
         mVirtualDisplay = mMediaProjection.createVirtualDisplay(
-                "DanielDisplay",
+                "TestDisplay",
                 displayBounds.width(),
                 displayBounds.height(),
                 DisplayMetrics.DENSITY_HIGH,