Merge "Revert "feat(multi finger multi tap): add Setting for control magnification enable gesture"" into main
diff --git a/Android.bp b/Android.bp
index 986a071..b5f7e99 100644
--- a/Android.bp
+++ b/Android.bp
@@ -695,12 +695,10 @@
         "--hide CallbackInterface",
         "--hide DeprecationMismatch",
         "--hide HiddenSuperclass",
-        "--hide HiddenTypeParameter",
         "--hide MissingPermission",
         "--hide RequiresPermission",
         "--hide SdkConstant",
         "--hide Todo",
-        "--hide UnavailableSymbol",
         "--hide-package android.audio.policy.configuration.V7_0",
         "--hide-package com.android.server",
         "--manifest $(location :frameworks-base-core-AndroidManifest.xml)",
diff --git a/core/api/current.txt b/core/api/current.txt
index cce8329..18001e8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33455,7 +33455,9 @@
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(String);
     method public boolean isAdminUser();
+    method @FlaggedApi("android.multiuser.support_communal_profile") public boolean isCommunalProfile();
     method public boolean isDemoUser();
+    method @FlaggedApi("android.multiuser.support_communal_profile_nextgen") public boolean isForegroundUserAdmin();
     method public static boolean isHeadlessSystemUserMode();
     method public boolean isManagedProfile();
     method public boolean isProfile();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 119e0ad..6062f79 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3875,6 +3875,7 @@
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
     method public void setRequestDowngrade(boolean);
+    method @FlaggedApi("android.content.pm.rollback_lifetime") @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackLifetimeMillis(long);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e130206..83b6880 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2148,7 +2148,9 @@
   }
 
   public final class BugreportParams {
+    field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 4; // 0x4
     field @FlaggedApi("android.os.bugreport_mode_max_value") public static final int BUGREPORT_MODE_MAX_VALUE = 7; // 0x7
+    field @FlaggedApi("android.app.admin.flags.onboarding_bugreport_v2_enabled") public static final int BUGREPORT_MODE_ONBOARDING = 7; // 0x7
   }
 
   public class Build {
@@ -2355,6 +2357,7 @@
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.content.pm.UserInfo createUser(@Nullable String, @NonNull String, int);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.List<android.content.pm.UserInfo> getAliveUsers();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.UserHandle getBootUser();
+    method @FlaggedApi("android.multiuser.support_communal_profile") @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getCommunalProfile();
     method public int getMainDisplayIdAssignedToUser();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public java.util.Set<java.lang.String> getPreInstallableSystemPackages(@NonNull String);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public String getUserType();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ecbc9b1..9a19d8e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -8638,8 +8638,8 @@
                 }
             }
 
-            SyncNotedAppOp syncOp = mService.noteProxyOperation(op, attributionSource.asState(),
-                    collectionMode == COLLECT_ASYNC, message,
+            SyncNotedAppOp syncOp = mService.noteProxyOperationWithState(op,
+                    attributionSource.asState(), collectionMode == COLLECT_ASYNC, message,
                     shouldCollectMessage, skipProxyOperation);
 
             if (syncOp.getOpMode() == MODE_ALLOWED) {
@@ -9110,7 +9110,7 @@
                 }
             }
 
-            SyncNotedAppOp syncOp = mService.startProxyOperation(clientId, op,
+            SyncNotedAppOp syncOp = mService.startProxyOperationWithState(clientId, op,
                     attributionSource.asState(), false, collectionMode == COLLECT_ASYNC, message,
                     shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
                     proxiedAttributionFlags, attributionChainId);
@@ -9229,8 +9229,8 @@
     public void finishProxyOp(@NonNull IBinder clientId, @NonNull String op,
             @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
         try {
-            mService.finishProxyOperation(clientId, strOpToOp(op), attributionSource.asState(),
-                    skipProxyOperation);
+            mService.finishProxyOperationWithState(
+                    clientId, strOpToOp(op), attributionSource.asState(), skipProxyOperation);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 2d55403..545ba8e 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -26,6 +26,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.app.admin.PasswordMetrics;
@@ -736,7 +737,7 @@
      * @see #isKeyguardLocked()
      */
     public boolean isDeviceLocked() {
-        return isDeviceLocked(mContext.getUserId());
+        return isDeviceLocked(mContext.getUserId(), mContext.getDeviceId());
     }
 
     /**
@@ -746,8 +747,17 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public boolean isDeviceLocked(int userId) {
+        return isDeviceLocked(userId, mContext.getDeviceId());
+    }
+
+    /**
+     * Per-user per-device version of {@link #isDeviceLocked()}.
+     *
+     * @hide
+     */
+    public boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
         try {
-            return mTrustManager.isDeviceLocked(userId, mContext.getAssociatedDisplayId());
+            return mTrustManager.isDeviceLocked(userId, deviceId);
         } catch (RemoteException e) {
             return false;
         }
@@ -769,7 +779,7 @@
      * @see #isKeyguardSecure()
      */
     public boolean isDeviceSecure() {
-        return isDeviceSecure(mContext.getUserId());
+        return isDeviceSecure(mContext.getUserId(), mContext.getDeviceId());
     }
 
     /**
@@ -779,8 +789,17 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public boolean isDeviceSecure(int userId) {
+        return isDeviceSecure(userId, mContext.getDeviceId());
+    }
+
+    /**
+     * Per-user per-device version of {@link #isDeviceSecure()}.
+     *
+     * @hide
+     */
+    public boolean isDeviceSecure(@UserIdInt int userId, int deviceId) {
         try {
-            return mTrustManager.isDeviceSecure(userId, mContext.getAssociatedDisplayId());
+            return mTrustManager.isDeviceSecure(userId, deviceId);
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 3bde39c..bbc843b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -374,7 +374,7 @@
      * that you take care of task management as described in the
      * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
      * Stack</a> document.  In particular, make sure to read the
-     * <a href="{@docRoot}/training/notify-user/navigation">Start
+     * <a href="{@docRoot}training/notify-user/navigation">Start
      * an Activity from a Notification</a> page for the correct ways to launch an application from a
      * notification.
      */
@@ -5606,7 +5606,8 @@
             contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
             // Use different highlighted colors for conversations' unread count
             if (p.mHighlightExpander) {
-                pillColor = Colors.flattenAlpha(getColors(p).getTertiaryAccentColor(), bgColor);
+                pillColor = Colors.flattenAlpha(
+                        getColors(p).getTertiaryFixedDimAccentColor(), bgColor);
                 textColor = Colors.flattenAlpha(
                         getColors(p).getOnTertiaryAccentTextColor(), pillColor);
             }
@@ -12835,6 +12836,9 @@
         private int mSecondaryAccentColor = COLOR_INVALID;
         private int mTertiaryAccentColor = COLOR_INVALID;
         private int mOnTertiaryAccentTextColor = COLOR_INVALID;
+        private int mTertiaryFixedDimAccentColor = COLOR_INVALID;
+        private int mOnTertiaryFixedAccentTextColor = COLOR_INVALID;
+
         private int mErrorColor = COLOR_INVALID;
         private int mContrastColor = COLOR_INVALID;
         private int mRippleAlpha = 0x33;
@@ -12892,7 +12896,7 @@
 
             if (isColorized) {
                 if (rawColor == COLOR_DEFAULT) {
-                    int[] attrs = {R.attr.colorAccentSecondary};
+                    int[] attrs = {R.attr.materialColorSecondary};
                     try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
                         mBackgroundColor = getColor(ta, 0, Color.WHITE);
                     }
@@ -12910,17 +12914,21 @@
                 mSecondaryAccentColor = mSecondaryTextColor;
                 mTertiaryAccentColor = flattenAlpha(mPrimaryTextColor, mBackgroundColor);
                 mOnTertiaryAccentTextColor = mBackgroundColor;
+                mTertiaryFixedDimAccentColor = mTertiaryAccentColor;
+                mOnTertiaryFixedAccentTextColor = mOnTertiaryAccentTextColor;
                 mErrorColor = mPrimaryTextColor;
                 mRippleAlpha = 0x33;
             } else {
                 int[] attrs = {
-                        R.attr.colorSurface,
-                        R.attr.textColorPrimary,
-                        R.attr.textColorSecondary,
-                        R.attr.colorAccent,
-                        R.attr.colorAccentSecondary,
-                        R.attr.colorAccentTertiary,
-                        R.attr.textColorOnAccent,
+                        R.attr.materialColorSurfaceContainerHigh,
+                        R.attr.materialColorOnSurface,
+                        R.attr.materialColorOnSurfaceVariant,
+                        R.attr.materialColorPrimary,
+                        R.attr.materialColorSecondary,
+                        R.attr.materialColorTertiary,
+                        R.attr.materialColorOnTertiary,
+                        R.attr.materialColorTertiaryFixedDim,
+                        R.attr.materialColorOnTertiaryFixed,
                         R.attr.colorError,
                         R.attr.colorControlHighlight
                 };
@@ -12932,8 +12940,10 @@
                     mSecondaryAccentColor = getColor(ta, 4, COLOR_INVALID);
                     mTertiaryAccentColor = getColor(ta, 5, COLOR_INVALID);
                     mOnTertiaryAccentTextColor = getColor(ta, 6, COLOR_INVALID);
-                    mErrorColor = getColor(ta, 7, COLOR_INVALID);
-                    mRippleAlpha = Color.alpha(getColor(ta, 8, 0x33ffffff));
+                    mTertiaryFixedDimAccentColor = getColor(ta, 7, COLOR_INVALID);
+                    mOnTertiaryFixedAccentTextColor = getColor(ta, 8, COLOR_INVALID);
+                    mErrorColor = getColor(ta, 9, COLOR_INVALID);
+                    mRippleAlpha = Color.alpha(getColor(ta, 10, 0x33ffffff));
                 }
                 mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
                         mBackgroundColor, nightMode);
@@ -12961,6 +12971,14 @@
                             ContrastColorUtil.resolvePrimaryColor(
                                     ctx, mTertiaryAccentColor, nightMode), 0xFF);
                 }
+                if (mTertiaryFixedDimAccentColor == COLOR_INVALID) {
+                    mTertiaryFixedDimAccentColor = mContrastColor;
+                }
+                if (mOnTertiaryFixedAccentTextColor == COLOR_INVALID) {
+                    mOnTertiaryFixedAccentTextColor = ColorUtils.setAlphaComponent(
+                            ContrastColorUtil.resolvePrimaryColor(
+                                    ctx, mTertiaryFixedDimAccentColor, nightMode), 0xFF);
+                }
                 if (mErrorColor == COLOR_INVALID) {
                     mErrorColor = mPrimaryTextColor;
                 }
@@ -13034,6 +13052,16 @@
             return mOnTertiaryAccentTextColor;
         }
 
+        /** @return the theme's tertiary fixed dim accent color for colored UI elements. */
+        public @ColorInt int getTertiaryFixedDimAccentColor() {
+            return mTertiaryFixedDimAccentColor;
+        }
+
+        /** @return the theme's text color to be used on the tertiary fixed accent color. */
+        public @ColorInt int getOnTertiaryFixedAccentTextColor() {
+            return mOnTertiaryFixedAccentTextColor;
+        }
+
         /**
          * @return the contrast-adjusted version of the color provided by the app, or the
          * primary text color when colorized.
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index a5e5135..70c25ea 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -34,8 +34,8 @@
     void unregisterTrustListener(in ITrustListener trustListener);
     void reportKeyguardShowingChanged();
     void setDeviceLockedForUser(int userId, boolean locked);
-    boolean isDeviceLocked(int userId, int displayId);
-    boolean isDeviceSecure(int userId, int displayId);
+    boolean isDeviceLocked(int userId, int deviceId);
+    boolean isDeviceSecure(int userId, int deviceId);
     @EnforcePermission("TRUST_LISTENER")
     boolean isTrustUsuallyManaged(int userId);
     void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index aefa55f..323592c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1204,12 +1204,15 @@
     /**
      * This change id is the gatekeeper for all treatments that force a given min aspect ratio.
      * Enabling this change will allow the following min aspect ratio treatments to be applied:
-     * OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
-     * OVERRIDE_MIN_ASPECT_RATIO_LARGE
+     * <ul>
+     *  <li>OVERRIDE_MIN_ASPECT_RATIO_MEDIUM
+     *  <li>OVERRIDE_MIN_ASPECT_RATIO_LARGE
+     * </ul>
      *
      * If OVERRIDE_MIN_ASPECT_RATIO is applied, the min aspect ratio given in the app's manifest
      * will be overridden to the largest enabled aspect ratio treatment unless the app's manifest
-     * value is higher.
+     * value is higher. By default, this will only apply to activities with fixed portrait
+     * orientation if OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY is not explicitly disabled.
      * @hide
      */
     @ChangeId
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index cd8938d..cbb20e0 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2535,6 +2535,8 @@
         public DataLoaderParams dataLoaderParams;
         /** {@hide} */
         public int rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
+        /** @hide */
+        public long rollbackLifetimeMillis = 0;
         /** {@hide} */
         public boolean forceQueryableOverride;
         /** {@hide} */
@@ -2589,6 +2591,7 @@
                 dataLoaderParams = new DataLoaderParams(dataLoaderParamsParcel);
             }
             rollbackDataPolicy = source.readInt();
+            rollbackLifetimeMillis = source.readLong();
             requireUserAction = source.readInt();
             packageSource = source.readInt();
             applicationEnabledSettingPersistent = source.readBoolean();
@@ -2621,6 +2624,7 @@
             ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
             ret.dataLoaderParams = dataLoaderParams;
             ret.rollbackDataPolicy = rollbackDataPolicy;
+            ret.rollbackLifetimeMillis = rollbackLifetimeMillis;
             ret.requireUserAction = requireUserAction;
             ret.packageSource = packageSource;
             ret.applicationEnabledSettingPersistent = applicationEnabledSettingPersistent;
@@ -2902,12 +2906,7 @@
          */
         @SystemApi
         public void setEnableRollback(boolean enable) {
-            if (enable) {
-                installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
-            } else {
-                installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
-            }
-            rollbackDataPolicy = PackageManager.ROLLBACK_DATA_POLICY_RESTORE;
+            setEnableRollback(enable, PackageManager.ROLLBACK_DATA_POLICY_RESTORE);
         }
 
         /**
@@ -2931,10 +2930,36 @@
                 installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
             } else {
                 installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+                rollbackLifetimeMillis = 0;
             }
             rollbackDataPolicy = dataPolicy;
         }
 
+        /**
+         * If rollback enabled for this session (via {@link #setEnableRollback}, set time
+         * after which rollback will no longer be possible
+         *
+         * <p>For multi-package installs, this value must be set on the parent session.
+         * Child session rollback lifetime will be ignored.
+         *
+         * @param lifetimeMillis time after which rollback expires
+         * @throws IllegalArgumentException if lifetimeMillis is negative or rollback is not
+         * enabled via setEnableRollback.
+         * @hide
+         */
+        @SystemApi
+        @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+        @FlaggedApi(Flags.FLAG_ROLLBACK_LIFETIME)
+        public void setRollbackLifetimeMillis(@DurationMillisLong long lifetimeMillis) {
+            if (lifetimeMillis < 0) {
+                throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative.");
+            }
+            if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
+                throw new IllegalArgumentException(
+                        "Can't set rollbackLifetimeMillis when rollback is not enabled");
+            }
+            rollbackLifetimeMillis = lifetimeMillis;
+        }
 
         /**
          * @deprecated use {@link #setRequestDowngrade(boolean)}.
@@ -3295,6 +3320,7 @@
             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
             pw.printPair("dataLoaderParams", dataLoaderParams);
             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
+            pw.printPair("rollbackLifetimeMillis", rollbackLifetimeMillis);
             pw.printPair("applicationEnabledSettingPersistent",
                     applicationEnabledSettingPersistent);
             pw.printHexPair("developmentInstallFlags", developmentInstallFlags);
@@ -3336,6 +3362,7 @@
                 dest.writeParcelable(null, flags);
             }
             dest.writeInt(rollbackDataPolicy);
+            dest.writeLong(rollbackLifetimeMillis);
             dest.writeInt(requireUserAction);
             dest.writeInt(packageSource);
             dest.writeBoolean(applicationEnabledSettingPersistent);
@@ -3529,6 +3556,9 @@
         /** {@hide} */
         public int rollbackDataPolicy;
 
+        /** @hide */
+        public long rollbackLifetimeMillis;
+
         /** {@hide} */
         public int requireUserAction;
 
@@ -3596,6 +3626,7 @@
             isCommitted = source.readBoolean();
             isPreapprovalRequested = source.readBoolean();
             rollbackDataPolicy = source.readInt();
+            rollbackLifetimeMillis = source.readLong();
             createdMillis = source.readLong();
             requireUserAction = source.readInt();
             installerUid = source.readInt();
@@ -4220,6 +4251,7 @@
             dest.writeBoolean(isCommitted);
             dest.writeBoolean(isPreapprovalRequested);
             dest.writeInt(rollbackDataPolicy);
+            dest.writeLong(rollbackLifetimeMillis);
             dest.writeLong(createdMillis);
             dest.writeInt(requireUserAction);
             dest.writeInt(installerUid);
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index 96609ad..9ad66ce 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -58,3 +58,11 @@
     bug: "295827951"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "rollback_lifetime"
+    namespace: "package_manager_service"
+    description: "Feature flag to enable custom rollback lifetime during install."
+    bug: "299670324"
+    is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 3ec239c..43cf97f 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -28,3 +28,10 @@
     description: "Framework support for communal profile."
     bug: "285426179"
 }
+
+flag {
+    name: "support_communal_profile_nextgen"
+    namespace: "multiuser"
+    description: "Further framework support for communal profile, beyond the basics, for later releases."
+    bug: "285426179"
+}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index a40fb15..66e3c28 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,10 +16,12 @@
 package android.net.vcn;
 
 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG;
 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -235,6 +237,9 @@
             "mMinUdpPort4500NatTimeoutSeconds";
     private final int mMinUdpPort4500NatTimeoutSeconds;
 
+    private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled";
+    private final boolean mIsSafeModeDisabled;
+
     private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions";
     @NonNull private final Set<Integer> mGatewayOptions;
 
@@ -247,6 +252,7 @@
             @NonNull long[] retryIntervalsMs,
             @IntRange(from = MIN_MTU_V6) int maxMtu,
             @NonNull int minUdpPort4500NatTimeoutSeconds,
+            boolean isSafeModeDisabled,
             @NonNull Set<Integer> gatewayOptions) {
         mGatewayConnectionName = gatewayConnectionName;
         mTunnelConnectionParams = tunnelConnectionParams;
@@ -255,6 +261,7 @@
         mMaxMtu = maxMtu;
         mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
         mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions));
+        mIsSafeModeDisabled = isSafeModeDisabled;
 
         mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates);
         if (mUnderlyingNetworkTemplates.isEmpty()) {
@@ -317,6 +324,7 @@
                 in.getInt(
                         MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY,
                         MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
+        mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY);
 
         validate();
     }
@@ -483,6 +491,17 @@
     }
 
     /**
+     * Check whether safe mode is enabled
+     *
+     * @see Builder#enableSafeMode(boolean)
+     * @hide
+     */
+    @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
+    public boolean isSafeModeEnabled() {
+        return !mIsSafeModeDisabled;
+    }
+
+    /**
      * Checks if the given VCN gateway option is enabled.
      *
      * @param option the option to check.
@@ -528,6 +547,7 @@
         result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
         result.putInt(MAX_MTU_KEY, mMaxMtu);
         result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds);
+        result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled);
 
         return result;
     }
@@ -542,6 +562,7 @@
                 Arrays.hashCode(mRetryIntervalsMs),
                 mMaxMtu,
                 mMinUdpPort4500NatTimeoutSeconds,
+                mIsSafeModeDisabled,
                 mGatewayOptions);
     }
 
@@ -559,6 +580,7 @@
                 && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
                 && mMaxMtu == rhs.mMaxMtu
                 && mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds
+                && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled
                 && mGatewayOptions.equals(rhs.mGatewayOptions);
     }
 
@@ -577,6 +599,7 @@
         @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
         private int mMaxMtu = DEFAULT_MAX_MTU;
         private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
+        private boolean mIsSafeModeDisabled = false;
 
         @NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>();
 
@@ -789,6 +812,28 @@
         }
 
         /**
+         * Enable/disable safe mode
+         *
+         * <p>If a VCN fails to provide connectivity within a system-provided timeout, it will enter
+         * safe mode. In safe mode, the VCN Network will be torn down and the system will restore
+         * connectivity by allowing underlying cellular networks to be used as default. At the same
+         * time, VCN will continue to retry until it succeeds.
+         *
+         * <p>When safe mode is disabled and VCN connection fails to provide connectivity, end users
+         * might not have connectivity, and may not have access to carrier-owned underlying
+         * networks.
+         *
+         * @param enabled whether safe mode should be enabled. Defaults to {@code true}
+         * @hide
+         */
+        @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
+        @NonNull
+        public Builder enableSafeMode(boolean enabled) {
+            mIsSafeModeDisabled = !enabled;
+            return this;
+        }
+
+        /**
          * Builds and validates the VcnGatewayConnectionConfig.
          *
          * @return an immutable VcnGatewayConnectionConfig instance
@@ -803,6 +848,7 @@
                     mRetryIntervalsMs,
                     mMaxMtu,
                     mMinUdpPort4500NatTimeoutSeconds,
+                    mIsSafeModeDisabled,
                     mGatewayOptions);
         }
     }
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 58def6e..960e84d 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -26,6 +26,7 @@
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.UserHandleAware;
 import android.annotation.WorkerThread;
 import android.app.ActivityManager;
 import android.content.Context;
@@ -280,8 +281,8 @@
      *
      * <p>{@link BugreportManager} takes ownership of {@code bugreportFd}.
      *
-     * <p>The caller may only request to retrieve a given bugreport once. Subsequent calls will fail
-     * with error code {@link BugreportCallback#BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE}.
+     * <p>The caller can reattempt to retrieve the bugreport multiple times if the user has not
+     * consented on previous attempts.
      *
      * @param bugreportFile the identifier for a bugreport that was previously generated for this
      *      caller using {@code startBugreport}.
@@ -294,6 +295,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.DUMP)
     @WorkerThread
+    @UserHandleAware
     public void retrieveBugreport(
             @NonNull String bugreportFile,
             @NonNull ParcelFileDescriptor bugreportFd,
@@ -307,8 +309,10 @@
             Preconditions.checkNotNull(callback);
             DumpstateListener dsListener = new DumpstateListener(executor, callback, false, false);
             mBinder.retrieveBugreport(Binder.getCallingUid(), mContext.getOpPackageName(),
+                    mContext.getUserId(),
                     bugreportFd.getFileDescriptor(),
                     bugreportFile,
+                    /* keepBugreportOnRetrieval = */ false,
                     dsListener);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index e8ad303..8510084 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.admin.flags.Flags;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -128,6 +129,8 @@
      *
      * @hide
      */
+    @TestApi
+    @FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
     public static final int BUGREPORT_MODE_ONBOARDING = IDumpstate.BUGREPORT_MODE_ONBOARDING;
 
     /**
@@ -145,7 +148,8 @@
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, prefix = { "BUGREPORT_FLAG_" }, value = {
             BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA,
-            BUGREPORT_FLAG_DEFER_CONSENT
+            BUGREPORT_FLAG_DEFER_CONSENT,
+            BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL
     })
     public @interface BugreportFlag {}
 
@@ -165,4 +169,20 @@
      * String, ParcelFileDescriptor, Executor, BugreportManager.BugreportCallback)}.
      */
     public static final int BUGREPORT_FLAG_DEFER_CONSENT = IDumpstate.BUGREPORT_FLAG_DEFER_CONSENT;
+
+    /**
+     * Flag for keeping a bugreport stored even after it has been retrieved via
+     * {@link BugreportManager#retrieveBugreport}.
+     *
+     * <p>This flag can only be used when {@link #BUGREPORT_FLAG_DEFER_CONSENT} is set.
+     * The bugreport may be retrieved multiple times using
+     * {@link BugreportManager#retrieveBugreport(
+     * String, ParcelFileDescriptor, Executor, BugreportManager.BugreportCallback)}.
+     *
+     * @hide
+     */
+    @TestApi
+    @FlaggedApi(Flags.FLAG_ONBOARDING_BUGREPORT_V2_ENABLED)
+    public static final int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL =
+            IDumpstate.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL;
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 839c56f..330b992 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -137,6 +137,7 @@
     boolean isUserVisible(int userId);
     int[] getVisibleUsers();
     int getMainDisplayIdAssignedToUser();
+    boolean isForegroundUserAdmin();
     boolean isUserNameSet(int userId);
     boolean hasRestrictedProfiles(int userId);
     boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userId, in IntentSender target, int flags);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 72bc211..cc79ae3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2774,6 +2774,8 @@
      * Returns the designated "communal profile" of the device, or {@code null} if there is none.
      * @hide
      */
+    @FlaggedApi(android.multiuser.Flags.FLAG_SUPPORT_COMMUNAL_PROFILE)
+    @TestApi
     @RequiresPermission(anyOf = {
             Manifest.permission.MANAGE_USERS,
             Manifest.permission.CREATE_USERS,
@@ -2791,16 +2793,33 @@
     }
 
     /**
+     * Checks if the context user is running in a communal profile.
+     *
+     * A communal profile is a {@link #isProfile() profile}, but instead of being associated with a
+     * particular parent user, it is communal to the device.
+     *
+     * @return whether the context user is a communal profile.
+     */
+    @FlaggedApi(android.multiuser.Flags.FLAG_SUPPORT_COMMUNAL_PROFILE)
+    @UserHandleAware(
+            requiresAnyOfPermissionsIfNotCallerProfileGroup = {
+                    android.Manifest.permission.MANAGE_USERS,
+                    android.Manifest.permission.QUERY_USERS,
+                    android.Manifest.permission.INTERACT_ACROSS_USERS})
+    public boolean isCommunalProfile() {
+        return isCommunalProfile(mUserId);
+    }
+
+    /**
      * Returns {@code true} if the given user is the designated "communal profile" of the device.
      * @hide
      */
     @RequiresPermission(anyOf = {
-            Manifest.permission.MANAGE_USERS,
-            Manifest.permission.CREATE_USERS,
-            Manifest.permission.QUERY_USERS})
-    public boolean isCommunalProfile(@UserIdInt int userId) {
-        final UserInfo user = getUserInfo(userId);
-        return user != null && user.isCommunalProfile();
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.QUERY_USERS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+    private boolean isCommunalProfile(@UserIdInt int userId) {
+        return isUserTypeCommunalProfile(getProfileType(userId));
     }
 
     /**
@@ -2840,6 +2859,23 @@
     }
 
     /**
+     * Used to check if the user currently running in the <b>foreground</b> is an
+     * {@link #isAdminUser() admin} user.
+     *
+     * @return whether the foreground user is an admin user.
+     * @see #isAdminUser()
+     * @see #isUserForeground()
+     */
+    @FlaggedApi(android.multiuser.Flags.FLAG_SUPPORT_COMMUNAL_PROFILE_NEXTGEN)
+    public boolean isForegroundUserAdmin() {
+        try {
+            return mService.isForegroundUserAdmin();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns whether the context user is of the given user type.
      *
      * @param userType the name of the user's user type, e.g.
@@ -2997,7 +3033,7 @@
     }
 
     /**
-     * Checks if the calling context user can have a restricted profile.
+     * Checks if the context user can have a restricted profile.
      * @return whether the context user can have a restricted profile.
      * @hide
      */
@@ -3101,11 +3137,11 @@
     }
 
     /**
-     * Checks if the calling context user is running in a profile. A profile is a user that
+     * Checks if the context user is running in a profile. A profile is a user that
      * typically has its own separate data but shares its UI with some parent user. For example, a
      * {@link #isManagedProfile() managed profile} is a type of profile.
      *
-     * @return whether the caller is in a profile.
+     * @return whether the context user is in a profile.
      */
     @UserHandleAware(
             requiresAnyOfPermissionsIfNotCallerProfileGroup = {
@@ -5247,7 +5283,7 @@
 
     /**
      * Returns the parent of the profile which this method is called from
-     * or null if called from a user that is not a profile.
+     * or null if it has no parent (e.g. if it is not a profile).
      *
      * @hide
      */
@@ -5269,7 +5305,7 @@
      *
      * @param user the handle of the user profile
      *
-     * @return the parent of the user or {@code null} if the user is not profile
+     * @return the parent of the user or {@code null} if the user has no parent
      *
      * @hide
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index be4693b..4da02f9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -11612,7 +11612,14 @@
             Log.d(mTag, "registerCallbacksForSync syncBuffer=" + syncBuffer);
         }
 
-        surfaceSyncGroup.addTransaction(mPendingTransaction);
+        final Transaction t;
+        if (mHasPendingTransactions) {
+            t = new Transaction();
+            t.merge(mPendingTransaction);
+        } else {
+            t = null;
+        }
+
         mAttachInfo.mThreadedRenderer.registerRtFrameCallback(new FrameDrawingCallback() {
             @Override
             public void onFrameDraw(long frame) {
@@ -11625,6 +11632,9 @@
                             "Received frameDrawingCallback syncResult=" + syncResult + " frameNum="
                                     + frame + ".");
                 }
+                if (t != null) {
+                    mergeWithNextTransaction(t, frame);
+                }
 
                 // If the syncResults are SYNC_LOST_SURFACE_REWARD_IF_FOUND or
                 // SYNC_CONTEXT_IS_STOPPED it means nothing will draw. There's no need to set up
diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java
index 841354a..e6eeca4 100644
--- a/core/java/android/window/TaskFragmentParentInfo.java
+++ b/core/java/android/window/TaskFragmentParentInfo.java
@@ -35,17 +35,21 @@
 
     private final boolean mVisible;
 
+    private final boolean mHasDirectActivity;
+
     public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
-            boolean visible) {
+            boolean visible, boolean hasDirectActivity) {
         mConfiguration.setTo(configuration);
         mDisplayId = displayId;
         mVisible = visible;
+        mHasDirectActivity = hasDirectActivity;
     }
 
     public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
         mConfiguration.setTo(info.getConfiguration());
         mDisplayId = info.mDisplayId;
         mVisible = info.mVisible;
+        mHasDirectActivity = info.mHasDirectActivity;
     }
 
     /** The {@link Configuration} of the parent Task */
@@ -68,6 +72,14 @@
     }
 
     /**
+     * Whether the parent Task has any direct child activity, which is not embedded in any
+     * TaskFragment, or not
+     */
+    public boolean hasDirectActivity() {
+        return mHasDirectActivity;
+    }
+
+    /**
      * Returns {@code true} if the parameters which are important for task fragment
      * organizers are equal between this {@link TaskFragmentParentInfo} and {@code that}.
      * Note that this method is usually called with
@@ -80,7 +92,7 @@
             return false;
         }
         return getWindowingMode() == that.getWindowingMode() && mDisplayId == that.mDisplayId
-                && mVisible == that.mVisible;
+                && mVisible == that.mVisible && mHasDirectActivity == that.mHasDirectActivity;
     }
 
     @WindowConfiguration.WindowingMode
@@ -94,6 +106,7 @@
                 + "config=" + mConfiguration
                 + ", displayId=" + mDisplayId
                 + ", visible=" + mVisible
+                + ", hasDirectActivity=" + mHasDirectActivity
                 + "}";
     }
 
@@ -114,7 +127,8 @@
         final TaskFragmentParentInfo that = (TaskFragmentParentInfo) obj;
         return mConfiguration.equals(that.mConfiguration)
                 && mDisplayId == that.mDisplayId
-                && mVisible == that.mVisible;
+                && mVisible == that.mVisible
+                && mHasDirectActivity == that.mHasDirectActivity;
     }
 
     @Override
@@ -122,6 +136,7 @@
         int result = mConfiguration.hashCode();
         result = 31 * result + mDisplayId;
         result = 31 * result + (mVisible ? 1 : 0);
+        result = 31 * result + (mHasDirectActivity ? 1 : 0);
         return result;
     }
 
@@ -130,12 +145,14 @@
         mConfiguration.writeToParcel(dest, flags);
         dest.writeInt(mDisplayId);
         dest.writeBoolean(mVisible);
+        dest.writeBoolean(mHasDirectActivity);
     }
 
     private TaskFragmentParentInfo(Parcel in) {
         mConfiguration.readFromParcel(in);
         mDisplayId = in.readInt();
         mVisible = in.readBoolean();
+        mHasDirectActivity = in.readBoolean();
     }
 
     public static final Creator<TaskFragmentParentInfo> CREATOR =
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 584dd80..492e2ac 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -20,6 +20,7 @@
 import android.app.AsyncNotedAppOp;
 import android.app.SyncNotedAppOp;
 import android.app.RuntimeAppOpAccessMessage;
+import android.content.AttributionSource;
 import android.content.AttributionSourceState;
 import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
@@ -32,10 +33,17 @@
 import com.android.internal.app.IAppOpsStartedCallback;
 import com.android.internal.app.MessageSamplingConfig;
 
+// AppOpsService AIDL interface.
+// PLEASE READ BEFORE MODIFYING THIS FILE.
+// Some methods in this interface or their transaction codes are mentioned in
+// frameworks/base/boot/hiddenapi/hiddenapi-unsupported.txt, meaning that we cannot change their
+// signature or ordering as they may be used by 3p apps.
+// Also, some methods are mentioned in native code, meaning that the numbering in
+// frameworks/native/libs/permission/include/binder/IAppOpsService.h must match the order here.
+// Please be careful to respect both these issues when modifying this file.
 interface IAppOpsService {
-    // These methods are also called by native code, so must
-    // be kept in sync with frameworks/native/libs/permission/include/binder/IAppOpsService.h
-    // and not be reordered
+    // These methods are also called by native code, so please be careful that the number in
+    // frameworks/native/libs/permission/include/binder/IAppOpsService.h matches the ordering here.
     int checkOperation(int code, int uid, String packageName);
     SyncNotedAppOp noteOperation(int code, int uid, String packageName, @nullable String attributionTag,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
@@ -54,21 +62,21 @@
     void setCameraAudioRestriction(int mode);
     void startWatchingModeWithFlags(int op, String packageName, int flags,
             IAppOpsCallback callback);
-    // End of methods also called by native code.
-    // Any new method exposed to native must be added after the last one, do not reorder
-
-    SyncNotedAppOp noteProxyOperation(int code, in AttributionSourceState attributionSourceState,
+    // End of methods also called by native code (there may be more blocks like this of native
+    // methods later in this file).
+    // Deprecated, use noteProxyOperationWithState instead.
+    SyncNotedAppOp noteProxyOperation(int code, in AttributionSource attributionSource,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
             boolean skipProxyOperation);
+    // Deprecated, use startProxyOperationWithState instead.
     SyncNotedAppOp startProxyOperation(IBinder clientId, int code,
-            in AttributionSourceState attributionSourceState, boolean startIfModeDefault,
+            in AttributionSource attributionSource, boolean startIfModeDefault,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
             boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags,
             int attributionChainId);
-    void finishProxyOperation(IBinder clientId, int code,
-            in AttributionSourceState attributionSourceState, boolean skipProxyOperation);
-
-    // Remaining methods are only used in Java.
+    // Deprecated, use finishProxyOperationWithState instead.
+    void finishProxyOperation(IBinder clientId, int code, in AttributionSource attributionSource,
+            boolean skipProxyOperation);
     int checkPackage(int uid, String packageName);
     RuntimeAppOpAccessMessage collectRuntimeAppOpAccessMessage();
     MessageSamplingConfig reportRuntimeAppOpAccessMessageAndGetConfig(String packageName,
@@ -127,8 +135,19 @@
     List<AsyncNotedAppOp> extractAsyncOps(String packageName);
 
     int checkOperationRaw(int code, int uid, String packageName, @nullable String attributionTag);
-
     void reloadNonHistoricalState();
 
     void collectNoteOpCallsForValidation(String stackTrace, int op, String packageName, long version);
+
+    SyncNotedAppOp noteProxyOperationWithState(int code,
+                in AttributionSourceState attributionSourceStateState,
+                boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+                boolean skipProxyOperation);
+    SyncNotedAppOp startProxyOperationWithState(IBinder clientId, int code,
+                in AttributionSourceState attributionSourceStateState, boolean startIfModeDefault,
+                boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+                boolean skipProxyOperation, int proxyAttributionFlags, int proxiedAttributionFlags,
+                int attributionChainId);
+    void finishProxyOperationWithState(IBinder clientId, int code,
+                in AttributionSourceState attributionSourceStateState, boolean skipProxyOperation);
 }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 965277c..1c5f4f0 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -868,6 +868,11 @@
                                  args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
                                  args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
 
+            // While `specializeAppProcess` sets the thread name on the process's main thread, this
+            // is distinct from the app process name which appears in stack traces, as the latter is
+            // sourced from the argument buffer of the Process class. Set the app process name here.
+            Zygote.setAppProcessName(args, TAG);
+
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
             return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 993e4e7..5fe086d 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -296,7 +296,6 @@
                     } else {
                         // child; result is a Runnable.
                         zygoteServer.setForkChild();
-                        Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?
                         return result;
                     }
                 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 8d11672..a3e0016 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1105,10 +1105,9 @@
     @UnsupportedAppUsage
     public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
         final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
-        if (isSpecialUserId(userId)) {
-            // For secure password storage (that is required for special users such as FRP), the
-            // underlying storage also enforces the deadline. Since we cannot store settings
-            // for special users, don't.
+        if (userId == USER_FRP) {
+            // For secure password storage (that is required for FRP), the underlying storage also
+            // enforces the deadline. Since we cannot store settings for the FRP user, don't.
             return deadline;
         }
         mLockoutDeadlines.put(userId, deadline);
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 03e9a6a..1b24efa 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -39,7 +39,7 @@
     explicit VelocityTrackerState(const VelocityTracker::Strategy strategy);
 
     void clear();
-    void addMovement(const MotionEvent* event);
+    void addMovement(const MotionEvent& event);
     // TODO(b/32830165): consider supporting an overload that supports computing velocity only for
     // a subset of the supported axes.
     void computeCurrentVelocity(int32_t units, float maxVelocity);
@@ -57,7 +57,7 @@
     mVelocityTracker.clear();
 }
 
-void VelocityTrackerState::addMovement(const MotionEvent* event) {
+void VelocityTrackerState::addMovement(const MotionEvent& event) {
     mVelocityTracker.addMovement(event);
 }
 
@@ -102,13 +102,13 @@
 static void android_view_VelocityTracker_nativeAddMovement(JNIEnv* env, jclass clazz, jlong ptr,
         jobject eventObj) {
     const MotionEvent* event = android_view_MotionEvent_getNativePtr(env, eventObj);
-    if (!event) {
+    if (event == nullptr) {
         LOG(WARNING) << "nativeAddMovement failed because MotionEvent was finalized.";
         return;
     }
 
     VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
-    state->addMovement(event);
+    state->addMovement(*event);
 }
 
 static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* env, jclass clazz,
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index a6830a6..c0c6e05 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -135,11 +135,12 @@
     <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
     <drawable name="notification_template_divider">#29000000</drawable>
     <drawable name="notification_template_divider_media">#29ffffff</drawable>
-    <color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
-    <color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
-    <color name="notification_secondary_text_color_light">@color/primary_text_default_material_light</color>
+    <color name="notification_primary_text_color_light">@color/system_on_surface_light</color>
+    <color name="notification_primary_text_color_dark">@color/system_on_surface_dark</color>
+    <!-- Note that the primary and secondary notification text colors are, in fact, the same. -->
+    <color name="notification_secondary_text_color_light">@color/system_on_surface_light</color>
+    <color name="notification_secondary_text_color_dark">@color/system_on_surface_dark</color>
     <item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.38</item>
-    <color name="notification_secondary_text_color_dark">@color/primary_text_default_material_dark</color>
     <color name="notification_default_color_dark">#ddffffff</color>
     <color name="notification_default_color_light">#a3202124</color>
 
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 72969f7..37a499a 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -104,19 +104,15 @@
     private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
 
     private static final Path[] UI_TRACES_PREDUMPED = {
+            Paths.get("/data/misc/perfetto-traces/bugreport/systrace.pftrace"),
             Paths.get("/data/misc/wmtrace/ime_trace_clients.winscope"),
             Paths.get("/data/misc/wmtrace/ime_trace_managerservice.winscope"),
             Paths.get("/data/misc/wmtrace/ime_trace_service.winscope"),
             Paths.get("/data/misc/wmtrace/wm_trace.winscope"),
             Paths.get("/data/misc/wmtrace/wm_log.winscope"),
-            Paths.get("/data/misc/wmtrace/layers_trace.winscope"),
-            Paths.get("/data/misc/wmtrace/transactions_trace.winscope"),
-            Paths.get("/data/misc/wmtrace/transition_trace.winscope"),
+            Paths.get("/data/misc/wmtrace/wm_transition_trace.winscope"),
             Paths.get("/data/misc/wmtrace/shell_transition_trace.winscope"),
     };
-    private static final Path[] UI_TRACES_GENERATED_DURING_BUGREPORT = {
-            Paths.get("/data/misc/wmtrace/layers_trace_from_transactions.winscope"),
-    };
 
     private Handler mHandler;
     private Executor mExecutor;
@@ -210,7 +206,7 @@
 
         mBrm.preDumpUiData();
         waitTillDumpstateExitedOrTimeout();
-        List<File> expectedPreDumpedTraceFiles = copyFilesAsRoot(UI_TRACES_PREDUMPED);
+        List<File> expectedPreDumpedTraceFiles = copyFiles(UI_TRACES_PREDUMPED);
 
         BugreportCallbackImpl callback = new BugreportCallbackImpl();
         mBrm.startBugreport(mBugreportFd, null, fullWithUsePreDumpFlag(), mExecutor,
@@ -225,7 +221,6 @@
         assertFdsAreClosed(mBugreportFd);
 
         assertThatBugreportContainsFiles(UI_TRACES_PREDUMPED);
-        assertThatBugreportContainsFiles(UI_TRACES_GENERATED_DURING_BUGREPORT);
 
         List<File> actualPreDumpedTraceFiles = extractFilesFromBugreport(UI_TRACES_PREDUMPED);
         assertThatAllFileContentsAreEqual(actualPreDumpedTraceFiles, expectedPreDumpedTraceFiles);
@@ -240,9 +235,9 @@
         // In some corner cases, data dumped as part of the full bugreport could be the same as the
         // pre-dumped data and this test would fail. Hence, here we create fake/artificial
         // pre-dumped data that we know it won't match with the full bugreport data.
-        createFilesWithFakeDataAsRoot(UI_TRACES_PREDUMPED, "system");
+        createFakeTraceFiles(UI_TRACES_PREDUMPED);
 
-        List<File> preDumpedTraceFiles = copyFilesAsRoot(UI_TRACES_PREDUMPED);
+        List<File> preDumpedTraceFiles = copyFiles(UI_TRACES_PREDUMPED);
 
         BugreportCallbackImpl callback = new BugreportCallbackImpl();
         mBrm.startBugreport(mBugreportFd, null, full(), mExecutor,
@@ -257,7 +252,6 @@
         assertFdsAreClosed(mBugreportFd);
 
         assertThatBugreportContainsFiles(UI_TRACES_PREDUMPED);
-        assertThatBugreportContainsFiles(UI_TRACES_GENERATED_DURING_BUGREPORT);
 
         List<File> actualTraceFiles = extractFilesFromBugreport(UI_TRACES_PREDUMPED);
         assertThatAllFileContentsAreDifferent(preDumpedTraceFiles, actualTraceFiles);
@@ -480,7 +474,32 @@
         return f;
     }
 
-    private static void startPreDumpedUiTraces() {
+    private static void startPreDumpedUiTraces() throws Exception {
+        // Perfetto traces
+        String perfettoConfig =
+                "buffers: {\n"
+                + "    size_kb: 2048\n"
+                + "    fill_policy: RING_BUFFER\n"
+                + "}\n"
+                + "data_sources: {\n"
+                + "    config {\n"
+                + "        name: \"android.surfaceflinger.transactions\"\n"
+                + "    }\n"
+                + "}\n"
+                + "bugreport_score: 10\n";
+        File tmp = createTempFile("tmp", ".cfg");
+        Files.write(perfettoConfig.getBytes(StandardCharsets.UTF_8), tmp);
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "install -m 644 -o root -g root "
+                + tmp.getAbsolutePath() + " /data/misc/perfetto-configs/bugreport-manager-test.cfg"
+        );
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "perfetto --background-wait"
+                + " --config /data/misc/perfetto-configs/bugreport-manager-test.cfg --txt"
+                + " --out /data/misc/perfetto-traces/not-used.perfetto-trace"
+        );
+
+        // Legacy traces
         InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
                 "cmd input_method tracing start"
         );
@@ -563,19 +582,24 @@
         return extractedFile;
     }
 
-    private static void createFilesWithFakeDataAsRoot(Path[] paths, String owner) throws Exception {
+    private static void createFakeTraceFiles(Path[] paths) throws Exception {
         File src = createTempFile("fake", ".data");
         Files.write("fake data".getBytes(StandardCharsets.UTF_8), src);
 
         for (Path path : paths) {
             InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
-                    "install -m 611 -o " + owner + " -g " + owner
-                    + " " + src.getAbsolutePath() + " " + path.toString()
+                    "install -m 644 -o system -g system "
+                    + src.getAbsolutePath() + " " + path.toString()
             );
         }
+
+        // Dumpstate executes "perfetto --save-for-bugreport" as shell
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "chown shell:shell /data/misc/perfetto-traces/bugreport/systrace.pftrace"
+        );
     }
 
-    private static List<File> copyFilesAsRoot(Path[] paths) throws Exception {
+    private static List<File> copyFiles(Path[] paths) throws Exception {
         ArrayList<File> files = new ArrayList<File>();
         for (Path src : paths) {
             File dst = createTempFile(src.getFileName().toString(), ".copy");
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 9430ba6..1577d9c1c1 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -859,6 +859,10 @@
             assertEquals(cDay.getTertiaryAccentColor(), cNight.getTertiaryAccentColor());
             assertEquals(cDay.getOnTertiaryAccentTextColor(),
                     cNight.getOnTertiaryAccentTextColor());
+            assertEquals(cDay.getTertiaryFixedDimAccentColor(),
+                    cNight.getTertiaryFixedDimAccentColor());
+            assertEquals(cDay.getOnTertiaryFixedAccentTextColor(),
+                    cNight.getOnTertiaryFixedAccentTextColor());
             assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
             assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
             assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
@@ -1832,6 +1836,8 @@
         assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getTertiaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getOnTertiaryAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getTertiaryFixedDimAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getOnTertiaryFixedAccentTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
         assertThat(c.getRippleAlpha()).isAtLeast(0x00);
@@ -1847,9 +1853,12 @@
         // These colors are only used for emphasized buttons; they do not need contrast
         assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
         assertContrastIsAtLeast(c.getTertiaryAccentColor(), c.getBackgroundColor(), 1);
+        assertContrastIsAtLeast(c.getTertiaryFixedDimAccentColor(), c.getBackgroundColor(), 1);
 
         // The text that is used within the accent color DOES need to have contrast
         assertContrastIsAtLeast(c.getOnTertiaryAccentTextColor(), c.getTertiaryAccentColor(), 4.5);
+        assertContrastIsAtLeast(c.getOnTertiaryFixedAccentTextColor(),
+                c.getTertiaryFixedDimAccentColor(), 4.5);
     }
 
     private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor,
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 06b62f8..dd116b5 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -33,6 +33,7 @@
 
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.endsWith;
+import static org.junit.Assume.assumeFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -119,6 +120,11 @@
 
     @Before
     public void setUp() throws Exception {
+        final PackageManager pm =
+                InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
+        assumeFalse("AccessibilityShortcutChooserActivity not supported on watch",
+                pm.hasSystemFeature(PackageManager.FEATURE_WATCH));
+
         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         mDevice.wakeUp();
         when(mAccessibilityServiceInfo.getResolveInfo()).thenReturn(mResolveInfo);
@@ -138,7 +144,9 @@
 
     @After
     public void cleanUp() {
-        mScenario.close();
+        if (mScenario != null) {
+            mScenario.close();
+        }
     }
 
     @Test
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 49606f0..7743ad5 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -1763,6 +1763,15 @@
             return;
         }
 
+        if (container.isFinished()) {
+            return;
+        }
+
+        if (container.isOverlay()) {
+            updateOverlayContainer(wct, container);
+            return;
+        }
+
         if (launchPlaceholderIfNecessary(wct, container)) {
             // Placeholder was launched, the positions will be updated when the activity is added
             // to the secondary container.
@@ -1783,6 +1792,25 @@
         updateSplitContainerIfNeeded(splitContainer, wct, null /* splitAttributes */);
     }
 
+
+    @VisibleForTesting
+    // Suppress GuardedBy warning because lint ask to mark this method as
+    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
+    @SuppressWarnings("GuardedBy")
+    @GuardedBy("mLock")
+    void updateOverlayContainer(@NonNull WindowContainerTransaction wct,
+                                @NonNull TaskFragmentContainer container) {
+        final TaskContainer taskContainer = container.getTaskContainer();
+        // Dismiss the overlay container if it's the only container in the task and there's no
+        // direct activity in the parent task.
+        if (taskContainer.getTaskFragmentContainers().size() == 1
+                && !taskContainer.hasDirectActivity()) {
+            container.finish(false /* shouldFinishDependent */, mPresenter, wct, this);
+        }
+
+        // TODO(b/295805054): Add the logic to update overlay container
+    }
+
     /**
      * Updates {@link SplitContainer} with the given {@link SplitAttributes} if the
      * {@link SplitContainer} is the top most and not finished. If passed {@link SplitAttributes}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 9e53380..eeb3ccf 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -75,6 +75,8 @@
 
     private boolean mIsVisible;
 
+    private boolean mHasDirectActivity;
+
     /**
      * TaskFragments that the organizer has requested to be closed. They should be removed when
      * the organizer receives
@@ -102,8 +104,9 @@
         mConfiguration = taskProperties.getConfiguration();
         mDisplayId = taskProperties.getDisplayId();
         // Note that it is always called when there's a new Activity is started, which implies
-        // the host task is visible.
+        // the host task is visible and has an activity in the task.
         mIsVisible = true;
+        mHasDirectActivity = true;
     }
 
     int getTaskId() {
@@ -118,6 +121,10 @@
         return mIsVisible;
     }
 
+    boolean hasDirectActivity() {
+        return mHasDirectActivity;
+    }
+
     @NonNull
     TaskProperties getTaskProperties() {
         return new TaskProperties(mDisplayId, mConfiguration);
@@ -127,6 +134,7 @@
         mConfiguration.setTo(info.getConfiguration());
         mDisplayId = info.getDisplayId();
         mIsVisible = info.isVisible();
+        mHasDirectActivity = info.hasDirectActivity();
     }
 
     /**
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 405f0b2..e74d5fb 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -58,6 +58,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.window.TaskFragmentInfo;
+import android.window.TaskFragmentParentInfo;
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.NonNull;
@@ -413,6 +414,33 @@
                 .isEqualTo(overlayContainer);
     }
 
+    @Test
+    public void testUpdateContainer_dontInvokeUpdateOverlayForNonOverlayContainer() {
+        TaskFragmentContainer taskFragmentContainer = createMockTaskFragmentContainer(mActivity);
+
+        mSplitController.updateContainer(mTransaction, taskFragmentContainer);
+        verify(mSplitController, never()).updateOverlayContainer(any(), any());
+    }
+
+    @Test
+    public void testUpdateOverlayContainer_dismissOverlayIfNeeded() {
+        TaskFragmentContainer overlayContainer = createTestOverlayContainer(TASK_ID, "test");
+
+        mSplitController.updateOverlayContainer(mTransaction, overlayContainer);
+
+        final TaskContainer taskContainer = overlayContainer.getTaskContainer();
+        assertThat(taskContainer.getTaskFragmentContainers()).containsExactly(overlayContainer);
+
+        taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(Configuration.EMPTY,
+                DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
+
+        mSplitController.updateOverlayContainer(mTransaction, overlayContainer);
+
+        assertWithMessage("The overlay must be dismissed since there's no activity"
+                + " in the task and other taskFragment.")
+                .that(taskContainer.getTaskFragmentContainers()).isEmpty();
+    }
+
     /**
      * A simplified version of {@link SplitController.ActivityStartMonitor
      * #createOrUpdateOverlayTaskFragmentIfNeeded}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 96839c5..02031a6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -1139,7 +1139,7 @@
     public void testOnTransactionReady_taskFragmentParentInfoChanged() {
         final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
         final TaskFragmentParentInfo parentInfo = new TaskFragmentParentInfo(Configuration.EMPTY,
-                DEFAULT_DISPLAY, true);
+                DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */);
         transaction.addChange(new TaskFragmentTransaction.Change(
                 TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED)
                 .setTaskId(TASK_ID)
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 2188996..e3f5169 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -79,14 +79,14 @@
 
         configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
-                DEFAULT_DISPLAY, true /* visible */));
+                DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
 
         assertEquals(WINDOWING_MODE_MULTI_WINDOW,
                 taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
 
         configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
         taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
-                DEFAULT_DISPLAY, true /* visible */));
+                DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
 
         assertEquals(WINDOWING_MODE_FREEFORM,
                 taskContainer.getWindowingModeForSplitTaskFragment(splitBounds));
@@ -106,13 +106,13 @@
 
         configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
-                DEFAULT_DISPLAY, true /* visible */));
+                DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
 
         assertFalse(taskContainer.isInPictureInPicture());
 
         configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_PINNED);
         taskContainer.updateTaskFragmentParentInfo(new TaskFragmentParentInfo(configuration,
-                DEFAULT_DISPLAY, true /* visible */));
+                DEFAULT_DISPLAY, true /* visible */, false /* hasDirectActivity */));
 
         assertTrue(taskContainer.isInPictureInPicture());
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index ca2c3b4..293b660 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -146,13 +146,13 @@
                 });
             }
         };
+        // If the remote is actually in the same process, then make a copy of parameters since
+        // remote impls assume that they have to clean-up native references.
+        final SurfaceControl.Transaction remoteStartT =
+                copyIfLocal(startTransaction, remote.getRemoteTransition());
+        final TransitionInfo remoteInfo =
+                remoteStartT == startTransaction ? info : info.localRemoteCopy();
         try {
-            // If the remote is actually in the same process, then make a copy of parameters since
-            // remote impls assume that they have to clean-up native references.
-            final SurfaceControl.Transaction remoteStartT =
-                    copyIfLocal(startTransaction, remote.getRemoteTransition());
-            final TransitionInfo remoteInfo =
-                    remoteStartT == startTransaction ? info : info.localRemoteCopy();
             handleDeath(remote.asBinder(), finishCallback);
             remote.getRemoteTransition().startAnimation(transition, remoteInfo, remoteStartT, cb);
             // assume that remote will apply the start transaction.
@@ -160,6 +160,10 @@
             Transitions.setRunningRemoteTransitionDelegate(remote.getAppThread());
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error running remote transition.", e);
+            if (remoteStartT != startTransaction) {
+                remoteStartT.close();
+            }
+            startTransaction.apply();
             unhandleDeath(remote.asBinder(), finishCallback);
             mRequestedRemotes.remove(transition);
             mMainExecutor.execute(() -> finishCallback.onTransitionFinished(null /* wct */));
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index e28ad67..200d4ef 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -502,7 +502,7 @@
      *       <td colspan="4"><strong>BDS</strong></td>
      *       <td colspan="3"><strong>GAL</strong></td>
      *       <td><strong>SBAS</strong></td>
-     *       <td><strong>IRNSS</strong></td>
+     *       <td><strong>NavIC</strong></td>
      *     </tr>
      *     <tr>
      *       <td><strong>State Flag</strong></td>
@@ -1528,17 +1528,17 @@
      * <p>Similar to the Attribute field described in RINEX 4.00, e.g., in Tables 9-16 (see
      * https://igs.org/wg/rinex/#documents-formats).
      *
-     * <p>Returns "A" for GALILEO E1A, GALILEO E6A, IRNSS L5A SPS, IRNSS SA SPS, GLONASS G1a L1OCd,
+     * <p>Returns "A" for GALILEO E1A, GALILEO E6A, NavIC L5A SPS, NavIC SA SPS, GLONASS G1a L1OCd,
      * GLONASS G2a L2CSI.
      *
-     * <p>Returns "B" for GALILEO E1B, GALILEO E6B, IRNSS L5B RS (D), IRNSS SB RS (D), GLONASS G1a
+     * <p>Returns "B" for GALILEO E1B, GALILEO E6B, NavIC L5B RS (D), NavIC SB RS (D), GLONASS G1a
      * L1OCp, GLONASS G2a L2OCp, QZSS L1Sb.
      *
      * <p>Returns "C" for GPS L1 C/A, GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C,
-     * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C RS (P), IRNSS SC RS (P).
+     * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, NavIC L5C RS (P), NavIC SC RS (P).
      *
      * <p>Returns "D" for GPS L2 (L1(C/A) + (P2-P1) (semi-codeless)), QZSS L5S(I), BDS B1C Data,
-     * BDS B2a Data, BDS B2b Data, BDS B2 (B2a+B2b) Data, BDS B3a Data.
+     * BDS B2a Data, BDS B2b Data, BDS B2 (B2a+B2b) Data, BDS B3a Data, NavIC L1 Data.
      *
      * <p>Returns “E” for QZSS L1 C/B, QZSS L6E.
      *
@@ -1553,7 +1553,7 @@
      * <p>Returns "N" for GPS L1 codeless, GPS L2 codeless.
      *
      * <p>Returns "P" for GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P, BDS B1C Pilot, BDS B2a Pilot,
-     * BDS B2b Pilot, BDS B2 (B2a+B2b) Pilot, BDS B3a Pilot, QZSS L5S(Q).
+     * BDS B2b Pilot, BDS B2 (B2a+B2b) Pilot, BDS B3a Pilot, QZSS L5S(Q), NavIC L1 Pilot.
      *
      * <p>Returns "Q" for GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q,
      * SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
@@ -1567,7 +1567,8 @@
      * GLONASS G2a L2CSI+L2OCp, GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO
      * E5b (I+Q), GALILEO E5a+b (I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C
      * (M+L), QZSS L5 (I+Q), QZSS L6 (D+P), BDS B1 (I+Q), BDS B1C Data+Pilot, BDS B2a Data+Pilot,
-     * BDS B2 (I+Q), BDS B2 (B2a+B2b) Data+Pilot, BDS B3 (I+Q), IRNSS L5 (B+C), IRNSS S (B+C).
+     * BDS B2 (I+Q), BDS B2 (B2a+B2b) Data+Pilot, BDS B3 (I+Q), NavIC L5 (B+C), NavIC S (B+C),
+     * NavIC L1 Data+Pilot.
      *
      * <p>Returns "Y" for GPS L1Y, GPS L2Y.
      *
diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig
index c9cfa67..386534b 100644
--- a/media/java/android/media/flags/media_better_together.aconfig
+++ b/media/java/android/media/flags/media_better_together.aconfig
@@ -34,3 +34,10 @@
     description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller."
     bug: "293743975"
 }
+
+flag {
+    namespace: "media_solutions"
+    name: "enable_waiting_state_for_system_session_creation_request"
+    description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id."
+    bug: "307723189"
+}
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index 10c880d..24efbd1 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -158,26 +158,6 @@
             in @nullable IMediaProjection projection);
 
     /**
-     * Notifies system server that we are handling a particular state during the consent flow.
-     *
-     * <p>Only used for emitting atoms.
-     *
-     * @param hostUid               The uid of the process requesting consent to capture, may be an app or
-     *                              SystemUI.
-     * @param state                 The state that SystemUI is handling during the consent flow.
-     *                              Must be a valid
-     *                              state defined in the MediaProjectionState enum.
-     * @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED.
-     *                              Indicates the entry point for requesting the permission. Must be
-     *                              a valid state defined
-     *                              in the SessionCreationSource enum.
-     */
-    @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
-    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
-            + ".permission.MANAGE_MEDIA_PROJECTION)")
-    oneway void notifyPermissionRequestStateChange(int hostUid, int state, int sessionCreationSource);
-
-    /**
      * Notifies system server that the permission request was initiated.
      *
      * <p>Only used for emitting atoms.
@@ -208,6 +188,19 @@
     oneway void notifyPermissionRequestDisplayed(int hostUid);
 
     /**
+     * Notifies system server that the permission request was cancelled.
+     *
+     * <p>Only used for emitting atoms.
+     *
+     * @param hostUid The uid of the process requesting consent to capture, may be an app or
+     *                SystemUI.
+     */
+    @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
+    @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+            + ".permission.MANAGE_MEDIA_PROJECTION)")
+    oneway void notifyPermissionRequestCancelled(int hostUid);
+
+    /**
      * Notifies system server that the app selector was displayed.
      *
      * <p>Only used for emitting atoms.
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 477e61d..f0fa6c5 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -336,7 +336,10 @@
             return result
         }
 
-        private fun parseCredentialEntryFromSlice(slice: Slice): CredentialEntry? {
+        /**
+         * @hide
+         */
+        fun parseCredentialEntryFromSlice(slice: Slice): CredentialEntry? {
             try {
                 when (slice.spec?.type) {
                     TYPE_PASSWORD_CREDENTIAL -> return PasswordCredentialEntry.fromSlice(slice)!!
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index d35dcb5..81cbd5a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -23,6 +23,8 @@
 import android.credentials.GetCandidateCredentialsException
 import android.credentials.GetCandidateCredentialsResponse
 import android.credentials.GetCredentialRequest
+import android.credentials.ui.GetCredentialProviderData
+import android.graphics.drawable.Icon
 import android.os.Bundle
 import android.os.CancellationSignal
 import android.os.OutcomeReceiver
@@ -42,6 +44,9 @@
 import org.json.JSONException
 import android.widget.inline.InlinePresentationSpec
 import androidx.autofill.inline.v1.InlineSuggestionUi
+import androidx.credentials.provider.CustomCredentialEntry
+import androidx.credentials.provider.PasswordCredentialEntry
+import androidx.credentials.provider.PublicKeyCredentialEntry
 import com.android.credentialmanager.GetFlowUtils
 import com.android.credentialmanager.getflow.CredentialEntryInfo
 import com.android.credentialmanager.getflow.ProviderDisplayInfo
@@ -110,6 +115,34 @@
         )
     }
 
+    private fun getEntryToIconMap(
+            candidateProviderDataList: MutableList<GetCredentialProviderData>
+    ): Map<String, Icon> {
+        val entryIconMap: MutableMap<String, Icon> = mutableMapOf()
+        candidateProviderDataList.forEach { provider ->
+            provider.credentialEntries.forEach { entry ->
+                val credentialEntry = GetFlowUtils.parseCredentialEntryFromSlice(entry.slice)
+                when (credentialEntry) {
+                    is PasswordCredentialEntry -> {
+                        entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
+                    }
+                    is PublicKeyCredentialEntry -> {
+                        entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
+                    }
+                    is CustomCredentialEntry -> {
+                        entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
+                    }
+                }
+            }
+        }
+        return entryIconMap
+    }
+
+    private fun getDefaultIcon(): Icon {
+        return Icon.createWithResource(
+                this, com.android.credentialmanager.R.drawable.ic_other_sign_in_24)
+    }
+
     private fun convertToFillResponse(
             getCredResponse: GetCandidateCredentialsResponse,
             filLRequest: FillRequest
@@ -120,6 +153,8 @@
         if (providerList.isEmpty()) {
             return null
         }
+        val entryIconMap: Map<String, Icon> =
+                getEntryToIconMap(getCredResponse.candidateProviderDataList)
         var totalEntryCount = 0
         providerList.forEach { provider ->
             totalEntryCount += provider.credentialEntryList.size
@@ -174,6 +209,10 @@
                     val sliceBuilder = InlineSuggestionUi
                             .newContentBuilder(pendingIntent)
                             .setTitle(credentialEntry.userName)
+                    val icon: Icon =
+                            entryIconMap[credentialEntry.entryKey + credentialEntry.entrySubkey]
+                                    ?: getDefaultIcon()
+                    sliceBuilder.setStartIcon(icon)
                     inlinePresentation = InlinePresentation(
                             sliceBuilder.build().slice, spec, /* pinned= */ false)
                 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index c9540c7..8bdbee3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -26,7 +26,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.PowerManager;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
@@ -202,10 +201,10 @@
     }
 
     private static void setBatterySaverConfirmationAcknowledged(Context context) {
-        Secure.putIntForUser(context.getContentResolver(),
-                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT);
-        Secure.putIntForUser(context.getContentResolver(),
-                Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1, UserHandle.USER_CURRENT);
+        Secure.putInt(context.getContentResolver(),
+                Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
+        Secure.putInt(context.getContentResolver(),
+                Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED, 1);
     }
 
     /**
diff --git a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
index 015e9f9..d1b8a06 100644
--- a/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
+++ b/packages/SystemUI/res/color/notification_guts_priority_button_bg_stroke.xml
@@ -14,8 +14,9 @@
   ~ limitations under the License
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <item android:state_selected="true"
-          android:color="?android:attr/colorAccent" />
+          android:color="?androidprv:attr/materialColorOnSurfaceVariant" />
     <item android:color="@color/notification_guts_priority_button_bg_stroke_color" />
 </selector>
diff --git a/packages/SystemUI/res/color/notification_guts_priority_contents.xml b/packages/SystemUI/res/color/notification_guts_priority_contents.xml
index 42f0189..cc8c25a 100644
--- a/packages/SystemUI/res/color/notification_guts_priority_contents.xml
+++ b/packages/SystemUI/res/color/notification_guts_priority_contents.xml
@@ -14,8 +14,9 @@
   ~ limitations under the License.
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
     <item android:state_selected="true"
-          android:color="?android:attr/colorAccent" />
+          android:color="?androidprv:attr/materialColorOnSurfaceVariant" />
     <item android:color="@color/notification_guts_priority_button_content_color" />
 </selector>
diff --git a/packages/SystemUI/res/color/remote_input_hint.xml b/packages/SystemUI/res/color/remote_input_hint.xml
index 7fe58db..0d90ee6 100644
--- a/packages/SystemUI/res/color/remote_input_hint.xml
+++ b/packages/SystemUI/res/color/remote_input_hint.xml
@@ -14,6 +14,7 @@
   ~ limitations under the License.
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?android:attr/textColorPrimary" android:alpha=".6" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:color="?androidprv:attr/materialColorOnSurfaceVariant" android:alpha=".6" />
 </selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/remote_input_send.xml b/packages/SystemUI/res/color/remote_input_send.xml
index 4dcd3dd..0acc66b 100644
--- a/packages/SystemUI/res/color/remote_input_send.xml
+++ b/packages/SystemUI/res/color/remote_input_send.xml
@@ -15,7 +15,8 @@
   ~ limitations under the License
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/colorAccent" android:alpha=".3" />
-    <item android:color="?android:attr/colorAccent" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:state_enabled="false" android:color="?androidprv:attr/materialColorPrimary" android:alpha=".3" />
+    <item android:color="?androidprv:attr/materialColorPrimary" />
 </selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/remote_input_text.xml b/packages/SystemUI/res/color/remote_input_text.xml
index 13bb1d7..bf2c198 100644
--- a/packages/SystemUI/res/color/remote_input_text.xml
+++ b/packages/SystemUI/res/color/remote_input_text.xml
@@ -15,7 +15,8 @@
   ~ limitations under the License
   -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" android:alpha=".6" />
-    <item android:color="?android:attr/textColorPrimary" />
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:state_enabled="false" android:color="?androidprv:attr/materialColorOnSurfaceVariant" android:alpha=".6" />
+    <item android:color="?androidprv:attr/materialColorOnSurfaceVariant" />
 </selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
index e626675..b959737 100644
--- a/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
+++ b/packages/SystemUI/res/drawable/notif_footer_btn_background.xml
@@ -26,7 +26,7 @@
                 <padding
                     android:left="20dp"
                     android:right="20dp" />
-                <solid android:color="?androidprv:attr/colorSurface" />
+                <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
             </shape>
         </inset>
     </item>
diff --git a/packages/SystemUI/res/drawable/notification_guts_bg.xml b/packages/SystemUI/res/drawable/notification_guts_bg.xml
index bd9394b..84e2231 100644
--- a/packages/SystemUI/res/drawable/notification_guts_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_guts_bg.xml
@@ -17,7 +17,7 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <solid android:color="?androidprv:attr/colorSurface" />
+    <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
     <!--The radius is 1dp smaller than the notification one, to avoid aliasing bugs on the corners -->
     <corners android:radius="1dp" />
 </shape>
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 3eaa618..355e75d 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -20,7 +20,7 @@
         android:color="?android:attr/colorControlHighlight">
     <item>
         <shape>
-            <solid android:color="?androidprv:attr/colorSurface" />
+            <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh" />
         </shape>
     </item>
     <item>
diff --git a/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml b/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml
index 535b354..45d1a53 100644
--- a/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml
+++ b/packages/SystemUI/res/drawable/remote_input_view_text_bg.xml
@@ -14,12 +14,13 @@
   ~ limitations under the License.
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="rectangle">
 
-    <solid android:color="?android:attr/colorBackgroundFloating" />
+    <solid android:color="?androidprv:attr/materialColorSurfaceDim" />
     <stroke
         android:width="@dimen/remote_input_view_text_stroke"
-        android:color="?android:attr/colorAccent"/>
+        android:color="?androidprv:attr/materialColorPrimary"/>
     <padding
         android:bottom="0dp"
         android:left="12dp"
diff --git a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
index 8b34080..06bed00 100644
--- a/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
+++ b/packages/SystemUI/res/drawable/status_bar_notification_section_header_clear_btn.xml
@@ -15,11 +15,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:width="40dp"
     android:height="40dp"
     android:viewportWidth="40"
     android:viewportHeight="40">
     <path
-        android:fillColor="@color/notification_section_clear_all_btn_color"
+        android:fillColor="?androidprv:attr/materialColorOnSurfaceVariant"
         android:pathData="M24.6667 16.2733L23.7267 15.3333L20 19.06L16.2734 15.3333L15.3334 16.2733L19.06 20L15.3334 23.7267L16.2734 24.6667L20 20.94L23.7267 24.6667L24.6667 23.7267L20.94 20L24.6667 16.2733Z"/>
 </vector>
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index bddcb6a..cf301c9 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -79,7 +79,4 @@
             android:tint="@color/accent_tint_color_selector"
             android:soundEffectsEnabled="false" />
     </LinearLayout>
-
-    <include layout="@layout/volume_dnd_icon"/>
-
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 3b70dc0..5ce2601 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -70,12 +70,6 @@
                     android:tint="?android:attr/textColorPrimary"
                     android:layout_gravity="center"
                     android:soundEffectsEnabled="false" />
-
-                <include layout="@layout/volume_dnd_icon"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginRight="@dimen/volume_dialog_stream_padding"
-                    android:layout_marginTop="6dp"/>
             </FrameLayout>
 
             <LinearLayout
diff --git a/packages/SystemUI/res/layout/bluetooth_device_item.xml b/packages/SystemUI/res/layout/bluetooth_device_item.xml
index 6d77943..08eccbb 100644
--- a/packages/SystemUI/res/layout/bluetooth_device_item.xml
+++ b/packages/SystemUI/res/layout/bluetooth_device_item.xml
@@ -44,10 +44,9 @@
         android:paddingTop="10dp"
         android:maxLines="1"
         android:ellipsize="end"
-        app:layout_constraintWidth_percent="0.7"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
-        app:layout_constraintEnd_toStartOf="@+id/gear_icon"
+        app:layout_constraintEnd_toStartOf="@+id/guideline"
         app:layout_constraintBottom_toTopOf="@+id/bluetooth_device_summary"
         android:gravity="center_vertical"
         android:textSize="14sp" />
@@ -60,34 +59,35 @@
         android:paddingBottom="10dp"
         android:maxLines="1"
         android:ellipsize="end"
-        app:layout_constraintWidth_percent="0.7"
         app:layout_constraintTop_toBottomOf="@+id/bluetooth_device_name"
         app:layout_constraintStart_toEndOf="@+id/bluetooth_device_icon"
-        app:layout_constraintEnd_toStartOf="@+id/gear_icon"
+        app:layout_constraintEnd_toStartOf="@+id/guideline"
         app:layout_constraintBottom_toBottomOf="parent"
         android:gravity="center_vertical" />
 
+    <androidx.constraintlayout.widget.Guideline
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/guideline"
+        app:layout_constraintGuide_percent="0.8"
+        android:orientation="vertical"/>
+
     <View
         android:id="@+id/gear_icon"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:contentDescription="@string/accessibility_bluetooth_device_settings_gear"
-        app:layout_constraintStart_toEndOf="@+id/bluetooth_device_name"
-        app:layout_constraintEnd_toEndOf="@+id/gear_icon_image"
+        app:layout_constraintStart_toEndOf="@+id/guideline"
+        app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent" />
 
     <ImageView
         android:id="@+id/gear_icon_image"
-        android:src="@drawable/ic_settings_24dp"
-        android:contentDescription="@string/accessibility_bluetooth_device_settings_gear"
         android:layout_width="0dp"
         android:layout_height="24dp"
-        app:layout_constraintStart_toEndOf="@+id/bluetooth_device_name"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
+        android:src="@drawable/ic_settings_24dp"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintWidth_percent="0.3"
-        android:gravity="center_vertical"
-        android:paddingStart="10dp" />
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index 5d986e0..c11a18b 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -51,147 +51,160 @@
         android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintBottom_toTopOf="@id/bluetooth_toggle_title"
+        app:layout_constraintBottom_toTopOf="@+id/scroll_view"
         app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_title" />
 
-    <TextView
-        android:id="@+id/bluetooth_toggle_title"
-        style="@style/BluetoothTileDialog.Device"
-        android:layout_width="0dp"
-        android:layout_height="64dp"
-        android:maxLines="1"
-        android:ellipsize="end"
-        android:gravity="center_vertical"
-        android:layout_marginTop="4dp"
-        android:text="@string/turn_on_bluetooth"
-        android:clickable="false"
-        android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
-        android:textSize="16sp"
-        app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle" />
-
-    <Switch
-        android:id="@+id/bluetooth_toggle"
-        style="@style/BluetoothTileDialog.Device"
-        android:layout_width="0dp"
-        android:layout_height="48dp"
-        android:gravity="center|center_vertical"
-        android:paddingEnd="24dp"
-        android:layout_marginTop="10dp"
-        android:contentDescription="@string/turn_on_bluetooth"
-        android:switchMinWidth="@dimen/settingslib_switch_track_width"
-        android:theme="@style/MainSwitch.Settingslib"
-        android:thumb="@drawable/settingslib_thumb_selector"
-        android:track="@drawable/settingslib_track_selector"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
-        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle" />
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/device_list"
+    <androidx.core.widget.NestedScrollView
+        android:id="@+id/scroll_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="20dp"
-        android:nestedScrollingEnabled="false"
-        android:overScrollMode="never"
-        android:scrollbars="vertical"
+        app:layout_constrainedHeight="true"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/bluetooth_toggle"
-        app:layout_constraintBottom_toTopOf="@+id/see_all_text" />
-
-    <androidx.constraintlayout.widget.Group
-        android:id="@+id/see_all_layout_group"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        app:constraint_referenced_ids="ic_arrow,see_all_text" />
-
-    <ImageView
-        android:id="@+id/ic_arrow"
-        android:layout_marginStart="36dp"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:importantForAccessibility="no"
-        android:gravity="center_vertical"
-        android:src="@drawable/ic_arrow_forward"
-        app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/see_all_text"
-        app:layout_constraintTop_toBottomOf="@id/device_list" />
-
-    <TextView
-        android:id="@+id/see_all_text"
-        style="@style/BluetoothTileDialog.Device"
-        android:layout_width="0dp"
-        android:layout_height="64dp"
-        android:maxLines="1"
-        android:ellipsize="end"
-        android:gravity="center_vertical"
-        android:layout_marginStart="0dp"
-        android:paddingStart="20dp"
-        android:text="@string/see_all_bluetooth_devices"
-        android:textSize="14sp"
-        android:textAppearance="@style/TextAppearance.Dialog.Title"
-        app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
-        app:layout_constraintStart_toEndOf="@+id/ic_arrow"
-        app:layout_constraintTop_toBottomOf="@id/device_list"
-        app:layout_constraintEnd_toEndOf="parent" />
-
-    <androidx.constraintlayout.widget.Group
-        android:id="@+id/pair_new_device_layout_group"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        app:constraint_referenced_ids="ic_add,pair_new_device_text" />
-
-    <ImageView
-        android:id="@+id/ic_add"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_marginStart="36dp"
-        android:gravity="center_vertical"
-        android:importantForAccessibility="no"
-        android:src="@drawable/ic_add"
-        app:layout_constraintBottom_toTopOf="@id/done_button"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/pair_new_device_text"
-        app:layout_constraintTop_toBottomOf="@id/see_all_text"
-        android:tint="?android:attr/textColorPrimary" />
-
-    <TextView
-        android:id="@+id/pair_new_device_text"
-        style="@style/BluetoothTileDialog.Device"
-        android:layout_width="0dp"
-        android:layout_height="64dp"
-        android:maxLines="1"
-        android:ellipsize="end"
-        android:gravity="center_vertical"
-        android:layout_marginStart="0dp"
-        android:paddingStart="20dp"
-        android:text="@string/pair_new_bluetooth_devices"
-        android:textSize="14sp"
-        android:textAppearance="@style/TextAppearance.Dialog.Title"
-        app:layout_constraintBottom_toTopOf="@id/done_button"
-        app:layout_constraintStart_toEndOf="@+id/ic_add"
-        app:layout_constraintTop_toBottomOf="@id/see_all_text"
-        app:layout_constraintEnd_toEndOf="parent" />
-
-    <Button
-        android:id="@+id/done_button"
-        style="@style/Widget.Dialog.Button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/dialog_bottom_padding"
-        android:layout_marginEnd="@dimen/dialog_side_padding"
-        android:layout_marginStart="@dimen/dialog_side_padding"
-        android:clickable="true"
-        android:ellipsize="end"
-        android:focusable="true"
-        android:maxLines="1"
-        android:text="@string/inline_done_button"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/pair_new_device_text" />
+        app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_subtitle">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/scroll_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" >
+
+            <TextView
+                android:id="@+id/bluetooth_toggle_title"
+                android:layout_width="0dp"
+                android:layout_height="64dp"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:gravity="start|center_vertical"
+                android:paddingEnd="0dp"
+                android:paddingStart="36dp"
+                android:text="@string/turn_on_bluetooth"
+                android:clickable="false"
+                android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
+                android:textSize="16sp"
+                app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintBottom_toTopOf="@+id/device_list"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <Switch
+                android:id="@+id/bluetooth_toggle"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp"
+                android:gravity="start|center_vertical"
+                android:paddingEnd="40dp"
+                android:contentDescription="@string/turn_on_bluetooth"
+                android:switchMinWidth="@dimen/settingslib_switch_track_width"
+                android:theme="@style/MainSwitch.Settingslib"
+                android:thumb="@drawable/settingslib_thumb_selector"
+                android:track="@drawable/settingslib_track_selector"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
+                app:layout_constraintBottom_toTopOf="@+id/device_list"
+                app:layout_constraintTop_toTopOf="parent" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/device_list"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dp"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle"
+                app:layout_constraintBottom_toTopOf="@+id/see_all_text" />
+
+            <androidx.constraintlayout.widget.Group
+                android:id="@+id/see_all_layout_group"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                app:constraint_referenced_ids="ic_arrow,see_all_text" />
+
+            <ImageView
+                android:id="@+id/ic_arrow"
+                android:layout_marginStart="36dp"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:importantForAccessibility="no"
+                android:gravity="center_vertical"
+                android:src="@drawable/ic_arrow_forward"
+                app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/see_all_text"
+                app:layout_constraintTop_toBottomOf="@id/device_list" />
+
+            <TextView
+                android:id="@+id/see_all_text"
+                style="@style/BluetoothTileDialog.Device"
+                android:layout_width="0dp"
+                android:layout_height="64dp"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:gravity="center_vertical"
+                android:layout_marginStart="0dp"
+                android:paddingStart="20dp"
+                android:text="@string/see_all_bluetooth_devices"
+                android:textSize="14sp"
+                android:textAppearance="@style/TextAppearance.Dialog.Title"
+                app:layout_constraintBottom_toTopOf="@+id/pair_new_device_text"
+                app:layout_constraintStart_toEndOf="@+id/ic_arrow"
+                app:layout_constraintTop_toBottomOf="@id/device_list"
+                app:layout_constraintEnd_toEndOf="parent" />
+
+            <androidx.constraintlayout.widget.Group
+                android:id="@+id/pair_new_device_layout_group"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                app:constraint_referenced_ids="ic_add,pair_new_device_text" />
+
+            <ImageView
+                android:id="@+id/ic_add"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:layout_marginStart="36dp"
+                android:gravity="center_vertical"
+                android:importantForAccessibility="no"
+                android:src="@drawable/ic_add"
+                app:layout_constraintBottom_toTopOf="@id/done_button"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintEnd_toStartOf="@id/pair_new_device_text"
+                app:layout_constraintTop_toBottomOf="@id/see_all_text"
+                android:tint="?android:attr/textColorPrimary" />
+
+            <TextView
+                android:id="@+id/pair_new_device_text"
+                style="@style/BluetoothTileDialog.Device"
+                android:layout_width="0dp"
+                android:layout_height="64dp"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:gravity="center_vertical"
+                android:layout_marginStart="0dp"
+                android:paddingStart="20dp"
+                android:text="@string/pair_new_bluetooth_devices"
+                android:textSize="14sp"
+                android:textAppearance="@style/TextAppearance.Dialog.Title"
+                app:layout_constraintStart_toEndOf="@+id/ic_add"
+                app:layout_constraintTop_toBottomOf="@id/see_all_text"
+                app:layout_constraintEnd_toEndOf="parent" />
+
+            <Button
+                android:id="@+id/done_button"
+                style="@style/Widget.Dialog.Button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/dialog_bottom_padding"
+                android:layout_marginEnd="@dimen/dialog_side_padding"
+                android:layout_marginStart="@dimen/dialog_side_padding"
+                android:clickable="true"
+                android:ellipsize="end"
+                android:focusable="true"
+                android:maxLines="1"
+                android:text="@string/inline_done_button"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintTop_toBottomOf="@id/pair_new_device_text"
+                app:layout_constraintBottom_toBottomOf="parent" />
+        </androidx.constraintlayout.widget.ConstraintLayout>
+    </androidx.core.widget.NestedScrollView>
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml
index c70f8e2..68c8dd9 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf.xml
@@ -16,6 +16,7 @@
 
 <FrameLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         android:id="@+id/half_shelf_dialog"
         android:orientation="vertical"
         android:layout_width="wrap_content"
@@ -65,7 +66,7 @@
                     android:gravity="center_vertical|start"
                     android:ellipsize="end"
                     android:maxLines="2"
-                    android:textColor="?android:attr/textColorPrimary"
+                    android:textColor="?androidprv:attr/materialColorOnSurface"
                     android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
                     android:textSize="16sp"
                 />
diff --git a/packages/SystemUI/res/layout/notif_half_shelf_row.xml b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
index 190f999..9ef342c 100644
--- a/packages/SystemUI/res/layout/notif_half_shelf_row.xml
+++ b/packages/SystemUI/res/layout/notif_half_shelf_row.xml
@@ -16,6 +16,7 @@
 
 <com.android.systemui.statusbar.notification.row.ChannelRow
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/half_shelf_row"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -59,7 +60,7 @@
                 android:ellipsize="end"
                 android:maxLines="1"
                 android:fontFamily="@*android:string/config_headlineFontFamily"
-                android:textColor="?android:attr/textColorPrimary"
+                android:textColor="?androidprv:attr/materialColorOnSurface"
                 android:textSize="16sp"
             />
 
@@ -74,7 +75,7 @@
                 android:maxLines="1"
                 android:layout_below="@id/channel_name"
                 android:fontFamily="@*android:string/config_bodyFontFamily"
-                android:textColor="?android:attr/textColorSecondary"
+                android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"
                 android:textSize="14sp"
             />
         </RelativeLayout>
diff --git a/packages/SystemUI/res/layout/notification_children_divider.xml b/packages/SystemUI/res/layout/notification_children_divider.xml
index eb74306..13e24a9 100644
--- a/packages/SystemUI/res/layout/notification_children_divider.xml
+++ b/packages/SystemUI/res/layout/notification_children_divider.xml
@@ -17,7 +17,8 @@
 
 <com.android.systemui.statusbar.AlphaOptimizedView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/notification_more_divider"
     android:layout_width="match_parent"
     android:layout_height="@dimen/notification_divider_height"
-    android:background="@color/notification_divider_color" />
+    android:background="?androidprv:attr/materialColorOnSurfaceVariant" />
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 4f6e88c..3a752c8 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -17,6 +17,7 @@
 
 <com.android.systemui.statusbar.notification.row.NotificationConversationInfo
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/notification_guts"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -173,7 +174,7 @@
             android:contentDescription="@string/notification_more_settings"
             android:background="@drawable/ripple_drawable_20dp"
             android:src="@drawable/ic_settings"
-            android:tint="?android:attr/colorAccent"
+            android:tint="?androidprv:attr/materialColorPrimary"
             android:layout_alignParentEnd="true" />
 
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 852db1b..19a3f2f 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -17,6 +17,7 @@
 
 <com.android.systemui.statusbar.notification.row.NotificationInfo
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/notification_guts"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -102,7 +103,7 @@
             android:contentDescription="@string/notification_app_settings"
             android:src="@drawable/ic_info"
             android:layout_toStartOf="@id/info"
-            android:tint="@color/notification_guts_link_icon_tint"/>
+            android:tint="?androidprv:attr/materialColorPrimary"/>
         <ImageButton
             android:id="@+id/info"
             android:layout_width="@dimen/notification_importance_toggle_size"
@@ -111,7 +112,7 @@
             android:contentDescription="@string/notification_more_settings"
             android:background="@drawable/ripple_drawable_20dp"
             android:src="@drawable/ic_settings"
-            android:tint="?android:attr/colorAccent"
+            android:tint="?androidprv:attr/materialColorPrimary"
             android:layout_alignParentEnd="true" />
 
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 8b53680..6e541a7 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -23,7 +23,7 @@
     android:orientation="vertical"
     android:paddingTop="2dp"
     android:paddingBottom="2dp"
-    android:background="?androidprv:attr/colorSurface"
+    android:background="?androidprv:attr/materialColorSurfaceContainerHigh"
     android:theme="@style/Theme.SystemUI">
 
     <RelativeLayout
@@ -38,7 +38,7 @@
             android:layout_alignParentStart="true"
             android:layout_centerVertical="true"
             android:paddingStart="@*android:dimen/notification_content_margin_end"
-            android:textColor="?android:attr/textColorPrimary"
+            android:textColor="?androidprv:attr/materialColorOnSurface"
             android:paddingEnd="4dp"/>
 
         <ImageView
diff --git a/packages/SystemUI/res/layout/notification_snooze_option.xml b/packages/SystemUI/res/layout/notification_snooze_option.xml
index d42cc02..fa6f965 100644
--- a/packages/SystemUI/res/layout/notification_snooze_option.xml
+++ b/packages/SystemUI/res/layout/notification_snooze_option.xml
@@ -16,10 +16,11 @@
 -->
 <TextView
         xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
         android:layout_width="match_parent"
         android:layout_height="@*android:dimen/notification_headerless_min_height"
         android:layout_marginStart="@*android:dimen/notification_content_margin_end"
         android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
         android:gravity="center_vertical"
         android:textSize="14sp"
-        android:textColor="?android:attr/textColorSecondary"/>
\ No newline at end of file
+        android:textColor="?androidprv:attr/materialColorOnSurfaceVariant"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index c1bac31..72424a13 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -41,7 +41,7 @@
             android:layout_height="wrap_content"
             >
             <com.android.systemui.statusbar.notification.row.FooterViewButton
-                style="@style/TextAppearance.NotificationSectionHeaderButton"
+                style="@style/TextAppearance.NotificationFooterButton"
                 android:id="@+id/manage_text"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
@@ -54,12 +54,11 @@
                 app:layout_constraintEnd_toStartOf="@id/dismiss_text"
                 android:background="@drawable/notif_footer_btn_background"
                 android:focusable="true"
-                android:textColor="@color/notif_pill_text"
                 android:contentDescription="@string/manage_notifications_history_text"
                 android:text="@string/manage_notifications_history_text"
                 />
             <com.android.systemui.statusbar.notification.row.FooterViewButton
-                style="@style/TextAppearance.NotificationSectionHeaderButton"
+                style="@style/TextAppearance.NotificationFooterButton"
                 android:id="@+id/dismiss_text"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
@@ -70,7 +69,6 @@
                 app:layout_constraintStart_toEndOf="@id/manage_text"
                 android:background="@drawable/notif_footer_btn_background"
                 android:focusable="true"
-                android:textColor="@color/notif_pill_text"
                 android:contentDescription="@string/accessibility_clear_all"
                 android:text="@string/clear_all_notifications_text"
                 />
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index c4d8d55..53abe87 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -40,7 +40,7 @@
             android:layout_weight="1">
 
             <TextView
-                style="@style/TextAppearance.NotificationSectionHeaderButton"
+                style="@style/TextAppearance.NotificationSectionHeaderLabel"
                 android:id="@+id/header_label"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 6a192d4..39a1f1f 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -69,12 +69,6 @@
                     android:tint="?android:attr/textColorPrimary"
                     android:layout_gravity="center"
                     android:soundEffectsEnabled="false" />
-
-                <include layout="@layout/volume_dnd_icon"
-                         android:layout_width="match_parent"
-                         android:layout_height="wrap_content"
-                         android:layout_marginRight="@dimen/volume_dialog_stream_padding"
-                         android:layout_marginTop="6dp"/>
             </FrameLayout>
 
             <LinearLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index c9256ae..f35de05 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -62,7 +62,6 @@
                 android:background="@null"
                 android:layoutDirection="ltr"
                 android:rotation="270" />
-            <include layout="@layout/volume_dnd_icon"/>
         </FrameLayout>
 
         <com.android.keyguard.AlphaOptimizedImageButton
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 99311e3..d9385c7 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -33,7 +33,7 @@
     <!-- The color of the text inside a notification -->
     <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
 
-    <color name="notif_pill_text">@color/material_dynamic_neutral95</color>
+    <color name="notif_pill_text">@android:color/system_on_surface_dark</color>
 
     <color name="notification_guts_link_icon_tint">@color/GM2_grey_500</color>
     <color name="notification_guts_sub_text_color">@color/GM2_grey_300</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index e942258..0620355 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -115,7 +115,7 @@
     <!-- Chosen so fill over background matches single tone -->
     <color name="dark_mode_qs_icon_color_dual_tone_fill">#99000000</color>
 
-    <color name="notif_pill_text">@color/material_dynamic_neutral10</color>
+    <color name="notif_pill_text">@android:color/system_on_surface_light</color>
 
     <!-- Keyboard shortcuts colors -->
     <color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4c41ca4..4c520444 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -466,7 +466,7 @@
     <string name="accessibility_bluetooth_device_icon">Bluetooth device icon</string>
 
     <!-- Content description of the bluetooth device settings gear icon. [CHAR LIMIT=NONE] -->
-    <string name="accessibility_bluetooth_device_settings_gear">Bluetooth device settings gear</string>
+    <string name="accessibility_bluetooth_device_settings_gear">Click to configure device detail</string>
 
     <!-- Content description of the battery when battery state is unknown for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_battery_unknown">Battery percentage unknown.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 084cb88..7ce530f 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -597,34 +597,34 @@
     <style name="TextAppearance.NotificationImportanceChannel">
         <item name="android:textSize">@dimen/notification_importance_channel_text</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
-        <item name="android:textColor">@color/notification_guts_header_text_color</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
         <item name="android:textSize">@dimen/notification_importance_channel_text</item>
     </style>
 
     <style name="TextAppearance.NotificationImportanceChannelGroup">
         <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@color/notification_guts_header_text_color</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
         <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
     </style>
 
     <style name="TextAppearance.NotificationImportanceApp">
         <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@color/notification_guts_sub_text_color</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
         <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
     </style>
 
     <style name="TextAppearance.NotificationImportanceHeader">
         <item name="android:textSize">@dimen/notification_importance_header_text</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@color/notification_guts_header_text_color</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
     </style>
 
     <style name="TextAppearance.NotificationImportanceDetail">
         <item name="android:textSize">@dimen/notification_importance_description_text</item>
         <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
-        <item name="android:textColor">@color/notification_guts_sub_text_color</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
         <item name="android:gravity">center</item>
     </style>
 
@@ -636,9 +636,27 @@
     </style>
 
     <style
+        name="TextAppearance.NotificationSectionHeaderLabel"
+        parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:minWidth">0dp</item>
+    </style>
+
+    <style
         name="TextAppearance.NotificationSectionHeaderButton"
         parent="@android:style/Widget.DeviceDefault.Button.Borderless">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:minWidth">0dp</item>
+    </style>
+
+    <style
+        name="TextAppearance.NotificationFooterButton"
+        parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
         <item name="android:textAllCaps">false</item>
         <item name="android:textSize">14sp</item>
         <item name="android:minWidth">0dp</item>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 584357b..0bd4859 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -1461,8 +1461,7 @@
         mDragView.setColorFilter(filter);
     }
 
-    @VisibleForTesting
-    void setBounceEffectDuration(int duration) {
+    private void setBounceEffectDuration(int duration) {
         mBounceEffectDuration = duration;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 06ec17f..f4a9f73 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -406,6 +406,10 @@
     // TODO(b/301610137): Tracking bug
     @JvmField val NEW_NETWORK_SLICE_UI = unreleasedFlag("new_network_slice_ui", teamfood = true)
 
+    // TODO(b/308138154): Tracking bug
+    val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS =
+        releasedFlag("filter_provisioning_network_subscriptions")
+
     // TODO(b/265892345): Tracking Bug
     val PLUG_IN_STATUS_BAR_CHIP = releasedFlag("plug_in_status_bar_chip")
 
@@ -479,7 +483,7 @@
     val MEDIA_REMOTE_RESUME = unreleasedFlag("media_remote_resume")
 
     // TODO(b/304506662): Tracking Bug
-    val MEDIA_DEVICE_NAME_FIX = unreleasedFlag("media_device_name_fix", teamfood = true)
+    val MEDIA_DEVICE_NAME_FIX = releasedFlag("media_device_name_fix")
 
     // 1000 - dock
     val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag("simulate_dock_through_charging")
@@ -618,7 +622,7 @@
 
     /** TODO(b/295143676): Tracking bug. When enable, captures a screenshot for each display. */
     @JvmField
-    val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot", teamfood = true)
+    val MULTI_DISPLAY_SCREENSHOT = releasedFlag("multi_display_screenshot")
 
     // 1400 - columbus
     // TODO(b/254512756): Tracking Bug
@@ -722,7 +726,7 @@
     @JvmField val KEYBOARD_BACKLIGHT_INDICATOR = releasedFlag("keyboard_backlight_indicator")
 
     // TODO(b/277192623): Tracking Bug
-    @JvmField val KEYBOARD_EDUCATION = unreleasedFlag("keyboard_education", teamfood = true)
+    @JvmField val KEYBOARD_EDUCATION = releasedFlag("keyboard_education")
 
     // TODO(b/277201412): Tracking Bug
     @JvmField
@@ -768,7 +772,8 @@
     @JvmField val PRECOMPUTED_TEXT = releasedFlag("precomputed_text")
 
     // TODO(b/302087895): Tracking Bug
-    @JvmField val CALL_LAYOUT_ASYNC_SET_DATA = unreleasedFlag("call_layout_async_set_data")
+    @JvmField val CALL_LAYOUT_ASYNC_SET_DATA =
+            unreleasedFlag("call_layout_async_set_data", teamfood = true)
 
     // TODO(b/302144438): Tracking Bug
     @JvmField val DECOUPLE_REMOTE_INPUT_DELEGATE_AND_CALLBACK_UPDATE =
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index aecfdaa..e768f16 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -91,7 +91,7 @@
     @SysUISingleton
     @NotifInflationLog
     public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) {
-        return factory.create("NotifInflationLog", 100);
+        return factory.create("NotifInflationLog", 250);
     }
 
     /** Provides a logging buffer for notification interruption calculations. */
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
index 1962119..98a3896 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLogger.kt
@@ -16,7 +16,6 @@
 package com.android.systemui.mediaprojection
 
 import android.media.projection.IMediaProjectionManager
-import android.os.Process
 import android.os.RemoteException
 import android.util.Log
 import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_APP as METRICS_CREATION_SOURCE_APP
@@ -66,6 +65,19 @@
     }
 
     /**
+     * Request to log that the permission request was cancelled.
+     *
+     * @param hostUid The UID of the package that initiates MediaProjection.
+     */
+    fun notifyProjectionRequestCancelled(hostUid: Int) {
+        try {
+            service.notifyPermissionRequestCancelled(hostUid)
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Error notifying server of projection cancelled", e)
+        }
+    }
+
+    /**
      * Request to log that the app selector was displayed.
      *
      * @param hostUid The UID of the package that initiates MediaProjection.
@@ -78,47 +90,6 @@
         }
     }
 
-    /**
-     * Request to log that the permission request moved to the given state.
-     *
-     * Should not be used for the initialization state, since that should use {@link
-     * MediaProjectionMetricsLogger#notifyProjectionInitiated(Int)} and pass the
-     * sessionCreationSource.
-     */
-    fun notifyPermissionProgress(state: Int) {
-        // TODO validate state is valid
-        notifyToServer(state, SessionCreationSource.UNKNOWN)
-    }
-
-    /**
-     * Notifies system server that we are handling a particular state during the consent flow.
-     *
-     * Only used for emitting atoms.
-     *
-     * @param state The state that SystemUI is handling during the consent flow. Must be a valid
-     *   state defined in the MediaProjectionState enum.
-     * @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED.
-     *   Indicates the entry point for requesting the permission. Must be a valid state defined in
-     *   the SessionCreationSource enum.
-     */
-    private fun notifyToServer(state: Int, sessionCreationSource: SessionCreationSource) {
-        Log.v(TAG, "FOO notifyToServer of state $state and source $sessionCreationSource")
-        try {
-            service.notifyPermissionRequestStateChange(
-                Process.myUid(),
-                state,
-                sessionCreationSource.toMetricsConstant()
-            )
-        } catch (e: RemoteException) {
-            Log.e(
-                TAG,
-                "Error notifying server of permission flow state $state from source " +
-                    "$sessionCreationSource",
-                e
-            )
-        }
-    }
-
     companion object {
         const val TAG = "MediaProjectionMetricsLogger"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index 04d5566..50e9e751 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -210,6 +210,10 @@
                 reviewGrantedConsentRequired,
                 /* projection= */ null
             )
+            if (isFinishing) {
+                // Only log dismissed when actually finishing, and not when changing configuration.
+                controller.onSelectorDismissed()
+            }
         }
         activityLauncher.destroy()
         controller.destroy()
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index 67ef119..575e198 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -18,7 +18,6 @@
 
 import android.content.ComponentName
 import android.os.UserHandle
-import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED as STATE_APP_SELECTOR_DISPLAYED
 import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
@@ -76,6 +75,10 @@
         scope.cancel()
     }
 
+    fun onSelectorDismissed() {
+        logger.notifyProjectionRequestCancelled(hostUid)
+    }
+
     private suspend fun refreshForegroundTaskThumbnails(tasks: List<RecentTask>) {
         coroutineScope {
             val thumbnails: List<Deferred<ThumbnailData?>> =
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
index 8b437c3..eea369f 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseScreenSharePermissionDialog.kt
@@ -32,6 +32,7 @@
 import androidx.annotation.DrawableRes
 import androidx.annotation.LayoutRes
 import androidx.annotation.StringRes
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.SystemUIDialog
 
@@ -40,16 +41,31 @@
     context: Context,
     private val screenShareOptions: List<ScreenShareOption>,
     private val appName: String?,
+    private val hostUid: Int,
+    private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
     @DrawableRes private val dialogIconDrawable: Int? = null,
-    @ColorRes private val dialogIconTint: Int? = null
+    @ColorRes private val dialogIconTint: Int? = null,
 ) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
     private lateinit var dialogTitle: TextView
     private lateinit var startButton: TextView
     private lateinit var cancelButton: TextView
     private lateinit var warning: TextView
     private lateinit var screenShareModeSpinner: Spinner
+    private var hasCancelBeenLogged: Boolean = false
     var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
 
+    override fun dismiss() {
+        super.dismiss()
+
+        // Dismiss can be called multiple times and we only want to log once.
+        if (hasCancelBeenLogged) {
+            return
+        }
+
+        mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
+        hasCancelBeenLogged = true
+    }
+
     public override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         window?.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index f7cc589..eacfa57 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -222,13 +222,19 @@
         // the correct screen width when in split screen.
         Context dialogContext = getApplicationContext();
         if (isPartialScreenSharingEnabled()) {
-            mDialog = new MediaProjectionPermissionDialog(dialogContext, getMediaProjectionConfig(),
+            mDialog = new MediaProjectionPermissionDialog(
+                    dialogContext,
+                    getMediaProjectionConfig(),
                     () -> {
                         MediaProjectionPermissionDialog dialog =
                                 (MediaProjectionPermissionDialog) mDialog;
                         ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
                         grantMediaProjectionPermission(selectedOption.getMode());
-                    }, () -> finish(RECORD_CANCEL, /* projection= */ null), appName);
+                    },
+                    () -> finish(RECORD_CANCEL, /* projection= */ null),
+                    appName,
+                    mUid,
+                    mMediaProjectionMetricsLogger);
         } else {
             AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(dialogContext,
                     R.style.Theme_SystemUI_Dialog)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
index b9bafd4..cff22b0 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialog.kt
@@ -18,6 +18,7 @@
 import android.content.Context
 import android.media.projection.MediaProjectionConfig
 import android.os.Bundle
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
 import com.android.systemui.res.R
 
 /** Dialog to select screen recording options */
@@ -26,12 +27,16 @@
     mediaProjectionConfig: MediaProjectionConfig?,
     private val onStartRecordingClicked: Runnable,
     private val onCancelClicked: Runnable,
-    private val appName: String?
+    private val appName: String?,
+    hostUid: Int,
+    mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
 ) :
     BaseScreenSharePermissionDialog(
         context,
         createOptionList(context, appName, mediaProjectionConfig),
-        appName
+        appName,
+        hostUid,
+        mediaProjectionMetricsLogger
     ) {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
index 4096226..7b4b557 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
@@ -78,7 +78,10 @@
         super.onCreate(savedInstanceState)
         uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN)
 
-        setContentView(LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null))
+        LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply {
+            accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings)
+            setContentView(this)
+        }
 
         toggleView = requireViewById(R.id.bluetooth_toggle)
         subtitleTextView = requireViewById(R.id.bluetooth_tile_dialog_subtitle) as TextView
@@ -114,14 +117,22 @@
     }
 
     internal fun onBluetoothStateUpdated(isEnabled: Boolean, subtitleResId: Int) {
-        toggleView.isChecked = isEnabled
+        toggleView.apply {
+            isChecked = isEnabled
+            setEnabled(true)
+            alpha = ENABLED_ALPHA
+        }
         subtitleTextView.text = context.getString(subtitleResId)
     }
 
     private fun setupToggle() {
         toggleView.isChecked = bluetoothToggleInitialValue
-        toggleView.setOnCheckedChangeListener { _, isChecked ->
+        toggleView.setOnCheckedChangeListener { view, isChecked ->
             mutableBluetoothStateToggle.value = isChecked
+            view.apply {
+                isEnabled = false
+                alpha = DISABLED_ALPHA
+            }
             logger.logBluetoothState(BluetoothStateStage.USER_TOGGLED, isChecked.toString())
             uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED)
         }
@@ -225,5 +236,7 @@
         const val ACTION_PREVIOUSLY_CONNECTED_DEVICE =
             "com.android.settings.PREVIOUSLY_CONNECTED_DEVICE"
         const val ACTION_PAIR_NEW_DEVICE = "android.settings.BLUETOOTH_PAIRING_SETTINGS"
+        const val DISABLED_ALPHA = 0.3f
+        const val ENABLED_ALPHA = 1f
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index ea1205a..05f125f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -163,8 +163,7 @@
         }
 
         mMediaProjectionMetricsLogger.notifyProjectionInitiated(
-                mUserContextProvider.getUserContext().getUserId(),
-                SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
+                getHostUid(), SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
 
         return flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)
                 ? new ScreenRecordPermissionDialog(
@@ -174,7 +173,8 @@
                         /* controller= */ this,
                         activityStarter,
                         mUserContextProvider,
-                        onStartRecordingClicked)
+                        onStartRecordingClicked,
+                        mMediaProjectionMetricsLogger)
                 : new ScreenRecordDialog(
                         context,
                         /* controller= */ this,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index f2e94e9..e7481cc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -66,8 +66,10 @@
     private Switch mAudioSwitch;
     private Spinner mOptions;
 
-    public ScreenRecordDialog(Context context, RecordingController controller,
-            UserContextProvider userContextProvider, @Nullable Runnable onStartRecordingClicked) {
+    public ScreenRecordDialog(Context context,
+                              RecordingController controller,
+                              UserContextProvider userContextProvider,
+                              @Nullable Runnable onStartRecordingClicked) {
         super(context);
         mController = controller;
         mUserContextProvider = userContextProvider;
@@ -89,7 +91,6 @@
 
         TextView cancelBtn = findViewById(R.id.button_cancel);
         cancelBtn.setOnClickListener(v -> dismiss());
-
         TextView startBtn = findViewById(R.id.button_start);
         startBtn.setOnClickListener(v -> {
             if (mOnStartRecordingClicked != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index 3b3aa53..f74234b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -33,6 +33,7 @@
 import android.widget.Switch
 import androidx.annotation.LayoutRes
 import com.android.systemui.mediaprojection.MediaProjectionCaptureTarget
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
 import com.android.systemui.mediaprojection.permission.BaseScreenSharePermissionDialog
 import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
@@ -50,12 +51,15 @@
     private val controller: RecordingController,
     private val activityStarter: ActivityStarter,
     private val userContextProvider: UserContextProvider,
-    private val onStartRecordingClicked: Runnable?
+    private val onStartRecordingClicked: Runnable?,
+    mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
 ) :
     BaseScreenSharePermissionDialog(
         context,
         createOptionList(),
         appName = null,
+        hostUid = hostUid,
+        mediaProjectionMetricsLogger,
         R.drawable.ic_screenrecord,
         R.color.screenrecord_icon_color
     ) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 33c42e0..ab015ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -72,10 +72,10 @@
         return findViewById(R.id.no_notifications_footer);
     }
 
-    public void setTextColor(@ColorInt int color) {
-        mEmptyText.setTextColor(color);
-        mEmptyFooterText.setTextColor(color);
-        mEmptyFooterText.setCompoundDrawableTintList(ColorStateList.valueOf(color));
+    public void setTextColors(@ColorInt int onSurface, @ColorInt int onSurfaceVariant) {
+        mEmptyText.setTextColor(onSurfaceVariant);
+        mEmptyFooterText.setTextColor(onSurface);
+        mEmptyFooterText.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
     }
 
     public void setText(@StringRes int text) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
index ba91654..9c51e3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java
@@ -234,26 +234,24 @@
      */
     public void updateColors() {
         Resources.Theme theme = mContext.getTheme();
-        final @ColorInt int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+        final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(mContext,
+                com.android.internal.R.attr.materialColorOnSurface);
+        final @ColorInt int scHigh = Utils.getColorAttrDefaultColor(mContext,
+                com.android.internal.R.attr.materialColorSurfaceContainerHigh);
         final Drawable clearAllBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
         final Drawable manageBg = theme.getDrawable(R.drawable.notif_footer_btn_background);
         // TODO(b/282173943): Remove redundant tinting once Resources are thread-safe
-        final @ColorInt int buttonBgColor =
-                Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface);
-        final ColorFilter bgColorFilter = new PorterDuffColorFilter(buttonBgColor, SRC_ATOP);
-        if (buttonBgColor != 0) {
+        final ColorFilter bgColorFilter = new PorterDuffColorFilter(scHigh, SRC_ATOP);
+        if (scHigh != 0) {
             clearAllBg.setColorFilter(bgColorFilter);
             manageBg.setColorFilter(bgColorFilter);
         }
         mClearAllButton.setBackground(clearAllBg);
-        mClearAllButton.setTextColor(textColor);
+        mClearAllButton.setTextColor(onSurface);
         mManageButton.setBackground(manageBg);
-        mManageButton.setTextColor(textColor);
-        final @ColorInt int labelTextColor =
-                Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
-        mSeenNotifsFooterTextView.setTextColor(labelTextColor);
-        mSeenNotifsFooterTextView.setCompoundDrawableTintList(
-                ColorStateList.valueOf(labelTextColor));
+        mManageButton.setTextColor(onSurface);
+        mSeenNotifsFooterTextView.setTextColor(onSurface);
+        mSeenNotifsFooterTextView.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));
     }
 
     private void updateResources() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
new file mode 100644
index 0000000..4ef80e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionSuppressor.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+package com.android.systemui.statusbar.notification.interruption
+
+import com.android.internal.logging.UiEventLogger.UiEventEnum
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+
+/**
+ * A reason why visual interruptions might be suppressed.
+ *
+ * @see VisualInterruptionCondition
+ * @see VisualInterruptionFilter
+ */
+enum class VisualInterruptionType {
+    /* HUN when awake */
+    PEEK,
+
+    /* HUN when dozing */
+    PULSE,
+
+    /* Bubble */
+    BUBBLE
+}
+
+/**
+ * A reason why visual interruptions might be suppressed.
+ *
+ * @see VisualInterruptionCondition
+ * @see VisualInterruptionFilter
+ */
+sealed interface VisualInterruptionSuppressor {
+    /** The type(s) of interruption that this suppresses. */
+    val types: Set<VisualInterruptionType>
+
+    /** A human-readable string to be logged to explain why this suppressed an interruption. */
+    val reason: String
+
+    /** An optional UiEvent ID to be recorded when this suppresses an interruption. */
+    val uiEventId: UiEventEnum?
+}
+
+/** A reason why visual interruptions might be suppressed regardless of the notification. */
+abstract class VisualInterruptionCondition(
+    override val types: Set<VisualInterruptionType>,
+    override val reason: String,
+    override val uiEventId: UiEventEnum? = null
+) : VisualInterruptionSuppressor {
+    /** @return true if these interruptions should be suppressed right now. */
+    abstract fun shouldSuppress(): Boolean
+}
+
+/** A reason why visual interruptions might be suppressed based on the notification. */
+abstract class VisualInterruptionFilter(
+    override val types: Set<VisualInterruptionType>,
+    override val reason: String,
+    override val uiEventId: UiEventEnum? = null
+) : VisualInterruptionSuppressor {
+    /**
+     * @param entry the notification to consider suppressing
+     * @return true if these interruptions should be suppressed for this notification right now
+     */
+    abstract fun shouldSuppress(entry: NotificationEntry): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 661768d..8f1e59d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -121,7 +121,7 @@
 
     private void updateColors() {
         mNormalColor = Utils.getColorAttrDefaultColor(mContext,
-                com.android.internal.R.attr.colorSurface);
+                com.android.internal.R.attr.materialColorSurfaceContainerHigh);
         mTintedRippleColor = mContext.getColor(
                 R.color.notification_ripple_tinted_color);
         mNormalRippleColor = mContext.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
index 892a635..da8c4dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java
@@ -28,7 +28,6 @@
 
 import androidx.annotation.ColorInt;
 
-import com.android.internal.util.ContrastColorUtil;
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
@@ -98,8 +97,8 @@
     private void resolveThemeTextColors() {
         try (TypedArray ta = mContext.getTheme().obtainStyledAttributes(
                 android.R.style.Theme_DeviceDefault_DayNight, new int[]{
-                        android.R.attr.textColorPrimary,
-                        android.R.attr.textColorSecondary
+                        com.android.internal.R.attr.materialColorOnSurface,
+                        com.android.internal.R.attr.materialColorOnSurfaceVariant
                 })) {
             if (ta != null) {
                 mPrimaryTextColor = ta.getColor(0, mPrimaryTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 62b268b..14593cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -65,10 +65,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.notification.ConversationIconFactory;
-import com.android.systemui.res.R;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
+import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.notification.NotificationChannelHelper;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -336,10 +336,11 @@
         Drawable person =  mIconFactory.getBaseIconDrawable(mShortcutInfo);
         if (person == null) {
             person = mContext.getDrawable(R.drawable.ic_person).mutate();
-            TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
-            int colorAccent = ta.getColor(0, 0);
+            TypedArray ta = mContext.obtainStyledAttributes(
+                    new int[]{com.android.internal.R.attr.materialColorPrimary});
+            int colorPrimary = ta.getColor(0, 0);
             ta.recycle();
-            person.setTint(colorAccent);
+            person.setTint(colorPrimary);
         }
         ImageView image = findViewById(R.id.conversation_icon);
         image.setImageDrawable(person);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index ff5b9cb..cdf178e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -326,7 +326,8 @@
         if (customBackgroundColor != 0) {
             return customBackgroundColor;
         }
-        return Utils.getColorAttr(mView.getContext(), android.R.attr.colorBackground)
+        return Utils.getColorAttr(mView.getContext(),
+                        com.android.internal.R.attr.materialColorSurfaceContainerHigh)
                 .getDefaultColor();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index a929e4f..0236fc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -1362,7 +1362,7 @@
         Resources.Theme theme = new ContextThemeWrapper(mContext,
                 com.android.internal.R.style.Theme_DeviceDefault_DayNight).getTheme();
         try (TypedArray ta = theme.obtainStyledAttributes(
-                new int[]{com.android.internal.R.attr.colorAccent})) {
+                new int[]{com.android.internal.R.attr.materialColorPrimary})) {
             color = ta.getColor(0, color);
         }
         mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, color);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index fd064ee..cfc433a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -244,10 +244,10 @@
         }
     }
 
-    fun setHeaderForegroundColor(@ColorInt color: Int) {
-        peopleHeaderView?.setForegroundColor(color)
-        silentHeaderView?.setForegroundColor(color)
-        alertingHeaderView?.setForegroundColor(color)
+    fun setHeaderForegroundColors(@ColorInt onSurface: Int, @ColorInt onSurfaceVariant: Int) {
+        peopleHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+        silentHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+        alertingHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1e9cfa8..8babcc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -344,7 +344,7 @@
     private boolean mAnimateNextBackgroundTop;
     private boolean mAnimateNextBackgroundBottom;
     private boolean mAnimateNextSectionBoundsChange;
-    private int mBgColor;
+    private @ColorInt int mBgColor;
     private float mDimAmount;
     private ValueAnimator mDimAnimator;
     private final ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
@@ -647,8 +647,8 @@
         mSections = mSectionsManager.createSectionsForBuckets();
 
         mAmbientState = Dependency.get(AmbientState.class);
-        mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackgroundFloating)
-                .getDefaultColor();
+        mBgColor = Utils.getColorAttr(mContext,
+                com.android.internal.R.attr.materialColorSurfaceContainerHigh).getDefaultColor();
         int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
         int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
         mSplitShadeMinContentHeight = res.getDimensionPixelSize(
@@ -790,8 +790,8 @@
     }
 
     void updateBgColor() {
-        mBgColor = Utils.getColorAttr(mContext, android.R.attr.colorBackgroundFloating)
-                .getDefaultColor();
+        mBgColor = Utils.getColorAttr(mContext,
+                com.android.internal.R.attr.materialColorSurfaceContainerHigh).getDefaultColor();
         updateBackgroundDimming();
         for (int i = 0; i < getChildCount(); i++) {
             View child = getChildAt(i);
@@ -4421,14 +4421,19 @@
     }
 
     /**
-     * Update colors of "dismiss" and "empty shade" views.
+     * Update colors of section headers, shade footer, and empty shade views.
      */
     void updateDecorViews() {
-        final @ColorInt int textColor =
-                Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
-        mSectionsManager.setHeaderForegroundColor(textColor);
+        final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(
+                mContext, com.android.internal.R.attr.materialColorOnSurface);
+        final @ColorInt int onSurfaceVariant = Utils.getColorAttrDefaultColor(
+                mContext, com.android.internal.R.attr.materialColorOnSurfaceVariant);
+
+        mSectionsManager.setHeaderForegroundColors(onSurface, onSurfaceVariant);
+
         mFooterView.updateColors();
-        mEmptyShadeView.setTextColor(textColor);
+
+        mEmptyShadeView.setTextColors(onSurface, onSurfaceVariant);
     }
 
     void goToFullShade(long delay) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index 722c28c..5c1149b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -132,8 +132,8 @@
         mLabelView.setText(resId);
     }
 
-    void setForegroundColor(@ColorInt int color) {
-        mLabelView.setTextColor(color);
-        mClearAllButton.setImageTintList(ColorStateList.valueOf(color));
+    void setForegroundColors(@ColorInt int onSurface, @ColorInt int onSurfaceVariant) {
+        mLabelView.setTextColor(onSurface);
+        mClearAllButton.setImageTintList(ColorStateList.valueOf(onSurfaceVariant));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 744d70e..3e753a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1505,8 +1505,9 @@
     private void updateThemeColors() {
         if (mScrimBehind == null) return;
         int background = Utils.getColorAttr(mScrimBehind.getContext(),
-                android.R.attr.colorBackgroundFloating).getDefaultColor();
-        int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
+                com.android.internal.R.attr.materialColorSurfaceDim).getDefaultColor();
+        int accent = Utils.getColorAttr(mScrimBehind.getContext(),
+                com.android.internal.R.attr.materialColorPrimary).getDefaultColor();
         mColors.setMainColor(background);
         mColors.setSecondaryColor(accent);
         final boolean isBackgroundLight = !ContrastColorUtil.isColorDark(background);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
index a033e1d..66ac17e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.annotation.ColorInt;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.View;
@@ -28,6 +29,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.res.R;
 import com.android.wm.shell.animation.Interpolators;
 
@@ -49,8 +51,9 @@
     }
 
     void updateColor() {
-        int textColor = getResources().getColor(R.color.notif_pill_text, mContext.getTheme());
-        setTextColor(textColor);
+        final @ColorInt int onSurface = Utils.getColorAttrDefaultColor(mContext,
+                com.android.internal.R.attr.materialColorOnSurface);
+        setTextColor(onSurface);
         setBackground(getResources().getDrawable(R.drawable.rounded_bg_full, mContext.getTheme()));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 27f6df4..d9d909a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.model
 
 import android.os.ParcelUuid
+import android.telephony.SubscriptionManager.ProfileClass
 
 /**
  * SystemUI representation of [SubscriptionInfo]. Currently we only use two fields on the
@@ -37,4 +38,7 @@
 
     /** Text representing the name for this connection */
     val carrierName: String,
+
+    /** Allow us to filter out PROVISIONING profiles. See [SubscriptionInfo.getProfileClass] */
+    @ProfileClass val profileClass: Int
 )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index c7987e2..205dc1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.util.Log
 import com.android.settingslib.SignalIcon
 import com.android.settingslib.mobile.MobileMappings
@@ -96,6 +97,7 @@
                     subscriptionId = subId,
                     isOpportunistic = false,
                     carrierName = DEFAULT_CARRIER_NAME,
+                    profileClass = PROFILE_CLASS_UNSET,
                 )
                 .also { subscriptionInfoCache[subId] = it }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index ecb80f2..2caf33b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -408,6 +408,7 @@
             isOpportunistic = isOpportunistic,
             groupUuid = groupUuid,
             carrierName = carrierName.toString(),
+            profileClass = profileClass,
         )
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 62150e9..dad4093 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -19,10 +19,13 @@
 import android.content.Context
 import android.telephony.CarrierConfigManager
 import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
 import com.android.settingslib.SignalIcon.MobileIconGroup
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
@@ -121,6 +124,7 @@
     userSetupRepo: UserSetupRepository,
     @Application private val scope: CoroutineScope,
     private val context: Context,
+    private val featureFlagsClassic: FeatureFlagsClassic,
 ) : MobileIconsInteractor {
 
     // Weak reference lookup for created interactors
@@ -163,6 +167,20 @@
         mobileConnectionsRepo.subscriptions
 
     /**
+     * Any filtering that we can do based purely on the info of each subscription. Currently this
+     * only applies the ProfileClass-based filter, but if we need other they can go here
+     */
+    private val subscriptionsBasedFilteredSubs =
+        unfilteredSubscriptions.map { subs -> applyProvisioningFilter(subs) }.distinctUntilChanged()
+
+    private fun applyProvisioningFilter(subs: List<SubscriptionModel>): List<SubscriptionModel> =
+        if (!featureFlagsClassic.isEnabled(FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS)) {
+            subs
+        } else {
+            subs.filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
+        }
+
+    /**
      * Generally, SystemUI wants to show iconography for each subscription that is listed by
      * [SubscriptionManager]. However, in the case of opportunistic subscriptions, we want to only
      * show a single representation of the pair of subscriptions. The docs define opportunistic as:
@@ -177,48 +195,15 @@
      */
     override val filteredSubscriptions: Flow<List<SubscriptionModel>> =
         combine(
-                unfilteredSubscriptions,
+                subscriptionsBasedFilteredSubs,
                 mobileConnectionsRepo.activeMobileDataSubscriptionId,
                 connectivityRepository.vcnSubId,
             ) { unfilteredSubs, activeId, vcnSubId ->
-                // Based on the old logic,
-                if (unfilteredSubs.size != 2) {
-                    return@combine unfilteredSubs
-                }
-
-                val info1 = unfilteredSubs[0]
-                val info2 = unfilteredSubs[1]
-
-                // Filtering only applies to subscriptions in the same group
-                if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
-                    return@combine unfilteredSubs
-                }
-
-                // If both subscriptions are primary, show both
-                if (!info1.isOpportunistic && !info2.isOpportunistic) {
-                    return@combine unfilteredSubs
-                }
-
-                // NOTE: at this point, we are now returning a single SubscriptionInfo
-
-                // If carrier required, always show the icon of the primary subscription.
-                // Otherwise, show whichever subscription is currently active for internet.
-                if (carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) {
-                    // return the non-opportunistic info
-                    return@combine if (info1.isOpportunistic) listOf(info2) else listOf(info1)
-                } else {
-                    // It's possible for the subId of the VCN to disagree with the active subId in
-                    // cases where the system has tried to switch but found no connection. In these
-                    // scenarios, VCN will always have the subId that we want to use, so use that
-                    // value instead of the activeId reported by telephony
-                    val subIdToKeep = vcnSubId ?: activeId
-
-                    return@combine if (info1.subscriptionId == subIdToKeep) {
-                        listOf(info1)
-                    } else {
-                        listOf(info2)
-                    }
-                }
+                filterSubsBasedOnOpportunistic(
+                    unfilteredSubs,
+                    activeId,
+                    vcnSubId,
+                )
             }
             .distinctUntilChanged()
             .logDiffsForTable(
@@ -229,6 +214,51 @@
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
 
+    private fun filterSubsBasedOnOpportunistic(
+        subList: List<SubscriptionModel>,
+        activeId: Int?,
+        vcnSubId: Int?,
+    ): List<SubscriptionModel> {
+        // Based on the old logic,
+        if (subList.size != 2) {
+            return subList
+        }
+
+        val info1 = subList[0]
+        val info2 = subList[1]
+
+        // Filtering only applies to subscriptions in the same group
+        if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
+            return subList
+        }
+
+        // If both subscriptions are primary, show both
+        if (!info1.isOpportunistic && !info2.isOpportunistic) {
+            return subList
+        }
+
+        // NOTE: at this point, we are now returning a single SubscriptionInfo
+
+        // If carrier required, always show the icon of the primary subscription.
+        // Otherwise, show whichever subscription is currently active for internet.
+        if (carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) {
+            // return the non-opportunistic info
+            return if (info1.isOpportunistic) listOf(info2) else listOf(info1)
+        } else {
+            // It's possible for the subId of the VCN to disagree with the active subId in
+            // cases where the system has tried to switch but found no connection. In these
+            // scenarios, VCN will always have the subId that we want to use, so use that
+            // value instead of the activeId reported by telephony
+            val subIdToKeep = vcnSubId ?: activeId
+
+            return if (info1.subscriptionId == subIdToKeep) {
+                listOf(info1)
+            } else {
+                listOf(info2)
+            }
+        }
+    }
+
     /**
      * Copied from the old pipeline. We maintain a 2s period of time where we will keep the
      * validated bit from the old active network (A) while data is changing to the new one (B).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index ceed81a..4864fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -130,7 +130,7 @@
     private ImageView mDelete;
     private ImageView mDeleteBg;
     private boolean mColorized;
-    private int mTint;
+    private int mLastBackgroundColor;
     private boolean mResetting;
     @Nullable
     private RevealParams mRevealParams;
@@ -181,10 +181,9 @@
         mEditorActionHandler = new EditorActionHandler();
         mUiEventLogger = Dependency.get(UiEventLogger.class);
         TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
-                com.android.internal.R.attr.colorAccent,
-                com.android.internal.R.attr.colorSurface,
+                com.android.internal.R.attr.materialColorSurfaceDim,
         });
-        mTint = ta.getColor(0, 0);
+        mLastBackgroundColor = ta.getColor(0, 0);
         ta.recycle();
     }
 
@@ -210,9 +209,9 @@
      * @param backgroundColor colorized notification color
      */
     public void setBackgroundTintColor(final int backgroundColor, boolean colorized) {
-        if (colorized == mColorized && backgroundColor == mTint) return;
+        if (colorized == mColorized && backgroundColor == mLastBackgroundColor) return;
         mColorized = colorized;
-        mTint = backgroundColor;
+        mLastBackgroundColor = backgroundColor;
         final int editBgColor;
         final int deleteBgColor;
         final int deleteFgColor;
@@ -237,8 +236,8 @@
             hintColor = mContext.getColor(R.color.remote_input_hint);
             deleteFgColor = textColor.getDefaultColor();
             try (TypedArray ta = getContext().getTheme().obtainStyledAttributes(new int[]{
-                    com.android.internal.R.attr.colorSurfaceHighlight,
-                    com.android.internal.R.attr.colorSurfaceVariant
+                    com.android.internal.R.attr.materialColorSurfaceDim,
+                    com.android.internal.R.attr.materialColorSurfaceVariant
             })) {
                 editBgColor = ta.getColor(0, backgroundColor);
                 deleteBgColor = ta.getColor(1, Color.GRAY);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 0ff308e..280c66a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -99,7 +99,6 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -256,7 +255,6 @@
     private CaptionsToggleImageButton mODICaptionsIcon;
     private View mSettingsView;
     private ImageButton mSettingsIcon;
-    private FrameLayout mZenIcon;
     private final List<VolumeRow> mRows = new ArrayList<>();
     private ConfigurableTexts mConfigurableTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -633,7 +631,6 @@
         mRinger = mDialog.findViewById(R.id.ringer);
         if (mRinger != null) {
             mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
-            mZenIcon = mRinger.findViewById(R.id.dnd_icon);
         }
 
         mSelectedRingerIcon = mDialog.findViewById(R.id.volume_new_ringer_active_icon);
@@ -847,7 +844,6 @@
         if (stream == STREAM_ACCESSIBILITY) {
             row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
         }
-        row.dndIcon = row.view.findViewById(R.id.dnd_icon);
         row.slider = row.view.findViewById(R.id.volume_row_slider);
         row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
         row.number = row.view.findViewById(R.id.volume_number);
@@ -1791,27 +1787,13 @@
     }
 
     /**
-     * Toggles enable state of views in a VolumeRow (not including seekbar or icon)
-     * Hides/shows zen icon
-     * @param enable whether to enable volume row views and hide dnd icon
-     */
-    private void enableVolumeRowViewsH(VolumeRow row, boolean enable) {
-        boolean showDndIcon = !enable;
-        row.dndIcon.setVisibility(showDndIcon ? VISIBLE : GONE);
-    }
-
-    /**
      * Toggles enable state of footer/ringer views
-     * Hides/shows zen icon
-     * @param enable whether to enable ringer views and hide dnd icon
+     * @param enable whether to enable ringer views
      */
     private void enableRingerViewsH(boolean enable) {
         if (mRingerIcon != null) {
             mRingerIcon.setEnabled(enable);
         }
-        if (mZenIcon != null) {
-            mZenIcon.setVisibility(enable ? GONE : VISIBLE);
-        }
     }
 
     private void trimObsoleteH() {
@@ -1937,9 +1919,11 @@
         // update icon
         final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
         final int iconRes;
-        if (isRingVibrate) {
+        if (zenMuted) {
+            iconRes = com.android.internal.R.drawable.ic_qs_dnd;
+        } else if (isRingVibrate) {
             iconRes = R.drawable.ic_volume_ringer_vibrate;
-        } else if (isRingSilent || zenMuted) {
+        } else if (isRingSilent) {
             iconRes = row.iconMuteRes;
         } else if (ss.routedToBluetooth) {
             if (isVoiceCallStream) {
@@ -2011,7 +1995,6 @@
         if (zenMuted) {
             row.tracking = false;
         }
-        enableVolumeRowViewsH(row, !zenMuted);
 
         // update slider
         final boolean enableSlider = !zenMuted;
@@ -2582,7 +2565,6 @@
         private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
         private int animTargetProgress;
         private int lastAudibleLevel = 1;
-        private FrameLayout dndIcon;
 
         void setIcon(int iconRes, Resources.Theme theme) {
             if (icon != null) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
index ac40ba6..603d548 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -21,7 +21,6 @@
 import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
 import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
 import static com.android.systemui.flags.Flags.MIGRATE_KEYGUARD_STATUS_VIEW;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.atLeast;
@@ -58,7 +57,6 @@
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore;
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.NotificationIconContainer;
@@ -144,7 +142,6 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
         mFakeDateView.setTag(R.id.tag_smartspace_view, new Object());
         mFakeWeatherView.setTag(R.id.tag_smartspace_view, new Object());
         mFakeSmartspaceView.setTag(R.id.tag_smartspace_view, new Object());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MockMagnificationAnimationCallback.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MockMagnificationAnimationCallback.java
deleted file mode 100644
index 89389b0..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MockMagnificationAnimationCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.systemui.accessibility;
-
-import android.os.RemoteException;
-import android.view.accessibility.IRemoteMagnificationAnimationCallback;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class MockMagnificationAnimationCallback extends IRemoteMagnificationAnimationCallback.Stub {
-
-    private final CountDownLatch mCountDownLatch;
-    private final AtomicInteger mSuccessCount;
-    private final AtomicInteger mFailedCount;
-
-    MockMagnificationAnimationCallback(CountDownLatch countDownLatch) {
-        mCountDownLatch = countDownLatch;
-        mSuccessCount = new AtomicInteger();
-        mFailedCount = new AtomicInteger();
-    }
-
-    public int getSuccessCount() {
-        return mSuccessCount.get();
-    }
-
-    public int getFailedCount() {
-        return mFailedCount.get();
-    }
-
-    @Override
-    public void onResult(boolean success) throws RemoteException {
-        if (success) {
-            mSuccessCount.getAndIncrement();
-        } else {
-            mFailedCount.getAndIncrement();
-        }
-        // It should be put at the last line to avoid making CountDownLatch#await passed without
-        // updating values.
-        mCountDownLatch.countDown();
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index f15164e..284c273 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -35,7 +35,6 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowManager;
@@ -68,7 +67,6 @@
 
 @LargeTest
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper(setAsMainLooper = true)
 public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
 
     @Rule
@@ -135,7 +133,9 @@
 
     @After
     public void tearDown() throws Exception {
-        mController.deleteWindowMagnification();
+        mInstrumentation.runOnMainSync(() -> {
+            mController.deleteWindowMagnification();
+        });
     }
 
     @Test
@@ -170,8 +170,7 @@
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, null);
+        enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
 
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
     }
@@ -179,10 +178,11 @@
     @Test
     public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()
             throws RemoteException {
-        mWindowMagnificationAnimationController.enableWindowMagnification(1,
+        enableWindowMagnificationAndWaitAnimating(
+                mWaitAnimationDuration, /* targetScale= */ 1.0f,
                 DEFAULT_CENTER_X, DEFAULT_CENTER_Y, mAnimationCallback);
 
-        verify(mSpyController).enableWindowMagnificationInternal(1, DEFAULT_CENTER_X,
+        verify(mSpyController).enableWindowMagnificationInternal(1.0f, DEFAULT_CENTER_X,
                 DEFAULT_CENTER_Y, 0f, 0f);
         verify(mAnimationCallback).onResult(true);
     }
@@ -196,13 +196,15 @@
         final float targetCenterX = DEFAULT_CENTER_X + 100;
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
-        Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, mAnimationCallback2);
-        mCurrentScale.set(mController.getScale());
-        mCurrentCenterX.set(mController.getCenterX());
-        mCurrentCenterY.set(mController.getCenterY());
-        advanceTimeBy(mWaitAnimationDuration);
+        resetMockObjects();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                    targetCenterX, targetCenterY, mAnimationCallback2);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -224,9 +226,8 @@
         enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+        enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN,
                 Float.NaN, Float.NaN, mAnimationCallback2);
-        advanceTimeBy(mWaitAnimationDuration);
 
         // The callback in 2nd enableWindowMagnification will return true
         verify(mAnimationCallback2).onResult(true);
@@ -245,12 +246,14 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, mAnimationCallback);
-        mCurrentScale.set(mController.getScale());
-        mCurrentCenterX.set(mController.getCenterX());
-        mCurrentCenterY.set(mController.getCenterY());
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                    targetCenterX, targetCenterY, mAnimationCallback);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -279,12 +282,14 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, mAnimationCallback);
-        mCurrentScale.set(mController.getScale());
-        mCurrentCenterX.set(mController.getCenterX());
-        mCurrentCenterY.set(mController.getCenterY());
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                    targetCenterX, targetCenterY, mAnimationCallback);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -314,8 +319,7 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, null);
+        enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
 
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         assertEquals(WindowMagnificationAnimationController.STATE_DISABLED,
@@ -333,8 +337,7 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, null);
+        enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
 
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
         verify(mAnimationCallback).onResult(false);
@@ -347,9 +350,8 @@
                 mAnimationCallback);
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
-                Float.NaN, Float.NaN, mAnimationCallback2);
-        advanceTimeBy(mWaitAnimationDuration);
+        enableWindowMagnificationAndWaitAnimating(
+                mWaitAnimationDuration, Float.NaN, Float.NaN, Float.NaN, mAnimationCallback2);
 
         verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
@@ -368,20 +370,25 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, mAnimationCallback2);
-        mCurrentScale.set(mController.getScale());
-        mCurrentCenterX.set(mController.getCenterX());
-        mCurrentCenterY.set(mController.getCenterY());
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                    targetCenterX, targetCenterY, mAnimationCallback2);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+        });
 
         // Current spec shouldn't match given spec.
         verify(mAnimationCallback2, never()).onResult(anyBoolean());
         verify(mAnimationCallback).onResult(false);
-        // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it is
-        // using SystemClock in reverse() (b/305731398). Therefore, we call end() on the animator
-        // directly to verify the result of animation is correct instead of querying the animation
-        // frame at a specific timing.
-        mValueAnimator.end();
+
+        mInstrumentation.runOnMainSync(() -> {
+            // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it
+            // is using SystemClock in reverse() (b/305731398). Therefore, we call end() on the
+            // animator directly to verify the result of animation is correct instead of querying
+            // the animation frame at a specific timing.
+            mValueAnimator.end();
+        });
 
         verify(mSpyController).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -410,8 +417,7 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, null);
+        enableWindowMagnificationWithoutAnimation(targetScale, targetCenterX, targetCenterY);
 
         verify(mAnimationCallback).onResult(false);
         verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
@@ -425,9 +431,8 @@
                 mAnimationCallback);
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(Float.NaN,
+        enableWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, Float.NaN,
                 Float.NaN, Float.NaN, mAnimationCallback2);
-        advanceTimeBy(mWaitAnimationDuration);
 
         verify(mSpyController, never()).enableWindowMagnificationInternal(anyFloat(), anyFloat(),
                 anyFloat());
@@ -445,12 +450,14 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
-                targetCenterX, targetCenterY, mAnimationCallback2);
-        mCurrentScale.set(mController.getScale());
-        mCurrentCenterX.set(mController.getCenterX());
-        mCurrentCenterY.set(mController.getCenterY());
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
+                    targetCenterX, targetCenterY, mAnimationCallback2);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -471,25 +478,26 @@
         final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
-                windowBounds.exactCenterX(), windowBounds.exactCenterY(),
-                offsetRatio, offsetRatio, mAnimationCallback);
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
+                    windowBounds.exactCenterX(), windowBounds.exactCenterY(),
+                    offsetRatio, offsetRatio, mAnimationCallback);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
-        // We delay the time of verifying to wait for the measurement and layout of the view
-        mHandler.postDelayed(() -> {
-            final View attachedView = mWindowManager.getAttachedView();
-            assertNotNull(attachedView);
-            final Rect mirrorViewBound = new Rect();
-            final View mirrorView = attachedView.findViewById(R.id.surface_view);
-            assertNotNull(mirrorView);
-            mirrorView.getBoundsOnScreen(mirrorViewBound);
+        // Wait for Rects update
+        waitForIdleSync();
+        final View attachedView = mWindowManager.getAttachedView();
+        assertNotNull(attachedView);
+        final Rect mirrorViewBound = new Rect();
+        final View mirrorView = attachedView.findViewById(R.id.surface_view);
+        assertNotNull(mirrorView);
+        mirrorView.getBoundsOnScreen(mirrorViewBound);
 
-            assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2),
-                    (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX()));
-            assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2),
-                    (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY()));
-        }, 100);
+        assertEquals((int) (offsetRatio * mirrorViewBound.width() / 2),
+                (int) (mirrorViewBound.exactCenterX() - windowBounds.exactCenterX()));
+        assertEquals((int) (offsetRatio * mirrorViewBound.height() / 2),
+                (int) (mirrorViewBound.exactCenterY() - windowBounds.exactCenterY()));
     }
 
     @Test
@@ -498,9 +506,11 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
         enableWindowMagnificationWithoutAnimation();
 
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                targetCenterX, targetCenterY, mAnimationCallback);
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    targetCenterX, targetCenterY, mAnimationCallback);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         verify(mAnimationCallback).onResult(true);
         verify(mAnimationCallback, never()).onResult(false);
@@ -512,15 +522,17 @@
             throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
 
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, mAnimationCallback);
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, mAnimationCallback);
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, mAnimationCallback);
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, mAnimationCallback2);
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    DEFAULT_CENTER_X + 10, DEFAULT_CENTER_Y + 10, mAnimationCallback);
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    DEFAULT_CENTER_X + 20, DEFAULT_CENTER_Y + 20, mAnimationCallback);
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    DEFAULT_CENTER_X + 30, DEFAULT_CENTER_Y + 30, mAnimationCallback);
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    DEFAULT_CENTER_X + 40, DEFAULT_CENTER_Y + 40, mAnimationCallback2);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         // only the last one callback will return true
         verify(mAnimationCallback2).onResult(true);
@@ -538,9 +550,11 @@
         enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                targetCenterX, targetCenterY, mAnimationCallback2);
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    targetCenterX, targetCenterY, mAnimationCallback2);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         // The callback in moveWindowMagnifierToPosition will return true
         verify(mAnimationCallback2).onResult(true);
@@ -556,9 +570,11 @@
         enableWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
-        mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
-                Float.NaN, Float.NaN, mAnimationCallback2);
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.moveWindowMagnifierToPosition(
+                    Float.NaN, Float.NaN, mAnimationCallback2);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         // The callback in moveWindowMagnifierToPosition will return true
         verify(mAnimationCallback2).onResult(true);
@@ -584,6 +600,7 @@
             throws RemoteException {
         enableWindowMagnificationWithoutAnimation();
 
+        resetMockObjects();
         deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback);
 
         verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
@@ -625,16 +642,18 @@
                 mAnimationCallback);
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.deleteWindowMagnification(
-                mAnimationCallback2);
-        mCurrentScale.set(mController.getScale());
-        mCurrentCenterX.set(mController.getCenterX());
-        mCurrentCenterY.set(mController.getCenterY());
-        // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it is
-        // using SystemClock in reverse() (b/305731398). Therefore, we call end() on the animator
-        // directly to verify the result of animation is correct instead of querying the animation
-        // frame at a specific timing.
-        mValueAnimator.end();
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.deleteWindowMagnification(
+                    mAnimationCallback2);
+            mCurrentScale.set(mController.getScale());
+            mCurrentCenterX.set(mController.getCenterX());
+            mCurrentCenterY.set(mController.getCenterY());
+            // ValueAnimator.reverse() could not work correctly with the AnimatorTestRule since it
+            // is using SystemClock in reverse() (b/305731398). Therefore, we call end() on the
+            // animator directly to verify the result of animation is correct instead of querying
+            // the animation frame at a specific timing.
+            mValueAnimator.end();
+        });
 
         verify(mSpyController).enableWindowMagnificationInternal(
                 mScaleCaptor.capture(),
@@ -661,7 +680,7 @@
                 mAnimationCallback);
 
         Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.deleteWindowMagnification(null);
+        deleteWindowMagnificationWithoutAnimation();
 
         verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
         verify(mAnimationCallback).onResult(false);
@@ -673,6 +692,7 @@
         deleteWindowMagnificationAndWaitAnimating(mWaitPartialAnimationDuration,
                 mAnimationCallback);
 
+        resetMockObjects();
         deleteWindowMagnificationAndWaitAnimating(mWaitAnimationDuration, mAnimationCallback2);
 
         verify(mSpyController).enableWindowMagnificationInternal(
@@ -710,8 +730,7 @@
         final float offsetY =
                 (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
                         + 1.0f;
-
-        mController.moveWindowMagnifier(offsetX, offsetY);
+        mInstrumentation.runOnMainSync(()-> mController.moveWindowMagnifier(offsetX, offsetY));
 
         verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y + offsetY);
@@ -726,8 +745,8 @@
         final float offsetY =
                 (float) Math.floor(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
                         - 1.0f;
-
-        mController.moveWindowMagnifier(offsetX, offsetY);
+        mInstrumentation.runOnMainSync(() ->
+                mController.moveWindowMagnifier(offsetX, offsetY));
 
         verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y);
@@ -742,8 +761,10 @@
                 (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE);
         // while diagonal scrolling enabled,
         //  should move with both offsetX and offsetY without regrading offsetY/offsetX
-        mController.setDiagonalScrolling(true);
-        mController.moveWindowMagnifier(offsetX, offsetY);
+        mInstrumentation.runOnMainSync(() -> {
+            mController.setDiagonalScrolling(true);
+            mController.moveWindowMagnifier(offsetX, offsetY);
+        });
 
         verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
         verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y + offsetY);
@@ -755,9 +776,11 @@
         final float targetCenterY = DEFAULT_CENTER_Y + 100;
         enableWindowMagnificationWithoutAnimation();
 
-        mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY,
-                mAnimationCallback);
-        advanceTimeBy(mWaitAnimationDuration);
+        mInstrumentation.runOnMainSync(() -> {
+            mController.moveWindowMagnifierToPosition(targetCenterX, targetCenterY,
+                    mAnimationCallback);
+            advanceTimeBy(mWaitAnimationDuration);
+        });
 
         verifyFinalSpec(DEFAULT_SCALE, targetCenterX, targetCenterY);
     }
@@ -774,24 +797,49 @@
     }
 
     private void enableWindowMagnificationWithoutAnimation() {
-        Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
-                DEFAULT_CENTER_X, DEFAULT_CENTER_Y, null);
+        enableWindowMagnificationWithoutAnimation(
+                DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
+    }
+
+    private void enableWindowMagnificationWithoutAnimation(
+            float targetScale, float targetCenterX, float targetCenterY) {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(
+                    targetScale, targetCenterX, targetCenterY, null);
+        });
     }
 
     private void enableWindowMagnificationAndWaitAnimating(long duration,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
-        Mockito.reset(mSpyController);
-        mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
-                DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
-        advanceTimeBy(duration);
+        enableWindowMagnificationAndWaitAnimating(
+                duration, DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y, callback);
+    }
+
+    private void enableWindowMagnificationAndWaitAnimating(
+            long duration,
+            float targetScale,
+            float targetCenterX,
+            float targetCenterY,
+            @Nullable IRemoteMagnificationAnimationCallback callback) {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.enableWindowMagnification(
+                    targetScale, targetCenterX, targetCenterY, callback);
+            advanceTimeBy(duration);
+        });
+    }
+
+    private void deleteWindowMagnificationWithoutAnimation() {
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.deleteWindowMagnification(null);
+        });
     }
 
     private void deleteWindowMagnificationAndWaitAnimating(long duration,
             @Nullable IRemoteMagnificationAnimationCallback callback) {
-        resetMockObjects();
-        mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
-        advanceTimeBy(duration);
+        mInstrumentation.runOnMainSync(() -> {
+            mWindowMagnificationAnimationController.deleteWindowMagnification(callback);
+            advanceTimeBy(duration);
+        });
     }
 
     private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 86ae517..06421db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -45,6 +45,7 @@
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -53,6 +54,7 @@
 
 import android.animation.ValueAnimator;
 import android.annotation.IdRes;
+import android.annotation.Nullable;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -89,6 +91,7 @@
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.FakeDisplayTracker;
@@ -102,6 +105,7 @@
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
@@ -111,8 +115,6 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 @LargeTest
@@ -120,12 +122,10 @@
 @RunWith(AndroidTestingRunner.class)
 public class WindowMagnificationControllerTest extends SysuiTestCase {
 
+    @Rule
+    public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule();
+
     private static final int LAYOUT_CHANGE_TIMEOUT_MS = 5000;
-    // The duration couldn't too short, otherwise the animation check on bounce effect
-    // won't work in expectation. (b/299537784)
-    private static final int BOUNCE_EFFECT_DURATION_MS = 2000;
-    private static final long ANIMATION_DURATION_MS = 300;
-    private final long mWaitingAnimationPeriod = 2 * ANIMATION_DURATION_MS;
     @Mock
     private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     @Mock
@@ -134,11 +134,16 @@
     private WindowMagnifierCallback mWindowMagnifierCallback;
     @Mock
     IRemoteMagnificationAnimationCallback mAnimationCallback;
+    @Mock
+    IRemoteMagnificationAnimationCallback mAnimationCallback2;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
     @Mock
     private SecureSettings mSecureSettings;
 
+    private long mWaitAnimationDuration;
+    private long mWaitBounceEffectDuration;
+
     private Handler mHandler;
     private TestableWindowManager mWindowManager;
     private SysUiState mSysUiState;
@@ -194,6 +199,13 @@
             mResources.getConfiguration().orientation = ORIENTATION_PORTRAIT;
         }
 
+        // Using the animation duration in WindowMagnificationAnimationController for testing.
+        mWaitAnimationDuration = mResources.getInteger(
+                com.android.internal.R.integer.config_longAnimTime);
+        // Using the bounce effect duration in WindowMagnificationController for testing.
+        mWaitBounceEffectDuration = mResources.getInteger(
+                com.android.internal.R.integer.config_shortAnimTime);
+
         mWindowMagnificationAnimationController = new WindowMagnificationAnimationController(
                 mContext, mValueAnimator);
         mWindowMagnificationController =
@@ -208,7 +220,6 @@
                         mSysUiState,
                         () -> mWindowSessionSpy,
                         mSecureSettings);
-        mWindowMagnificationController.setBounceEffectDuration(BOUNCE_EFFECT_DURATION_MS);
 
         verify(mMirrorWindowControl).setWindowDelegate(
                 any(MirrorWindowControl.MirrorWindowDelegate.class));
@@ -281,9 +292,9 @@
                     /* magnificationFrameOffsetRatioY= */ 0,
                     Mockito.mock(IRemoteMagnificationAnimationCallback.class));
         });
+        advanceTimeBy(LAYOUT_CHANGE_TIMEOUT_MS);
 
-        verify(mSfVsyncFrameProvider,
-                timeout(LAYOUT_CHANGE_TIMEOUT_MS).atLeast(2)).postFrameCallback(any());
+        verify(mSfVsyncFrameProvider, atLeast(2)).postFrameCallback(any());
     }
 
     @Test
@@ -401,14 +412,12 @@
 
     @Test
     public void moveWindowMagnifierToPositionWithAnimation_expectedValuesAndInvokeCallback()
-            throws InterruptedException {
+            throws RemoteException {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                     Float.NaN, 0, 0, null);
         });
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
+
         final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
         verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                 .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
@@ -417,12 +426,12 @@
 
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.moveWindowMagnifierToPosition(
-                    targetCenterX, targetCenterY, animationCallback);
+                    targetCenterX, targetCenterY, mAnimationCallback);
         });
+        advanceTimeBy(mWaitAnimationDuration);
 
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
-        assertEquals(1, animationCallback.getSuccessCount());
-        assertEquals(0, animationCallback.getFailedCount());
+        verify(mAnimationCallback, times(1)).onResult(eq(true));
+        verify(mAnimationCallback, never()).onResult(eq(false));
         verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                 .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
         assertEquals(mWindowMagnificationController.getCenterX(),
@@ -435,14 +444,12 @@
 
     @Test
     public void moveWindowMagnifierToPositionMultipleTimes_expectedValuesAndInvokeCallback()
-            throws InterruptedException {
+            throws RemoteException {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                     Float.NaN, 0, 0, null);
         });
-        final CountDownLatch countDownLatch = new CountDownLatch(4);
-        final MockMagnificationAnimationCallback animationCallback =
-                new MockMagnificationAnimationCallback(countDownLatch);
+
         final ArgumentCaptor<Rect> sourceBoundsCaptor = ArgumentCaptor.forClass(Rect.class);
         verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                 .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
@@ -451,20 +458,20 @@
 
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.moveWindowMagnifierToPosition(
-                    centerX + 10, centerY + 10, animationCallback);
+                    centerX + 10, centerY + 10, mAnimationCallback);
             mWindowMagnificationController.moveWindowMagnifierToPosition(
-                    centerX + 20, centerY + 20, animationCallback);
+                    centerX + 20, centerY + 20, mAnimationCallback);
             mWindowMagnificationController.moveWindowMagnifierToPosition(
-                    centerX + 30, centerY + 30, animationCallback);
+                    centerX + 30, centerY + 30, mAnimationCallback);
             mWindowMagnificationController.moveWindowMagnifierToPosition(
-                    centerX + 40, centerY + 40, animationCallback);
+                    centerX + 40, centerY + 40, mAnimationCallback2);
         });
+        advanceTimeBy(mWaitAnimationDuration);
 
-        assertTrue(countDownLatch.await(mWaitingAnimationPeriod, TimeUnit.MILLISECONDS));
         // only the last one callback will return true
-        assertEquals(1, animationCallback.getSuccessCount());
+        verify(mAnimationCallback2).onResult(eq(true));
         // the others will return false
-        assertEquals(3, animationCallback.getFailedCount());
+        verify(mAnimationCallback, times(3)).onResult(eq(false));
         verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS))
                 .onSourceBoundsChanged((eq(mContext.getDisplayId())), sourceBoundsCaptor.capture());
         assertEquals(mWindowMagnificationController.getCenterX(),
@@ -1078,27 +1085,16 @@
 
         final View mirrorView = mWindowManager.getAttachedView();
 
-        final long timeout = SystemClock.uptimeMillis() + 5000;
         final AtomicDouble maxScaleX = new AtomicDouble();
-        final Runnable onAnimationFrame = new Runnable() {
-            @Override
-            public void run() {
-                // For some reason the fancy way doesn't compile...
-//                maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
-                final double oldMax = maxScaleX.get();
-                final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
-                assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
+        advanceTimeBy(mWaitBounceEffectDuration, /* runnableOnEachRefresh= */ () -> {
+            // For some reason the fancy way doesn't compile...
+            // maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
+            final double oldMax = maxScaleX.get();
+            final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
+            assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
+        });
 
-                if (SystemClock.uptimeMillis() < timeout) {
-                    mirrorView.postOnAnimation(this);
-                }
-            }
-        };
-        mirrorView.postOnAnimation(onAnimationFrame);
-
-        waitForIdleSync();
-
-        ReferenceTestUtils.waitForCondition(() -> maxScaleX.get() > 1.0);
+        assertTrue(maxScaleX.get() > 1.0);
     }
 
     @Test
@@ -1455,4 +1451,23 @@
         return newRotation;
     }
 
+    // advance time based on the device frame refresh rate
+    private void advanceTimeBy(long timeDelta) {
+        advanceTimeBy(timeDelta, /* runnableOnEachRefresh= */ null);
+    }
+
+    // advance time based on the device frame refresh rate, and trigger runnable on each refresh
+    private void advanceTimeBy(long timeDelta, @Nullable Runnable runnableOnEachRefresh) {
+        final float frameRate = mContext.getDisplay().getRefreshRate();
+        final int timeSlot = (int) (1000 / frameRate);
+        int round = (int) Math.ceil((double) timeDelta / timeSlot);
+        for (; round >= 0; round--) {
+            mInstrumentation.runOnMainSync(() -> {
+                mAnimatorTestRule.advanceTimeBy(timeSlot);
+                if (runnableOnEachRefresh != null) {
+                    runnableOnEachRefresh.run();
+                }
+            });
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index daa6070..3da7261 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -19,8 +19,6 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -89,7 +87,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         MockitoAnnotations.initMocks(this);
         mContextWrapper = new ContextWrapper(mContext) {
             @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
index 5666435..fd258e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -58,7 +56,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
                 mock(SecureSettings.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
index e832940..2e75480 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationControllerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.any;
@@ -77,7 +75,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 stubWindowManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
index e8192c4..34a2e87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuEduTooltipViewTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.res.Resources;
@@ -45,7 +43,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
         mMenuViewAppearance = new MenuViewAppearance(mContext, windowManager);
         mMenuEduTooltipView = new MenuEduTooltipView(mContext, mMenuViewAppearance);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index 62cb9a0..4ac18d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -19,8 +19,6 @@
 import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
 import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.doReturn;
@@ -74,7 +72,6 @@
 
     @Before
     public void setUp() {
-        setFlagDefaults(mSetFlagsRule);
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 stubWindowManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 3248753..f0a497d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -18,8 +18,6 @@
 
 import static android.view.View.OVER_SCROLL_NEVER;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyFloat;
@@ -82,7 +80,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
                 mock(SecureSettings.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
index 03a4ba7..31824ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
@@ -19,8 +19,6 @@
 import static android.view.WindowInsets.Type.displayCutout;
 import static android.view.WindowInsets.Type.systemBars;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
@@ -75,7 +73,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         final WindowManager wm = mContext.getSystemService(WindowManager.class);
         doAnswer(invocation -> wm.getMaximumWindowMetrics()).when(
                 mWindowManager).getMaximumWindowMetrics();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 76094c1..0f1364d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -23,7 +23,6 @@
 import static android.view.WindowInsets.Type.systemBars;
 
 import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.LayerIndex;
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -122,7 +121,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         final Rect mDisplayBounds = new Rect();
         mDisplayBounds.set(/* left= */ 0, /* top= */ 0, DISPLAY_WINDOW_WIDTH,
                 DISPLAY_WINDOW_HEIGHT);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index b9fd5d0f..5cd0fd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -18,8 +18,6 @@
 
 import static android.app.UiModeManager.MODE_NIGHT_YES;
 
-import static com.android.systemui.accessibility.utils.FlagUtils.setFlagDefaults;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
@@ -69,7 +67,6 @@
 
     @Before
     public void setUp() throws Exception {
-        setFlagDefaults(mSetFlagsRule);
         mUiModeManager = mContext.getSystemService(UiModeManager.class);
         mNightMode = mUiModeManager.getNightMode();
         mUiModeManager.setNightMode(MODE_NIGHT_YES);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/FlagUtils.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/FlagUtils.java
deleted file mode 100644
index c7bb0f5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/utils/FlagUtils.java
+++ /dev/null
@@ -1,36 +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.
- */
-
-package com.android.systemui.accessibility.utils;
-
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
-import android.platform.test.flag.junit.SetFlagsRule;
-
-import com.android.systemui.Flags;
-
-public class FlagUtils {
-    /**
-     * Populates a setFlagsRule with every SystemUI a11y feature flag.
-     * This function should be updated when new flags are added.
-     *
-     * @param setFlagsRule set flags rule from the test environment.
-     */
-    public static void setFlagDefaults(SetFlagsRule setFlagsRule) {
-        setFlagDefault(setFlagsRule, Flags.FLAG_FLOATING_MENU_OVERLAPS_NAV_BARS_FLAG);
-        setFlagDefault(setFlagsRule, Flags.FLAG_FLOATING_MENU_IME_DISPLACEMENT_ANIMATION);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt
index f4d2cfd..f4f05d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/SetFlagsRuleExtensions.kt
@@ -18,52 +18,7 @@
 
 import android.platform.test.flag.junit.SetFlagsRule
 
-/**
- * Set the given flag's value to the real value for the current build configuration. This prevents
- * test code from crashing because it is reading an unspecified flag value.
- *
- * REMINDER: You should always test your code with your flag in both configurations, so generally
- * you should be explicitly enabling or disabling your flag. This method is for situations where the
- * flag needs to be read (e.g. in the class constructor), but its value shouldn't affect the actual
- * test cases. In those cases, it's mildly safer to use this method than to hard-code `false` or
- * `true` because then at least if you're wrong, and the flag value *does* matter, you'll notice
- * when the flag is flipped and tests start failing.
- */
-fun SetFlagsRule.setFlagDefault(flagName: String) {
-    if (getFlagDefault(flagName)) {
-        enableFlags(flagName)
-    } else {
-        disableFlags(flagName)
-    }
-}
-
-/**
- * Set the given flag to an explicit value, or, if null, to the real value for the current build
- * configuration. This allows for convenient provisioning in tests where certain tests don't care
- * what the value is (`setFlagValue(FLAG_FOO, null)`), and others want an explicit value.
- */
-fun SetFlagsRule.setFlagValue(name: String, value: Boolean?) {
-    when (value) {
-        null -> setFlagDefault(name)
-        true -> enableFlags(name)
-        false -> disableFlags(name)
-    }
-}
-
-// NOTE: This code uses reflection to gain access to private members of aconfig generated
-//  classes (in the same way SetFlagsRule does internally) because this is the only way to get
-//  at the underlying information and read the current value of the flag.
-// If aconfig had flag constants with accessible default values, this would be unnecessary.
-private fun getFlagDefault(name: String): Boolean {
-    val flagPackage = name.substringBeforeLast(".")
-    val featureFlagsImplClass = Class.forName("$flagPackage.FeatureFlagsImpl")
-    val featureFlagsImpl = featureFlagsImplClass.getConstructor().newInstance()
-    val flagMethodName = name.substringAfterLast(".").snakeToCamelCase()
-    val flagGetter = featureFlagsImplClass.getDeclaredMethod(flagMethodName)
-    return flagGetter.invoke(featureFlagsImpl) as Boolean
-}
-
-private fun String.snakeToCamelCase(): String {
-    val pattern = "_[a-z]".toRegex()
-    return replace(pattern) { it.value.last().uppercase() }
+/** Set the given flag to an explicit value. */
+fun SetFlagsRule.setFlagValue(name: String, value: Boolean) {
+    if (value) enableFlags(name) else disableFlags(name)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
index fd1e2c7..da448aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/MediaProjectionMetricsLoggerTest.kt
@@ -74,6 +74,15 @@
     }
 
     @Test
+    fun notifyProjectionCancelled_forwardsToServiceWithMetricsValue() {
+        val hostUid = 123
+
+        logger.notifyProjectionRequestCancelled(hostUid)
+
+        verify(service).notifyPermissionRequestCancelled(hostUid)
+    }
+
+    @Test
     fun notifyAppSelectorDisplayed_forwardsToService() {
         val hostUid = 654
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 5255f71..44798ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -4,7 +4,6 @@
 import android.os.UserHandle
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED as STATE_APP_SELECTOR_DISPLAYED
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
@@ -214,7 +213,7 @@
     @Test
     fun init_firstStart_logsAppSelectorDisplayed() {
         val hostUid = 123456789
-        val controller = createController(isFirstStart = true,  hostUid)
+        val controller = createController(isFirstStart = true, hostUid)
 
         controller.init()
 
@@ -231,6 +230,15 @@
         verify(logger, never()).notifyAppSelectorDisplayed(hostUid)
     }
 
+    @Test
+    fun onSelectorDismissed_logsProjectionRequestCancelled() {
+        val hostUid = 123
+
+        createController(hostUid = hostUid).onSelectorDismissed()
+
+        verify(logger).notifyProjectionRequestCancelled(hostUid)
+    }
+
     private fun givenCaptureAllowed(isAllow: Boolean) {
         whenever(policyResolver.isScreenCaptureAllowed(any(), any())).thenReturn(isAllow)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index c439cfe..49049bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.screenrecord;
 
+import static android.os.Process.myUid;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static junit.framework.Assert.assertFalse;
@@ -31,8 +33,8 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Looper;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
 
@@ -60,6 +62,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 /**
  * Tests for exception handling and  bitmap configuration in adding smart actions to Screenshot
  * Notification.
@@ -117,10 +120,6 @@
     // starting, and notifies listeners.
     @Test
     public void testCancelCountdown() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         mController.startCountdown(100, 10, null, null);
 
         assertTrue(mController.isStarting());
@@ -137,10 +136,6 @@
     // Test that when recording is started, the start intent is sent and listeners are notified.
     @Test
     public void testStartRecording() throws PendingIntent.CanceledException {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         PendingIntent startIntent = Mockito.mock(PendingIntent.class);
         mController.startCountdown(0, 0, startIntent, null);
 
@@ -151,10 +146,6 @@
     // Test that when recording is stopped, the stop intent is sent and listeners are notified.
     @Test
     public void testStopRecording() throws PendingIntent.CanceledException {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         PendingIntent startIntent = Mockito.mock(PendingIntent.class);
         PendingIntent stopIntent = Mockito.mock(PendingIntent.class);
 
@@ -182,10 +173,6 @@
     // Test that broadcast will update state
     @Test
     public void testUpdateStateBroadcast() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         // When a recording has started
         PendingIntent startIntent = Mockito.mock(PendingIntent.class);
         mController.startCountdown(0, 0, startIntent, null);
@@ -211,10 +198,6 @@
     // Test that switching users will stop an ongoing recording
     @Test
     public void testUserChange() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         // If we are recording
         PendingIntent startIntent = Mockito.mock(PendingIntent.class);
         PendingIntent stopIntent = Mockito.mock(PendingIntent.class);
@@ -231,10 +214,6 @@
 
     @Test
     public void testPoliciesFlagDisabled_screenCapturingNotAllowed_returnsNullDevicePolicyDialog() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, false);
         when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true);
@@ -247,10 +226,6 @@
 
     @Test
     public void testPartialScreenSharingDisabled_returnsLegacyDialog() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, false);
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, false);
 
@@ -262,10 +237,6 @@
 
     @Test
     public void testPoliciesFlagEnabled_screenCapturingNotAllowed_returnsDevicePolicyDialog() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
         when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(true);
@@ -278,10 +249,6 @@
 
     @Test
     public void testPoliciesFlagEnabled_screenCapturingAllowed_returnsNullDevicePolicyDialog() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
-
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
         when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
@@ -294,9 +261,6 @@
 
     @Test
     public void testPoliciesFlagEnabled_screenCapturingAllowed_logsProjectionInitiated() {
-        if (Looper.myLooper() == null) {
-            Looper.prepare();
-        }
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING, true);
         mFeatureFlags.set(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES, true);
         when(mDevicePolicyResolver.isScreenCaptureCompletelyDisabled((any()))).thenReturn(false);
@@ -306,7 +270,7 @@
 
         verify(mMediaProjectionMetricsLogger)
                 .notifyProjectionInitiated(
-                        TEST_USER_ID,
+                        /* hostUid= */ myUid(),
                         SessionCreationSource.SYSTEM_UI_SCREEN_RECORDER);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
index bf12d7d..fd38139 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorActivity
 import com.android.systemui.mediaprojection.permission.ENTIRE_SCREEN
 import com.android.systemui.mediaprojection.permission.SINGLE_APP
@@ -41,7 +42,6 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
@@ -57,6 +57,7 @@
     @Mock private lateinit var userContextProvider: UserContextProvider
     @Mock private lateinit var flags: FeatureFlags
     @Mock private lateinit var onStartRecordingClicked: Runnable
+    @Mock private lateinit var mediaProjectionMetricsLogger: MediaProjectionMetricsLogger
 
     private lateinit var dialog: ScreenRecordPermissionDialog
 
@@ -72,7 +73,8 @@
                 controller,
                 starter,
                 userContextProvider,
-                onStartRecordingClicked
+                onStartRecordingClicked,
+                mediaProjectionMetricsLogger,
             )
         dialog.onCreate(null)
         whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
@@ -149,6 +151,28 @@
         assertThat(dialog.isShowing).isFalse()
     }
 
+    @Test
+    fun showDialog_cancelClickedMultipleTimes_projectionRequestCancelledIsLoggedOnce() {
+        dialog.show()
+
+        clickOnCancel()
+        clickOnCancel()
+
+        verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
+    }
+
+    @Test
+    fun dismissDialog_dismissCalledMultipleTimes_projectionRequestCancelledIsLoggedOnce() {
+        dialog.show()
+
+        TestableLooper.get(this).runWithLooper {
+            dialog.dismiss()
+            dialog.dismiss()
+        }
+
+        verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
+    }
+
     private fun clickOnCancel() {
         dialog.requireViewById<View>(android.R.id.button2).performClick()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index df38f93..f98267b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.shade.ui.viewmodel
 
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -151,12 +152,14 @@
                 subscriptionId = 1,
                 isOpportunistic = false,
                 carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_UNSET,
             )
         private val SUB_2 =
             SubscriptionModel(
                 subscriptionId = 2,
                 isOpportunistic = false,
                 carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_UNSET,
             )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index a4c12f6..2bee7b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -43,7 +41,6 @@
 import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
 import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository;
 import com.android.systemui.statusbar.domain.interactor.SilentNotificationStatusIconsVisibilityInteractor;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -72,7 +69,6 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
         mListener = new NotificationListener(
                 mContext,
                 mNotificationManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index e81207e..428574b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -63,11 +63,11 @@
     @Before
     fun setUp() {
         initMocks(this)
-        setUp(NotificationIconContainerRefactor.FLAG_NAME to null)
         entry = NotificationEntryBuilder().setSection(section).build()
+        setUpWithFlags()
     }
 
-    private fun setUp(vararg flags: Pair<String, Boolean?>) {
+    private fun setUpWithFlags(vararg flags: Pair<String, Boolean>) {
         flags.forEach { (name, value) -> mSetFlagsRule.setFlagValue(name, value) }
         reset(pipeline)
         coordinator =
@@ -84,14 +84,14 @@
 
     @Test
     fun testUpdateNotificationIcons() {
-        setUp(NotificationIconContainerRefactor.FLAG_NAME to false)
+        setUpWithFlags(NotificationIconContainerRefactor.FLAG_NAME to false)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(notificationIconAreaController).updateNotificationIcons(eq(listOf(entry)))
     }
 
     @Test
     fun testSetRenderedListOnInteractor() {
-        setUp(NotificationIconContainerRefactor.FLAG_NAME to true)
+        setUpWithFlags(NotificationIconContainerRefactor.FLAG_NAME to true)
         afterRenderListListener.onAfterRenderList(listOf(entry), stackController)
         verify(renderListInteractor).setRenderedList(eq(listOf(entry)))
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index cbb0894..947bcfb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -2,7 +2,6 @@
 
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision.FSI_DEVICE_NOT_INTERACTIVE
@@ -19,7 +18,30 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
-class NotificationInterruptStateProviderWrapperTest : SysuiTestCase() {
+class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
+    override val provider: VisualInterruptionDecisionProvider
+        get() =
+            NotificationInterruptStateProviderWrapper(
+                NotificationInterruptStateProviderImpl(
+                        context.contentResolver,
+                        powerManager,
+                        ambientDisplayConfiguration,
+                        batteryController,
+                        statusBarStateController,
+                        keyguardStateController,
+                        headsUpManager,
+                        logger,
+                        mainHandler,
+                        flags,
+                        keyguardNotificationVisibilityProvider,
+                        uiEventLogger,
+                        userTracker,
+                        deviceProvisionedController
+                    )
+                    .also { it.mUseHeadsUp = true }
+            )
+
+    // Tests of internals of the wrapper:
 
     @Test
     fun decisionOfTrue() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
new file mode 100644
index 0000000..6f4bbd5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -0,0 +1,221 @@
+package com.android.systemui.statusbar.notification.interruption
+
+import android.app.ActivityManager
+import android.app.Notification
+import android.app.Notification.BubbleMetadata
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_MUTABLE
+import android.content.Intent
+import android.content.pm.UserInfo
+import android.graphics.drawable.Icon
+import android.hardware.display.FakeAmbientDisplayConfiguration
+import android.os.Handler
+import android.os.PowerManager
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.statusbar.FakeStatusBarStateController
+import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.notification.NotifPipelineFlags
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.utils.leaks.FakeBatteryController
+import com.android.systemui.utils.leaks.LeakCheckedTest
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.`when` as whenever
+
+abstract class VisualInterruptionDecisionProviderTestBase : SysuiTestCase() {
+    private val leakCheck = LeakCheckedTest.SysuiLeakCheck()
+
+    protected val ambientDisplayConfiguration = FakeAmbientDisplayConfiguration(context)
+    protected val batteryController = FakeBatteryController(leakCheck)
+    protected val deviceProvisionedController: DeviceProvisionedController = mock()
+    protected val flags: NotifPipelineFlags = mock()
+    protected val headsUpManager: HeadsUpManager = mock()
+    protected val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider =
+        mock()
+    protected val keyguardStateController: KeyguardStateController = mock()
+    protected val logger: NotificationInterruptLogger = mock()
+    protected val mainHandler: Handler = mock()
+    protected val powerManager: PowerManager = mock()
+    protected val statusBarStateController = FakeStatusBarStateController()
+    protected val uiEventLogger = UiEventLoggerFake()
+    protected val userTracker = FakeUserTracker()
+
+    protected abstract val provider: VisualInterruptionDecisionProvider
+
+    @Before
+    fun setUp() {
+        val user = UserInfo(ActivityManager.getCurrentUser(), "Current user", /* flags = */ 0)
+        userTracker.set(listOf(user), /* currentUserIndex = */ 0)
+
+        whenever(headsUpManager.isSnoozed(any())).thenReturn(false)
+        whenever(keyguardNotificationVisibilityProvider.shouldHideNotification(any()))
+            .thenReturn(false)
+    }
+
+    @Test
+    fun testShouldPeek() {
+        ensureStateForPeek()
+
+        assertTrue(provider.makeUnloggedHeadsUpDecision(createPeekEntry()).shouldInterrupt)
+    }
+
+    @Test
+    fun testShouldPulse() {
+        ensureStateForPulse()
+
+        assertTrue(provider.makeUnloggedHeadsUpDecision(createPulseEntry()).shouldInterrupt)
+    }
+
+    @Test
+    fun testShouldFsi_awake() {
+        ensureStateForAwakeFsi()
+
+        assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+    }
+
+    @Test
+    fun testShouldFsi_dreaming() {
+        ensureStateForDreamingFsi()
+
+        assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+    }
+
+    @Test
+    fun testShouldFsi_keyguard() {
+        ensureStateForKeyguardFsi()
+
+        assertTrue(provider.makeUnloggedFullScreenIntentDecision(createFsiEntry()).shouldInterrupt)
+    }
+
+    @Test
+    fun testShouldBubble() {
+        assertTrue(provider.makeAndLogBubbleDecision(createBubbleEntry()).shouldInterrupt)
+    }
+
+    private fun ensureStateForPeek() {
+        whenever(powerManager.isScreenOn).thenReturn(true)
+        statusBarStateController.dozing = false
+        statusBarStateController.dreaming = false
+    }
+
+    private fun ensureStateForPulse() {
+        ambientDisplayConfiguration.fakePulseOnNotificationEnabled = true
+        batteryController.setIsAodPowerSave(false)
+        statusBarStateController.dozing = true
+    }
+
+    private fun ensureStateForAwakeFsi() {
+        whenever(powerManager.isInteractive).thenReturn(false)
+        statusBarStateController.dreaming = false
+        statusBarStateController.state = SHADE
+    }
+
+    private fun ensureStateForDreamingFsi() {
+        whenever(powerManager.isInteractive).thenReturn(true)
+        statusBarStateController.dreaming = true
+        statusBarStateController.state = SHADE
+    }
+
+    private fun ensureStateForKeyguardFsi() {
+        whenever(powerManager.isInteractive).thenReturn(true)
+        statusBarStateController.dreaming = false
+        statusBarStateController.state = KEYGUARD
+    }
+
+    private fun createNotif(
+        hasFsi: Boolean = false,
+        bubbleMetadata: BubbleMetadata? = null
+    ): Notification {
+        return Notification.Builder(context, TEST_CHANNEL_ID)
+            .apply {
+                setContentTitle(TEST_CONTENT_TITLE)
+                setContentText(TEST_CONTENT_TEXT)
+
+                if (hasFsi) {
+                    setFullScreenIntent(mock(), /* highPriority = */ true)
+                }
+
+                if (bubbleMetadata != null) {
+                    setBubbleMetadata(bubbleMetadata)
+                }
+            }
+            .setContentTitle(TEST_CONTENT_TITLE)
+            .setContentText(TEST_CONTENT_TEXT)
+            .build()
+    }
+
+    private fun createBubbleMetadata(): BubbleMetadata {
+        val pendingIntent =
+            PendingIntent.getActivity(
+                context,
+                /* requestCode = */ 0,
+                Intent().setPackage(context.packageName),
+                FLAG_MUTABLE
+            )
+
+        val icon = Icon.createWithResource(context.resources, R.drawable.android)
+
+        return BubbleMetadata.Builder(pendingIntent, icon).build()
+    }
+
+    private fun createEntry(
+        notif: Notification,
+        importance: Int = IMPORTANCE_DEFAULT,
+        canBubble: Boolean? = null
+    ): NotificationEntry {
+        return NotificationEntryBuilder()
+            .apply {
+                setPkg(TEST_PACKAGE)
+                setOpPkg(TEST_PACKAGE)
+                setTag(TEST_TAG)
+                setChannel(NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, importance))
+                setNotification(notif)
+                setImportance(importance)
+
+                if (canBubble != null) {
+                    setCanBubble(canBubble)
+                }
+            }
+            .build()
+    }
+
+    private fun createPeekEntry() = createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH)
+
+    private fun createPulseEntry() =
+        createEntry(notif = createNotif(), importance = IMPORTANCE_HIGH).also {
+            modifyRanking(it).setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build()
+        }
+
+    private fun createFsiEntry() =
+        createEntry(notif = createNotif(hasFsi = true), importance = IMPORTANCE_HIGH)
+
+    private fun createBubbleEntry() =
+        createEntry(
+            notif = createNotif(bubbleMetadata = createBubbleMetadata()),
+            importance = IMPORTANCE_HIGH,
+            canBubble = true
+        )
+}
+
+private const val TEST_CONTENT_TITLE = "Test Content Title"
+private const val TEST_CONTENT_TEXT = "Test content text"
+private const val TEST_CHANNEL_ID = "test_channel"
+private const val TEST_CHANNEL_NAME = "Test Channel"
+private const val TEST_PACKAGE = "test_package"
+private const val TEST_TAG = "test_tag"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
index ccef1d5..9b9cb82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
@@ -61,8 +61,9 @@
                 else -> null
             } as T?
         }
-        mNormalColor =
-            Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface)
+
+        mNormalColor = Utils.getColorAttrDefaultColor(mContext,
+                com.android.internal.R.attr.materialColorSurfaceContainerHigh)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 8f36d4f..033c96a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -19,8 +19,6 @@
 import static android.view.View.GONE;
 import static android.view.WindowInsets.Type.ime;
 
-import static com.android.systemui.Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR;
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL;
@@ -167,11 +165,6 @@
         mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR);
         mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION);
         mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX);
-        // Some tests in this file test the FooterView. Since we're refactoring the FooterView
-        // business logic out of the NSSL, the behavior tested in this file will eventually be
-        // tested directly in the new FooterView stack. For now, we just want to make sure that the
-        // old behavior is preserved when the flag is off.
-        setFlagDefault(mSetFlagsRule, FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR);
 
         // Inject dependencies before initializing the layout
         mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 6478a3e..05fd6d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -21,7 +21,6 @@
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 
@@ -164,7 +163,6 @@
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
@@ -337,7 +335,6 @@
         mFeatureFlags.set(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI, false);
         // Set default value to avoid IllegalStateException.
         mFeatureFlags.set(Flags.SHORTCUT_LIST_SEARCH_LAYOUT, false);
-        setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
         // For the Shade to respond to Back gesture, we must enable the event routing
         mFeatureFlags.set(Flags.WM_SHADE_ALLOW_BACK_GESTURE, true);
         // For the Shade to animate during the Back gesture, we must enable the animation flag.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 19215e3..53cb8a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
 import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -54,7 +52,6 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -107,7 +104,6 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
         mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle,
                 mStatusBarStateController, mDeviceProvisionedController, mFeatureFlags,
                 mHeadsUpManager, mBatteryController, mScrimController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 1fad2a2..c1ef1ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -48,7 +46,6 @@
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.Clock;
@@ -92,7 +89,6 @@
     @Before
     public void setUp() throws Exception {
         allowTestableLooperAsMainThread();
-        setFlagDefault(mSetFlagsRule, NotificationIconContainerRefactor.FLAG_NAME);
         mTestHelper = new NotificationTestHelper(
                 mContext,
                 mDependency,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 92e40df..c24d9ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -15,8 +15,6 @@
  */
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.verify;
@@ -30,7 +28,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.SetFlagsRuleExtensionsKt;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index 2b28562..62d8f7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -20,23 +20,18 @@
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.setFlagDefault
 import com.android.systemui.statusbar.StatusBarIconView
 import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
 import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
-import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.`when` as whenever
 
-/**
- * Tests for {@link NotificationIconContainer}.
- */
+/** Tests for {@link NotificationIconContainer}. */
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @RunWithLooper
@@ -44,15 +39,12 @@
 
     private val iconContainer = NotificationIconContainer(context, /* attrs= */ null)
 
-    @Before
-    fun setup() {
-        mSetFlagsRule.setFlagDefault(NotificationIconContainerRefactor.FLAG_NAME)
-    }
-
     @Test
     fun calculateWidthFor_zeroIcons_widthIsZero() {
-        assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 0f),
-                /* actual= */ 0f)
+        assertEquals(
+            /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 0f),
+            /* actual= */ 0f
+        )
     }
 
     @Test
@@ -61,8 +53,10 @@
         iconContainer.setActualPaddingEnd(10f)
         iconContainer.setIconSize(10)
 
-        assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
-                /* actual= */ 30f)
+        assertEquals(
+            /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
+            /* actual= */ 30f
+        )
     }
 
     @Test
@@ -71,8 +65,10 @@
         iconContainer.setActualPaddingEnd(10f)
         iconContainer.setIconSize(10)
 
-        assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
-                /* actual= */ 60f)
+        assertEquals(
+            /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
+            /* actual= */ 60f
+        )
     }
 
     @Test
@@ -80,8 +76,10 @@
         iconContainer.setActualPaddingStart(10f)
         iconContainer.setActualPaddingEnd(10f)
         iconContainer.setIconSize(10)
-        assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
-                /* actual= */ 60f)
+        assertEquals(
+            /* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
+            /* actual= */ 60f
+        )
     }
 
     @Test
@@ -214,112 +212,121 @@
 
     @Test
     fun shouldForceOverflow_appearingAboveSpeedBump_true() {
-        val forceOverflow = iconContainer.shouldForceOverflow(
+        val forceOverflow =
+            iconContainer.shouldForceOverflow(
                 /* i= */ 1,
                 /* speedBumpIndex= */ 0,
                 /* iconAppearAmount= */ 1f,
                 /* maxVisibleIcons= */ 5
-        )
+            )
         assertTrue(forceOverflow)
     }
 
     @Test
     fun shouldForceOverflow_moreThanMaxVisible_true() {
-        val forceOverflow = iconContainer.shouldForceOverflow(
+        val forceOverflow =
+            iconContainer.shouldForceOverflow(
                 /* i= */ 10,
                 /* speedBumpIndex= */ 11,
                 /* iconAppearAmount= */ 0f,
                 /* maxVisibleIcons= */ 5
-        )
+            )
         assertTrue(forceOverflow)
     }
 
     @Test
     fun shouldForceOverflow_belowSpeedBumpAndLessThanMaxVisible_false() {
-        val forceOverflow = iconContainer.shouldForceOverflow(
+        val forceOverflow =
+            iconContainer.shouldForceOverflow(
                 /* i= */ 0,
                 /* speedBumpIndex= */ 11,
                 /* iconAppearAmount= */ 0f,
                 /* maxVisibleIcons= */ 5
-        )
+            )
         assertFalse(forceOverflow)
     }
 
     @Test
     fun isOverflowing_lastChildXLessThanLayoutEnd_false() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ true,
                 /* translationX= */ 0f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertFalse(isOverflowing)
     }
 
-
     @Test
     fun isOverflowing_lastChildXEqualToLayoutEnd_true() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ true,
                 /* translationX= */ 10f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertTrue(isOverflowing)
     }
 
     @Test
     fun isOverflowing_lastChildXGreaterThanDotX_true() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ true,
                 /* translationX= */ 9f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertTrue(isOverflowing)
     }
 
     @Test
     fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ true,
                 /* translationX= */ 20f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertTrue(isOverflowing)
     }
 
     @Test
     fun isOverflowing_notLastChildXLessThanDotX_false() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ false,
                 /* translationX= */ 0f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertFalse(isOverflowing)
     }
 
     @Test
     fun isOverflowing_notLastChildXGreaterThanDotX_true() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ false,
                 /* translationX= */ 20f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertTrue(isOverflowing)
     }
 
     @Test
     fun isOverflowing_notLastChildXEqualToDotX_true() {
-        val isOverflowing = iconContainer.isOverflowing(
+        val isOverflowing =
+            iconContainer.isOverflowing(
                 /* isLastChild= */ false,
                 /* translationX= */ 8f,
                 /* layoutEnd= */ 10f,
                 /* iconSize= */ 2f,
-        )
+            )
         assertTrue(isOverflowing)
     }
 
@@ -335,4 +342,4 @@
         whenever(iconView.notification).thenReturn(sbn)
         return iconView
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 4d4f33b..9b6940e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -18,6 +18,7 @@
 
 import android.telephony.SubscriptionInfo
 import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.telephony.TelephonyManager
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -249,11 +250,13 @@
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_1_ID)
                 whenever(it.carrierName).thenReturn(SUB_1_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
         private val MODEL_1 =
             SubscriptionModel(
                 subscriptionId = SUB_1_ID,
                 carrierName = SUB_1_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
 
         private const val SUB_2_ID = 2
@@ -262,11 +265,13 @@
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_2_ID)
                 whenever(it.carrierName).thenReturn(SUB_2_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
         private val MODEL_2 =
             SubscriptionModel(
                 subscriptionId = SUB_2_ID,
                 carrierName = SUB_2_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 1c21ebe..787a266 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -19,6 +19,7 @@
 import android.net.ConnectivityManager
 import android.telephony.ServiceState
 import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.telephony.TelephonyCallback
 import android.telephony.TelephonyManager
 import androidx.test.filters.SmallTest
@@ -88,6 +89,7 @@
             SubscriptionModel(
                 subscriptionId = SUB_ID,
                 carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
         )
 
@@ -737,7 +739,7 @@
 
     private companion object {
         const val SUB_ID = 42
-        private val DEFAULT_NAME = "default name"
+        private const val DEFAULT_NAME = "default name"
         private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
         private const val SEP = "-"
         private const val BUFFER_SEPARATOR = "|"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index ba64265..a90bd48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -32,13 +32,13 @@
 import android.telephony.ServiceState.STATE_IN_SERVICE
 import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
 import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.telephony.TelephonyCallback
 import android.telephony.TelephonyCallback.DataActivityListener
 import android.telephony.TelephonyCallback.ServiceStateListener
 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
 import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
 import android.telephony.TelephonyManager
-import android.telephony.TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED
 import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
 import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
 import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
@@ -132,6 +132,7 @@
             SubscriptionModel(
                 subscriptionId = SUB_1_ID,
                 carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
         )
 
@@ -677,6 +678,7 @@
                 SubscriptionModel(
                     subscriptionId = SUB_1_ID,
                     carrierName = DEFAULT_NAME,
+                    profileClass = PROFILE_CLASS_UNSET,
                 )
 
             assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
@@ -686,6 +688,7 @@
                 SubscriptionModel(
                     subscriptionId = SUB_1_ID,
                     carrierName = updatedName,
+                    profileClass = PROFILE_CLASS_UNSET,
                 )
 
             assertThat(latest?.name).isEqualTo(updatedName)
@@ -980,9 +983,9 @@
     companion object {
         private const val SUB_1_ID = 1
 
-        private val DEFAULT_NAME = "Fake Mobile Network"
+        private const val DEFAULT_NAME = "Fake Mobile Network"
         private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
-        private val SEP = "-"
+        private const val SEP = "-"
 
         private const val SPN = "testSpn"
         private const val PLMN = "testPlmn"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 18ba6c4..936c58e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -31,6 +31,7 @@
 import android.telephony.SubscriptionInfo
 import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.telephony.TelephonyCallback
 import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
 import android.telephony.TelephonyManager
@@ -1223,12 +1224,14 @@
                 whenever(it.subscriptionId).thenReturn(SUB_1_ID)
                 whenever(it.groupUuid).thenReturn(GROUP_1)
                 whenever(it.carrierName).thenReturn(SUB_1_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
         private val MODEL_1 =
             SubscriptionModel(
                 subscriptionId = SUB_1_ID,
                 groupUuid = GROUP_1,
                 carrierName = SUB_1_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
 
         // Subscription 2
@@ -1240,12 +1243,14 @@
                 whenever(it.subscriptionId).thenReturn(SUB_2_ID)
                 whenever(it.groupUuid).thenReturn(GROUP_2)
                 whenever(it.carrierName).thenReturn(SUB_2_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
         private val MODEL_2 =
             SubscriptionModel(
                 subscriptionId = SUB_2_ID,
                 groupUuid = GROUP_2,
                 carrierName = SUB_2_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
 
         // Subs 3 and 4 are considered to be in the same group ------------------------------------
@@ -1257,6 +1262,7 @@
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_3_ID_GROUPED)
                 whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
 
         // Subscription 4
@@ -1265,6 +1271,7 @@
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_4_ID_GROUPED)
                 whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
 
         // Subs 3 and 4 are considered to be in the same group ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1279,9 +1286,14 @@
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
                 whenever(it.carrierName).thenReturn(SUB_CM_NAME)
+                whenever(it.profileClass).thenReturn(PROFILE_CLASS_UNSET)
             }
         private val MODEL_CM =
-            SubscriptionModel(subscriptionId = SUB_CM_ID, carrierName = SUB_CM_NAME)
+            SubscriptionModel(
+                subscriptionId = SUB_CM_ID,
+                carrierName = SUB_CM_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
 
         private val WIFI_INFO_CM =
             mock<WifiInfo>().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index e2f9119..20d5c5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
 
 import android.telephony.CellSignalStrength
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
 import androidx.test.filters.SmallTest
 import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
@@ -65,6 +66,7 @@
             SubscriptionModel(
                 subscriptionId = SUB_1_ID,
                 carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
             )
         )
 
@@ -649,9 +651,9 @@
 
         private const val SUB_1_ID = 1
 
-        private val DEFAULT_NAME = "test default name"
+        private const val DEFAULT_NAME = "test default name"
         private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
-        private val DERIVED_NAME = "test derived name"
+        private const val DERIVED_NAME = "test derived name"
         private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index b4c7578..2060288 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -17,10 +17,16 @@
 package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
 
 import android.os.ParcelUuid
+import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import androidx.test.filters.SmallTest
 import com.android.settingslib.mobile.MobileMappings
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
@@ -57,6 +63,10 @@
     private lateinit var connectionsRepository: FakeMobileConnectionsRepository
     private val userSetupRepository = FakeUserSetupRepository()
     private val mobileMappingsProxy = FakeMobileMappingsProxy()
+    private val flags =
+        FakeFeatureFlagsClassic().apply {
+            set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -99,6 +109,7 @@
                 userSetupRepository,
                 testScope.backgroundScope,
                 context,
+                flags,
             )
     }
 
@@ -318,6 +329,123 @@
         }
 
     @Test
+    fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() =
+        testScope.runTest {
+            // GIVEN the flag is false
+            flags.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
+
+            // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
+            val sub1 =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    isOpportunistic = false,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(sub1))
+
+            // WHEN filtering is applied
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // THEN the provisioning sub is still present (unfiltered)
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
+    fun filteredSubscriptions_filtersOutProvisioningSubs() =
+        testScope.runTest {
+            val sub1 =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    isOpportunistic = false,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+            val sub2 =
+                SubscriptionModel(
+                    subscriptionId = SUB_2_ID,
+                    isOpportunistic = false,
+                    carrierName = "Carrier 2",
+                    profileClass = SubscriptionManager.PROFILE_CLASS_PROVISIONING,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    /** Note: I'm not sure if this will ever be the case, but we can test it at least */
+    @Test
+    fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() =
+        testScope.runTest {
+            // This is a contrived test case, where the active subId is the one that would
+            // also be filtered by opportunistic filtering.
+
+            // GIVEN grouped, opportunistic subscriptions
+            val groupUuid = ParcelUuid(UUID.randomUUID())
+            val sub1 =
+                SubscriptionModel(
+                    subscriptionId = 1,
+                    isOpportunistic = true,
+                    groupUuid = groupUuid,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            val sub2 =
+                SubscriptionModel(
+                    subscriptionId = 2,
+                    isOpportunistic = true,
+                    groupUuid = groupUuid,
+                    carrierName = "Carrier 2",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            // GIVEN active subId is 1
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+            connectionsRepository.setActiveMobileDataSubscriptionId(1)
+
+            // THEN filtering of provisioning subs takes place first, and we result in sub2
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub2))
+        }
+
+    @Test
+    fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() =
+        testScope.runTest {
+            // Grouped filtering only happens when the list of subs is length 2. In this case
+            // we'll show that filtering of provisioning subs happens before, and thus grouped
+            // filtering happens even though the unfiltered list is length 3
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+
+            val sub2 =
+                SubscriptionModel(
+                    subscriptionId = 2,
+                    isOpportunistic = true,
+                    groupUuid = null,
+                    carrierName = "Carrier 2",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2, sub3))
+            connectionsRepository.setActiveMobileDataSubscriptionId(1)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
     fun activeDataConnection_turnedOn() =
         testScope.runTest {
             CONNECTION_1.setDataEnabled(true)
@@ -806,7 +934,8 @@
                 subscriptionId = subscriptionIds.first,
                 isOpportunistic = opportunistic.first,
                 groupUuid = groupUuid,
-                carrierName = "Carrier ${subscriptionIds.first}"
+                carrierName = "Carrier ${subscriptionIds.first}",
+                profileClass = PROFILE_CLASS_UNSET,
             )
 
         val sub2 =
@@ -814,7 +943,8 @@
                 subscriptionId = subscriptionIds.second,
                 isOpportunistic = opportunistic.second,
                 groupUuid = groupUuid,
-                carrierName = "Carrier ${opportunistic.second}"
+                carrierName = "Carrier ${opportunistic.second}",
+                profileClass = PROFILE_CLASS_UNSET,
             )
 
         return Pair(sub1, sub2)
@@ -824,12 +954,20 @@
 
         private const val SUB_1_ID = 1
         private val SUB_1 =
-            SubscriptionModel(subscriptionId = SUB_1_ID, carrierName = "Carrier $SUB_1_ID")
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = "Carrier $SUB_1_ID",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
         private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
 
         private const val SUB_2_ID = 2
         private val SUB_2 =
-            SubscriptionModel(subscriptionId = SUB_2_ID, carrierName = "Carrier $SUB_2_ID")
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                carrierName = "Carrier $SUB_2_ID",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
         private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
 
         private const val SUB_3_ID = 3
@@ -838,7 +976,8 @@
                 subscriptionId = SUB_3_ID,
                 isOpportunistic = true,
                 groupUuid = ParcelUuid(UUID.randomUUID()),
-                carrierName = "Carrier $SUB_3_ID"
+                carrierName = "Carrier $SUB_3_ID",
+                profileClass = PROFILE_CLASS_UNSET,
             )
         private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
 
@@ -848,7 +987,8 @@
                 subscriptionId = SUB_4_ID,
                 isOpportunistic = true,
                 groupUuid = ParcelUuid(UUID.randomUUID()),
-                carrierName = "Carrier $SUB_4_ID"
+                carrierName = "Carrier $SUB_4_ID",
+                profileClass = PROFILE_CLASS_UNSET,
             )
         private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index 1d5487f..6a69d1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -70,7 +70,11 @@
     private lateinit var airplaneModeInteractor: AirplaneModeInteractor
 
     private val connectivityRepository = FakeConnectivityRepository()
-    private val flags = FakeFeatureFlagsClassic().also { it.set(Flags.NEW_NETWORK_SLICE_UI, false) }
+    private val flags =
+        FakeFeatureFlagsClassic().also {
+            it.set(Flags.NEW_NETWORK_SLICE_UI, false)
+            it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
 
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var constants: ConnectivityConstants
@@ -114,6 +118,7 @@
                 FakeUserSetupRepository(),
                 testScope.backgroundScope,
                 context,
+                flags,
             )
 
         interactor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index c831e62..b39fc5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -82,7 +82,11 @@
     @Mock private lateinit var tableLogBuffer: TableLogBuffer
     @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
 
-    private val flags = FakeFeatureFlagsClassic().also { it.set(Flags.NEW_NETWORK_SLICE_UI, false) }
+    private val flags =
+        FakeFeatureFlagsClassic().also {
+            it.set(Flags.NEW_NETWORK_SLICE_UI, false)
+            it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
 
@@ -120,6 +124,7 @@
                 FakeUserSetupRepository(),
                 testScope.backgroundScope,
                 context,
+                flags,
             )
 
         interactor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index f3e334e..f029152 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
 
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.mobile.TelephonyIcons
@@ -102,6 +103,7 @@
                         subscriptionId = 1,
                         isOpportunistic = false,
                         carrierName = "Carrier 1",
+                        profileClass = PROFILE_CLASS_UNSET,
                     ),
                 )
             assertThat(latest).isEqualTo(listOf(1))
@@ -112,16 +114,19 @@
                         subscriptionId = 2,
                         isOpportunistic = false,
                         carrierName = "Carrier 2",
+                        profileClass = PROFILE_CLASS_UNSET,
                     ),
                     SubscriptionModel(
                         subscriptionId = 5,
                         isOpportunistic = true,
                         carrierName = "Carrier 5",
+                        profileClass = PROFILE_CLASS_UNSET,
                     ),
                     SubscriptionModel(
                         subscriptionId = 7,
                         isOpportunistic = true,
                         carrierName = "Carrier 7",
+                        profileClass = PROFILE_CLASS_UNSET,
                     ),
                 )
             assertThat(latest).isEqualTo(listOf(2, 5, 7))
@@ -335,18 +340,21 @@
                 subscriptionId = 1,
                 isOpportunistic = false,
                 carrierName = "Carrier 1",
+                profileClass = PROFILE_CLASS_UNSET,
             )
         private val SUB_2 =
             SubscriptionModel(
                 subscriptionId = 2,
                 isOpportunistic = false,
                 carrierName = "Carrier 2",
+                profileClass = PROFILE_CLASS_UNSET,
             )
         private val SUB_3 =
             SubscriptionModel(
                 subscriptionId = 3,
                 isOpportunistic = false,
                 carrierName = "Carrier 3",
+                profileClass = PROFILE_CLASS_UNSET,
             )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index c935dbb..8405fb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -22,6 +22,8 @@
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Text
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon
 import com.android.systemui.res.R
@@ -75,6 +77,11 @@
     private val mobileConnectionRepository =
         FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer)
 
+    private val flags =
+        FakeFeatureFlagsClassic().also {
+            it.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
+
     private val internet = context.getString(R.string.quick_settings_internet_label)
 
     @Before
@@ -101,6 +108,7 @@
                 userSetupRepo,
                 testScope.backgroundScope,
                 context,
+                flags,
             )
 
         underTest =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index c4c7472..7456e00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -26,6 +26,8 @@
 import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNotSame;
 import static junit.framework.Assert.assertTrue;
 
@@ -40,6 +42,9 @@
 
 import android.app.KeyguardManager;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -52,6 +57,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageButton;
 
 import androidx.test.core.view.MotionEventBuilder;
 import androidx.test.filters.SmallTest;
@@ -90,6 +96,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Arrays;
 import java.util.function.Predicate;
 
 @SmallTest
@@ -757,6 +764,86 @@
                 foundCaptionLog);
     }
 
+    @Test
+    public void turnOnDnD_volumeSliderIconChangesToDnd() {
+        State state = createShellState();
+        state.zenMode = Settings.Global.ZEN_MODE_NO_INTERRUPTIONS;
+
+        mDialog.onStateChangedH(state);
+        mTestableLooper.processAllMessages();
+
+        boolean foundDnDIcon = findDndIconAmongVolumeRows();
+        assertTrue(foundDnDIcon);
+    }
+
+    @Test
+    public void turnOffDnD_volumeSliderIconIsNotDnd() {
+        State state = createShellState();
+        state.zenMode = Settings.Global.ZEN_MODE_OFF;
+
+        mDialog.onStateChangedH(state);
+        mTestableLooper.processAllMessages();
+
+        boolean foundDnDIcon = findDndIconAmongVolumeRows();
+        assertFalse(foundDnDIcon);
+    }
+
+    /**
+     * @return true if at least one volume row has the DND icon
+     */
+    private boolean findDndIconAmongVolumeRows() {
+        ViewGroup volumeDialogRows = mDialog.getDialogView().findViewById(R.id.volume_dialog_rows);
+        assumeNotNull(volumeDialogRows);
+        Drawable expected =  getContext().getDrawable(com.android.internal.R.drawable.ic_qs_dnd);
+        boolean foundDnDIcon = false;
+        final int rowCount = volumeDialogRows.getChildCount();
+        // we don't make assumptions about the position of the dnd row
+        for (int i = 0; i < rowCount && !foundDnDIcon; i++) {
+            View volumeRow = volumeDialogRows.getChildAt(i);
+            ImageButton rowIcon = volumeRow.findViewById(R.id.volume_row_icon);
+            assertNotNull(rowIcon);
+
+            // VolumeDialogImpl changes tint and alpha in a private method, so we clear those here.
+            rowIcon.setImageTintList(null);
+            rowIcon.setAlpha(0xFF);
+
+            Drawable actual = rowIcon.getDrawable();
+            foundDnDIcon |= areDrawablesEqual(expected, actual);
+        }
+        return foundDnDIcon;
+    }
+
+    private boolean areDrawablesEqual(Drawable drawable1, Drawable drawable2) {
+        int size = 100;
+        Bitmap bm1 = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+        Bitmap bm2 = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+
+        Canvas canvas1 = new Canvas(bm1);
+        Canvas canvas2 = new Canvas(bm2);
+
+        drawable1.setBounds(0, 0, size, size);
+        drawable2.setBounds(0, 0, size, size);
+
+        drawable1.draw(canvas1);
+        drawable2.draw(canvas2);
+
+        boolean areBitmapsEqual = areBitmapsEqual(bm1, bm2);
+        bm1.recycle();
+        bm2.recycle();
+        return areBitmapsEqual;
+    }
+
+    private boolean areBitmapsEqual(Bitmap a, Bitmap b) {
+        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;
+        int w = a.getWidth();
+        int h = a.getHeight();
+        int[] aPix = new int[w * h];
+        int[] bPix = new int[w * h];
+        a.getPixels(aPix, 0, w, 0, 0, w, h);
+        b.getPixels(bPix, 0, w, 0, 0, w, h);
+        return Arrays.equals(aPix, bPix);
+    }
+
     @After
     public void teardown() {
         // Detailed logs to track down timeout issues in b/299491332
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt
new file mode 100644
index 0000000..cdd0ff7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/android/hardware/display/FakeAmbientDisplayConfiguration.kt
@@ -0,0 +1,68 @@
+package android.hardware.display
+
+import android.content.Context
+
+class FakeAmbientDisplayConfiguration(context: Context) : AmbientDisplayConfiguration(context) {
+    var fakePulseOnNotificationEnabled = true
+
+    override fun pulseOnNotificationEnabled(user: Int) = fakePulseOnNotificationEnabled
+
+    override fun pulseOnNotificationAvailable() = TODO("Not yet implemented")
+
+    override fun pickupGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun dozePickupSensorAvailable() = TODO("Not yet implemented")
+
+    override fun tapGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun tapSensorAvailable() = TODO("Not yet implemented")
+
+    override fun doubleTapGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun doubleTapSensorAvailable() = TODO("Not yet implemented")
+
+    override fun quickPickupSensorEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun screenOffUdfpsEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun wakeScreenGestureAvailable() = TODO("Not yet implemented")
+
+    override fun wakeLockScreenGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun wakeDisplayGestureEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun getWakeLockScreenDebounce() = TODO("Not yet implemented")
+
+    override fun doubleTapSensorType() = TODO("Not yet implemented")
+
+    override fun tapSensorTypeMapping() = TODO("Not yet implemented")
+
+    override fun longPressSensorType() = TODO("Not yet implemented")
+
+    override fun udfpsLongPressSensorType() = TODO("Not yet implemented")
+
+    override fun quickPickupSensorType() = TODO("Not yet implemented")
+
+    override fun pulseOnLongPressEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun alwaysOnEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun alwaysOnAvailable() = TODO("Not yet implemented")
+
+    override fun alwaysOnAvailableForUser(user: Int) = TODO("Not yet implemented")
+
+    override fun ambientDisplayComponent() = TODO("Not yet implemented")
+
+    override fun accessibilityInversionEnabled(user: Int) = TODO("Not yet implemented")
+
+    override fun ambientDisplayAvailable() = TODO("Not yet implemented")
+
+    override fun dozeSuppressed(user: Int) = TODO("Not yet implemented")
+
+    override fun disableDozeSettings(userId: Int) = TODO("Not yet implemented")
+
+    override fun disableDozeSettings(shouldDisableNonUserConfigurable: Boolean, userId: Int) =
+        TODO("Not yet implemented")
+
+    override fun restoreDozeSettings(userId: Int) = TODO("Not yet implemented")
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index e6e6b7b..29e737e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -15,7 +15,7 @@
  */
 package com.android.systemui;
 
-import static com.android.systemui.Flags.FLAG_EXAMPLE_FLAG;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
@@ -65,7 +65,7 @@
             new AndroidXAnimatorIsolationRule();
 
     @Rule
-    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
 
     @Rule
     public SysuiTestableContext mContext = new SysuiTestableContext(
@@ -88,9 +88,6 @@
         if (isRobolectricTest()) {
             mContext = mContext.createDefaultDisplayContext();
         }
-        // Set the value of a single gantry flag inside the com.android.systemui package to
-        // ensure all flags in that package are faked (and thus require a value to be set).
-        mSetFlagsRule.disableFlags(FLAG_EXAMPLE_FLAG);
         mSysuiDependency = new SysuiTestDependency(mContext, shouldFailOnLeakedReceiver());
         mDependency = mSysuiDependency.install();
         mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt
new file mode 100644
index 0000000..19fdb6d
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/FakeStatusBarStateController.kt
@@ -0,0 +1,159 @@
+package com.android.systemui.statusbar
+
+import android.view.View
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+
+class FakeStatusBarStateController : SysuiStatusBarStateController {
+    @JvmField var state = StatusBarState.SHADE
+
+    @JvmField var upcomingState = StatusBarState.SHADE
+
+    @JvmField var lastState = StatusBarState.SHADE
+
+    @JvmField var dozing = false
+
+    @JvmField var expanded = false
+
+    @JvmField var pulsing = false
+
+    @JvmField var dreaming = false
+
+    @JvmField var dozeAmount = 0.0f
+
+    @JvmField var interpolatedDozeAmount = 0.0f
+
+    @JvmField var dozeAmountTarget = 0.0f
+
+    @JvmField var leaveOpen = false
+
+    @JvmField var keyguardRequested = false
+
+    var lastSetDozeAmountView: View? = null
+        private set
+
+    var lastSetDozeAmountAnimated = false
+        private set
+
+    var lastSystemBarAppearance = 0
+        private set
+
+    var lastSystemBarBehavior = 0
+        private set
+
+    var lastSystemBarRequestedVisibleTypes = 0
+        private set
+
+    var lastSystemBarPackageName: String? = null
+        private set
+
+    private val _callbacks = mutableSetOf<StatusBarStateController.StateListener>()
+
+    @JvmField val callbacks: Set<StatusBarStateController.StateListener> = _callbacks
+
+    private var fullscreen = false
+
+    override fun start() {}
+
+    override fun getState() = state
+
+    override fun setState(newState: Int, force: Boolean): Boolean {
+        val oldState = this.state
+        newState != oldState || force || return false
+
+        callbacks.forEach { it.onStatePreChange(oldState, newState) }
+        this.lastState = oldState
+        this.state = newState
+        setUpcomingState(newState)
+        callbacks.forEach { it.onStateChanged(newState) }
+        callbacks.forEach { it.onStatePostChange() }
+        return true
+    }
+
+    override fun getCurrentOrUpcomingState() = upcomingState
+
+    override fun setUpcomingState(upcomingState: Int) {
+        upcomingState != this.upcomingState || return
+        this.upcomingState = upcomingState
+        callbacks.forEach { it.onUpcomingStateChanged(upcomingState) }
+    }
+
+    override fun isDozing() = dozing
+
+    override fun setIsDozing(dozing: Boolean): Boolean {
+        dozing != this.dozing || return false
+        this.dozing = dozing
+        callbacks.forEach { it.onDozingChanged(dozing) }
+        return true
+    }
+
+    override fun isExpanded() = expanded
+
+    fun fakeShadeExpansionFullyChanged(expanded: Boolean) {
+        expanded != this.expanded || return
+        this.expanded = expanded
+        callbacks.forEach { it.onExpandedChanged(expanded) }
+    }
+
+    override fun isPulsing() = pulsing
+
+    override fun setPulsing(pulsing: Boolean) {
+        pulsing != this.pulsing || return
+        this.pulsing = pulsing
+        callbacks.forEach { it.onPulsingChanged(pulsing) }
+    }
+
+    override fun isDreaming() = dreaming
+
+    override fun setIsDreaming(drreaming: Boolean): Boolean {
+        dreaming != this.dreaming || return false
+        this.dreaming = dreaming
+        callbacks.forEach { it.onDreamingChanged(dreaming) }
+        return true
+    }
+
+    override fun getDozeAmount() = dozeAmount
+
+    override fun setAndInstrumentDozeAmount(view: View?, dozeAmount: Float, animated: Boolean) {
+        dozeAmountTarget = dozeAmount
+        lastSetDozeAmountView = view
+        lastSetDozeAmountAnimated = animated
+        if (!animated) {
+            this.dozeAmount = dozeAmount
+        }
+    }
+
+    override fun leaveOpenOnKeyguardHide() = leaveOpen
+
+    override fun setLeaveOpenOnKeyguardHide(leaveOpen: Boolean) {
+        this.leaveOpen = leaveOpen
+    }
+
+    override fun getInterpolatedDozeAmount() = interpolatedDozeAmount
+
+    fun fakeInterpolatedDozeAmountChanged(interpolatedDozeAmount: Float) {
+        this.interpolatedDozeAmount = interpolatedDozeAmount
+        callbacks.forEach { it.onDozeAmountChanged(dozeAmount, interpolatedDozeAmount) }
+    }
+
+    override fun goingToFullShade() = state == StatusBarState.SHADE && leaveOpen
+
+    override fun fromShadeLocked() = lastState == StatusBarState.SHADE_LOCKED
+
+    override fun isKeyguardRequested(): Boolean = keyguardRequested
+
+    override fun setKeyguardRequested(keyguardRequested: Boolean) {
+        this.keyguardRequested = keyguardRequested
+    }
+
+    override fun addCallback(listener: StatusBarStateController.StateListener?) {
+        _callbacks.add(listener!!)
+    }
+
+    override fun addCallback(listener: StatusBarStateController.StateListener?, rank: Int) {
+        throw RuntimeException("addCallback with rank unsupported")
+    }
+
+    override fun removeCallback(listener: StatusBarStateController.StateListener?) {
+        _callbacks.remove(listener!!)
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
index eaa109d..209cac6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeBatteryController.java
@@ -25,6 +25,7 @@
 
 public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCallback>
         implements BatteryController {
+    private boolean mIsAodPowerSave = false;
     private boolean mWirelessCharging;
 
     public FakeBatteryController(LeakCheck test) {
@@ -63,7 +64,7 @@
 
     @Override
     public boolean isAodPowerSave() {
-        return false;
+        return mIsAodPowerSave;
     }
 
     @Override
@@ -71,6 +72,10 @@
         return mWirelessCharging;
     }
 
+    public void setIsAodPowerSave(boolean isAodPowerSave) {
+        mIsAodPowerSave = isAodPowerSave;
+    }
+
     public void setWirelessCharging(boolean wirelessCharging) {
         mWirelessCharging = wirelessCharging;
     }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 961e9d3..3985a0e 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -155,6 +155,7 @@
         "service-permission.stubs.system_server",
         "service-rkp.stubs.system_server",
         "service-sdksandbox.stubs.system_server",
+        "device_policy_aconfig_flags_lib",
     ],
     plugins: ["ImmutabilityAnnotationProcessor"],
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 210c18d..e88d0c6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15934,7 +15934,7 @@
         try {
             sdkSandboxInfo =
                     sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
-                            sdkSandboxClientAppInfo, isSdkInSandbox);
+                            sdkSandboxClientAppInfo, userId, isSdkInSandbox);
         } catch (NameNotFoundException e) {
             reportStartInstrumentationFailureLocked(
                     watcher, className, "Can't find SdkSandbox package");
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 516293b..052b0c2 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -2680,8 +2680,17 @@
                 .filterAppAccess(packageName, callingUid, userId);
     }
 
+    /** @deprecated Use {@link #noteProxyOperationWithState} instead. */
     @Override
     public SyncNotedAppOp noteProxyOperation(int code,
+            AttributionSource attributionSource, boolean shouldCollectAsyncNotedOp,
+            String message, boolean shouldCollectMessage, boolean skipProxyOperation) {
+        return mCheckOpsDelegateDispatcher.noteProxyOperation(code, attributionSource,
+                shouldCollectAsyncNotedOp, message, shouldCollectMessage, skipProxyOperation);
+    }
+
+    @Override
+    public SyncNotedAppOp noteProxyOperationWithState(int code,
             AttributionSourceState attributionSourceState, boolean shouldCollectAsyncNotedOp,
             String message, boolean shouldCollectMessage, boolean skipProxyOperation) {
         AttributionSource attributionSource = new AttributionSource(attributionSourceState);
@@ -3212,8 +3221,21 @@
                 attributionChainId);
     }
 
+    /** @deprecated Use {@link #startProxyOperationWithState} instead. */
     @Override
     public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code,
+            @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
+            boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
+            boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
+            @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
+        return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code, attributionSource,
+                startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags,
+                attributionChainId);
+    }
+
+    @Override
+    public SyncNotedAppOp startProxyOperationWithState(@NonNull IBinder clientId, int code,
             @NonNull AttributionSourceState attributionSourceState, boolean startIfModeDefault,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
             boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
@@ -3513,8 +3535,16 @@
         finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
     }
 
+    /** @deprecated Use {@link #finishProxyOperationWithState} instead. */
     @Override
     public void finishProxyOperation(@NonNull IBinder clientId, int code,
+            @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
+        mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource,
+                skipProxyOperation);
+    }
+
+    @Override
+    public void finishProxyOperationWithState(@NonNull IBinder clientId, int code,
             @NonNull AttributionSourceState attributionSourceState, boolean skipProxyOperation) {
         AttributionSource attributionSource = new AttributionSource(attributionSourceState);
         mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource,
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index c29d9bd..f085647 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -108,7 +108,7 @@
         final boolean credentialRequested = Utils.isCredentialRequested(promptInfo);
 
         final boolean credentialAvailable = trustManager.isDeviceSecure(userId,
-                context.getAssociatedDisplayId());
+                context.getDeviceId());
 
         // Assuming that biometric authenticators are listed in priority-order, the rest of this
         // function will attempt to find the first authenticator that's as strong or stronger than
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 76dde54..e3c0cf7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -646,7 +646,7 @@
                             intendingUid,
                             intendingUserId,
                             intendingDeviceId)
-                    || isDeviceLocked(intendingUserId)) {
+                    || isDeviceLocked(intendingUserId, deviceId)) {
                 return null;
             }
             synchronized (mLock) {
@@ -686,7 +686,7 @@
                             intendingUserId,
                             intendingDeviceId,
                             false)
-                    || isDeviceLocked(intendingUserId)) {
+                    || isDeviceLocked(intendingUserId, deviceId)) {
                 return null;
             }
             synchronized (mLock) {
@@ -710,7 +710,7 @@
                             intendingUserId,
                             intendingDeviceId,
                             false)
-                    || isDeviceLocked(intendingUserId)) {
+                    || isDeviceLocked(intendingUserId, deviceId)) {
                 return false;
             }
             synchronized (mLock) {
@@ -785,7 +785,7 @@
                             intendingUserId,
                             intendingDeviceId,
                             false)
-                    || isDeviceLocked(intendingUserId)) {
+                    || isDeviceLocked(intendingUserId, deviceId)) {
                 return false;
             }
             synchronized (mLock) {
@@ -814,7 +814,7 @@
                             intendingUserId,
                             intendingDeviceId,
                             false)
-                    || isDeviceLocked(intendingUserId)) {
+                    || isDeviceLocked(intendingUserId, deviceId)) {
                 return null;
             }
             synchronized (mLock) {
@@ -1150,12 +1150,12 @@
                 && text.equals(clipboard.primaryClip.getItemAt(0).getText());
     }
 
-    private boolean isDeviceLocked(@UserIdInt int userId) {
+    private boolean isDeviceLocked(@UserIdInt int userId, int deviceId) {
         final long token = Binder.clearCallingIdentity();
         try {
             final KeyguardManager keyguardManager = getContext().getSystemService(
                     KeyguardManager.class);
-            return keyguardManager != null && keyguardManager.isDeviceLocked(userId);
+            return keyguardManager != null && keyguardManager.isDeviceLocked(userId, deviceId);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 67a1ccd..78077a8 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -40,6 +40,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.media.flags.Flags;
 
 import java.util.List;
 import java.util.Objects;
@@ -358,21 +359,8 @@
 
             RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build();
 
-            if (mPendingSessionCreationRequest != null) {
-                SessionCreationRequest sessionCreationRequest;
-                synchronized (mRequestLock) {
-                    sessionCreationRequest = mPendingSessionCreationRequest;
-                    mPendingSessionCreationRequest = null;
-                }
-                if (sessionCreationRequest != null) {
-                    if (TextUtils.equals(mSelectedRouteId, sessionCreationRequest.mRouteId)) {
-                        mCallback.onSessionCreated(this,
-                                sessionCreationRequest.mRequestId, newSessionInfo);
-                    } else {
-                        mCallback.onRequestFailed(this, sessionCreationRequest.mRequestId,
-                                MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
-                    }
-                }
+            synchronized (mRequestLock) {
+                reportPendingSessionRequestResultLockedIfNeeded(newSessionInfo);
             }
 
             if (Objects.equals(oldSessionInfo, newSessionInfo)) {
@@ -395,6 +383,59 @@
         }
     }
 
+    @GuardedBy("mRequestLock")
+    private void reportPendingSessionRequestResultLockedIfNeeded(
+            RoutingSessionInfo newSessionInfo) {
+        if (mPendingSessionCreationRequest == null) {
+            // No pending request, nothing to report.
+            return;
+        }
+
+        long pendingRequestId = mPendingSessionCreationRequest.mRequestId;
+        if (TextUtils.equals(mSelectedRouteId, mPendingSessionCreationRequest.mRouteId)) {
+            if (DEBUG) {
+                Slog.w(
+                        TAG,
+                        "Session creation success to route "
+                                + mPendingSessionCreationRequest.mRouteId);
+            }
+            mPendingSessionCreationRequest = null;
+            mCallback.onSessionCreated(this, pendingRequestId, newSessionInfo);
+        } else {
+            boolean isRequestedRouteConnectedBtRoute = isRequestedRouteConnectedBtRoute();
+            if (!Flags.enableWaitingStateForSystemSessionCreationRequest()
+                    || !isRequestedRouteConnectedBtRoute) {
+                if (DEBUG) {
+                    Slog.w(
+                            TAG,
+                            "Session creation failed to route "
+                                    + mPendingSessionCreationRequest.mRouteId);
+                }
+                mPendingSessionCreationRequest = null;
+                mCallback.onRequestFailed(
+                        this, pendingRequestId, MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
+            } else if (DEBUG) {
+                Slog.w(
+                        TAG,
+                        "Session creation waiting state to route "
+                                + mPendingSessionCreationRequest.mRouteId);
+            }
+        }
+    }
+
+    @GuardedBy("mRequestLock")
+    private boolean isRequestedRouteConnectedBtRoute() {
+        // Using AllRoutes instead of TransferableRoutes as BT Stack sends an intermediate update
+        // where two BT routes are active so the transferable routes list is empty.
+        // See b/307723189 for context
+        for (MediaRoute2Info btRoute : mBluetoothRouteController.getAllBluetoothRoutes()) {
+            if (TextUtils.equals(btRoute.getId(), mPendingSessionCreationRequest.mRouteId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void publishProviderState() {
         updateProviderState();
         notifyProviderState();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 58927d1..893ed61 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -470,6 +470,11 @@
     }
 
     @VisibleForTesting
+    void notifyPermissionRequestCancelled(int hostUid) {
+        mMediaProjectionMetricsLogger.logProjectionPermissionRequestCancelled(hostUid);
+    }
+
+    @VisibleForTesting
     void notifyAppSelectorDisplayed(int hostUid) {
         mMediaProjectionMetricsLogger.logAppSelectorDisplayed(hostUid);
     }
@@ -852,19 +857,6 @@
 
         @Override // Binder call
         @EnforcePermission(MANAGE_MEDIA_PROJECTION)
-        public void notifyPermissionRequestStateChange(int hostUid, int state,
-                int sessionCreationSource) {
-            notifyPermissionRequestStateChange_enforcePermission();
-            final long token = Binder.clearCallingIdentity();
-            try {
-                mMediaProjectionMetricsLogger.notifyProjectionStateChange(hostUid, state, sessionCreationSource);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
-        @Override // Binder call
-        @EnforcePermission(MANAGE_MEDIA_PROJECTION)
         public void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource) {
             notifyPermissionRequestInitiated_enforcePermission();
             final long token = Binder.clearCallingIdentity();
@@ -890,6 +882,18 @@
 
         @Override // Binder call
         @EnforcePermission(MANAGE_MEDIA_PROJECTION)
+        public void notifyPermissionRequestCancelled(int hostUid) {
+            notifyPermissionRequestCancelled_enforcePermission();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                MediaProjectionManagerService.this.notifyPermissionRequestCancelled(hostUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        @EnforcePermission(MANAGE_MEDIA_PROJECTION)
         public void notifyAppSelectorDisplayed(int hostUid) {
             notifyAppSelectorDisplayed_enforcePermission();
             final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
index 55a30bf..d7fefeb 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionMetricsLogger.java
@@ -118,6 +118,23 @@
     }
 
     /**
+     * Logs that requesting permission for media projection was cancelled by the user.
+     *
+     * @param hostUid UID of the package that initiates MediaProjection.
+     */
+    public void logProjectionPermissionRequestCancelled(int hostUid) {
+        write(
+                mSessionIdGenerator.getCurrentSessionId(),
+                FrameworkStatsLog
+                        .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED,
+                hostUid,
+                TARGET_UID_UNKNOWN,
+                TIME_SINCE_LAST_ACTIVE_UNKNOWN,
+                FrameworkStatsLog
+                        .MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+    }
+
+    /**
      * Logs that the app selector dialog is shown for the user.
      *
      * @param hostUid UID of the package that initiates MediaProjection.
@@ -174,23 +191,6 @@
         }
     }
 
-    public void notifyProjectionStateChange(int hostUid, int state, int sessionCreationSource) {
-        write(hostUid, state, sessionCreationSource);
-    }
-
-    private void write(int hostUid, int state, int sessionCreationSource) {
-        mFrameworkStatsLogWrapper.write(
-                /* code */ FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED,
-                /* session_id */ 123,
-                /* state */ state,
-                /* previous_state */ FrameworkStatsLog
-                        .MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN,
-                /* host_uid */ hostUid,
-                /* target_uid */ -1,
-                /* time_since_last_active */ 0,
-                /* creation_source */ sessionCreationSource);
-    }
-
     private void write(
             int sessionId,
             int state,
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 1134714..e57ea0f 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.server.os;
 
+import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -52,8 +54,10 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.HashSet;
 import java.util.Objects;
 import java.util.OptionalInt;
+import java.util.Set;
 
 /**
  * Implementation of the service that provides a privileged API to capture and consume bugreports.
@@ -101,10 +105,12 @@
         private final ArrayMap<Pair<Integer, String>, ArraySet<String>> mBugreportFiles =
                 new ArrayMap<>();
 
+        @GuardedBy("mLock")
+        private final Set<String> mBugreportFilesToPersist = new HashSet<>();
+
         /**
          * Checks that a given file was generated on behalf of the given caller. If the file was
-         * generated on behalf of the caller, it is removed from the bugreport mapping so that it
-         * may not be retrieved again. If the file was not generated on behalf of the caller, an
+         * not generated on behalf of the caller, an
          * {@link IllegalArgumentException} is thrown.
          *
          * @param callingInfo a (uid, package name) pair identifying the caller
@@ -114,35 +120,76 @@
          * @throws IllegalArgumentException if {@code bugreportFile} is not associated with
          *                                  {@code callingInfo}.
          */
+        @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
+                conditional = true)
         void ensureCallerPreviouslyGeneratedFile(
-                Pair<Integer, String> callingInfo, String bugreportFile) {
+                Context context, Pair<Integer, String> callingInfo, int userId,
+                String bugreportFile) {
             synchronized (mLock) {
-                ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(callingInfo);
-                if (bugreportFilesForCaller != null
-                        && bugreportFilesForCaller.contains(bugreportFile)) {
-                    bugreportFilesForCaller.remove(bugreportFile);
-                    if (bugreportFilesForCaller.isEmpty()) {
-                        mBugreportFiles.remove(callingInfo);
+                if (onboardingBugreportV2Enabled()) {
+                    final int uidForUser = Binder.withCleanCallingIdentity(() -> {
+                        try {
+                            return context.getPackageManager()
+                                    .getPackageUidAsUser(callingInfo.second, userId);
+                        } catch (PackageManager.NameNotFoundException exception) {
+                            throwInvalidBugreportFileForCallerException(
+                                    bugreportFile, callingInfo.second);
+                            return -1;
+                        }
+                    });
+                    if (uidForUser != callingInfo.first && context.checkCallingOrSelfPermission(
+                            Manifest.permission.INTERACT_ACROSS_USERS)
+                            != PackageManager.PERMISSION_GRANTED) {
+                        throw new SecurityException(
+                                callingInfo.second + " does not hold the "
+                                        + "INTERACT_ACROSS_USERS permission to access "
+                                        + "cross-user bugreports.");
+                    }
+                    ArraySet<String> bugreportFilesForUid = mBugreportFiles.get(
+                            new Pair<>(uidForUser, callingInfo.second));
+                    if (bugreportFilesForUid == null
+                            || !bugreportFilesForUid.contains(bugreportFile)) {
+                        throwInvalidBugreportFileForCallerException(
+                                bugreportFile, callingInfo.second);
                     }
                 } else {
-                    throw new IllegalArgumentException(
-                            "File " + bugreportFile + " was not generated"
-                                    + " on behalf of calling package " + callingInfo.second);
+                    ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(callingInfo);
+                    if (bugreportFilesForCaller != null
+                            && bugreportFilesForCaller.contains(bugreportFile)) {
+                        bugreportFilesForCaller.remove(bugreportFile);
+                        if (bugreportFilesForCaller.isEmpty()) {
+                            mBugreportFiles.remove(callingInfo);
+                        }
+                    } else {
+                        throwInvalidBugreportFileForCallerException(
+                                bugreportFile, callingInfo.second);
+
+                    }
                 }
             }
         }
 
+        private static void throwInvalidBugreportFileForCallerException(
+                String bugreportFile, String packageName) {
+            throw new IllegalArgumentException("File " + bugreportFile + " was not generated on"
+                    + " behalf of calling package " + packageName);
+        }
+
         /**
          * Associates a bugreport file with a caller, which is identified as a
          * (uid, package name) pair.
          */
-        void addBugreportFileForCaller(Pair<Integer, String> caller, String bugreportFile) {
+        void addBugreportFileForCaller(
+                Pair<Integer, String> caller, String bugreportFile, boolean keepOnRetrieval) {
             synchronized (mLock) {
                 if (!mBugreportFiles.containsKey(caller)) {
                     mBugreportFiles.put(caller, new ArraySet<>());
                 }
                 ArraySet<String> bugreportFilesForCaller = mBugreportFiles.get(caller);
                 bugreportFilesForCaller.add(bugreportFile);
+                if ((onboardingBugreportV2Enabled()) && keepOnRetrieval) {
+                    mBugreportFilesToPersist.add(bugreportFile);
+                }
             }
         }
     }
@@ -246,16 +293,17 @@
     }
 
     @Override
-    @RequiresPermission(Manifest.permission.DUMP)
-    public void retrieveBugreport(int callingUidUnused, String callingPackage,
-            FileDescriptor bugreportFd, String bugreportFile, IDumpstateListener listener) {
+    @RequiresPermission(value = Manifest.permission.DUMP, conditional = true)
+    public void retrieveBugreport(int callingUidUnused, String callingPackage, int userId,
+            FileDescriptor bugreportFd, String bugreportFile,
+            boolean keepBugreportOnRetrievalUnused, IDumpstateListener listener) {
         int callingUid = Binder.getCallingUid();
         enforcePermission(callingPackage, callingUid, false);
 
         Slogf.i(TAG, "Retrieving bugreport for %s / %d", callingPackage, callingUid);
         try {
             mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                    new Pair<>(callingUid, callingPackage), bugreportFile);
+                    mContext, new Pair<>(callingUid, callingPackage), userId, bugreportFile);
         } catch (IllegalArgumentException e) {
             Slog.e(TAG, e.getMessage());
             reportError(listener, IDumpstateListener.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
@@ -281,10 +329,17 @@
             // Wrap the listener so we can intercept binder events directly.
             DumpstateListener myListener = new DumpstateListener(listener, ds,
                     new Pair<>(callingUid, callingPackage), /* reportFinishedFile= */ true);
+
+            boolean keepBugreportOnRetrieval = false;
+            if (onboardingBugreportV2Enabled()) {
+                keepBugreportOnRetrieval = mBugreportFileManager.mBugreportFilesToPersist.contains(
+                        bugreportFile);
+            }
+
             setCurrentDumpstateListenerLocked(myListener);
             try {
-                ds.retrieveBugreport(callingUid, callingPackage, bugreportFd,
-                        bugreportFile, myListener);
+                ds.retrieveBugreport(callingUid, callingPackage, userId, bugreportFd,
+                        bugreportFile, keepBugreportOnRetrieval, myListener);
             } catch (RemoteException e) {
                 Slog.e(TAG, "RemoteException in retrieveBugreport", e);
             }
@@ -317,7 +372,8 @@
     private void validateBugreportFlags(int flags) {
         flags = clearBugreportFlag(flags,
                 BugreportParams.BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA
-                        | BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT);
+                        | BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT
+                        | BugreportParams.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL);
         if (flags != 0) {
             Slog.w(TAG, "Unknown bugreport flags: " + flags);
             throw new IllegalArgumentException("Unknown bugreport flags: " + flags);
@@ -482,6 +538,9 @@
         boolean reportFinishedFile =
                 (bugreportFlags & BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT) != 0;
 
+        boolean keepBugreportOnRetrieval =
+                (bugreportFlags & BugreportParams.BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL) != 0;
+
         IDumpstate ds = startAndGetDumpstateBinderServiceLocked();
         if (ds == null) {
             Slog.w(TAG, "Unable to get bugreport service");
@@ -490,7 +549,8 @@
         }
 
         DumpstateListener myListener = new DumpstateListener(listener, ds,
-                new Pair<>(callingUid, callingPackage), reportFinishedFile);
+                new Pair<>(callingUid, callingPackage), reportFinishedFile,
+                keepBugreportOnRetrieval);
         setCurrentDumpstateListenerLocked(myListener);
         try {
             ds.startBugreport(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode,
@@ -646,9 +706,16 @@
         private final boolean mReportFinishedFile;
         private int mProgress; // used for debugging purposes only
         private boolean mDone;
+        private boolean mKeepBugreportOnRetrieval;
 
         DumpstateListener(IDumpstateListener listener, IDumpstate ds,
                 Pair<Integer, String> caller, boolean reportFinishedFile) {
+            this(listener, ds, caller, reportFinishedFile, /* keepBugreportOnRetrieval= */ false);
+        }
+
+        DumpstateListener(IDumpstateListener listener, IDumpstate ds,
+                Pair<Integer, String> caller, boolean reportFinishedFile,
+                boolean keepBugreportOnRetrieval) {
             if (DEBUG) {
                 Slogf.d(TAG, "Starting DumpstateListener(id=%d) for caller %s", mId, caller);
             }
@@ -656,6 +723,7 @@
             mDs = ds;
             mCaller = caller;
             mReportFinishedFile = reportFinishedFile;
+            mKeepBugreportOnRetrieval = keepBugreportOnRetrieval;
             try {
                 mDs.asBinder().linkToDeath(this, 0);
             } catch (RemoteException e) {
@@ -690,7 +758,8 @@
                 reportFinishedLocked("File: " + bugreportFile);
             }
             if (mReportFinishedFile) {
-                mBugreportFileManager.addBugreportFileForCaller(mCaller, bugreportFile);
+                mBugreportFileManager.addBugreportFileForCaller(
+                        mCaller, bugreportFile, mKeepBugreportOnRetrieval);
             } else if (DEBUG) {
                 Slog.d(TAG, "Not reporting finished file");
             }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 7c32cde..2951ef6 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2374,12 +2374,6 @@
                 permissionParamsBuilder.setAutoRevokePermissionsMode(autoRevokePermissionsMode);
                 mPm.mPermissionManager.onPackageInstalled(pkg, installRequest.getPreviousAppId(),
                         permissionParamsBuilder.build(), userId);
-                // Apply restricted settings on potentially dangerous packages.
-                if (installRequest.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
-                        || installRequest.getPackageSource()
-                        == PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE) {
-                    enableRestrictedSettings(pkgName, pkg.getUid());
-                }
             }
             installRequest.setName(pkgName);
             installRequest.setAppId(pkg.getUid());
@@ -2394,16 +2388,13 @@
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
-    private void enableRestrictedSettings(String pkgName, int appId) {
+    private void enableRestrictedSettings(String pkgName, int appId, int userId) {
         final AppOpsManager appOpsManager = mPm.mContext.getSystemService(AppOpsManager.class);
-        final int[] allUsersList = mPm.mUserManager.getUserIds();
-        for (int userId : allUsersList) {
-            final int uid = UserHandle.getUid(userId, appId);
-            appOpsManager.setMode(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
-                    uid,
-                    pkgName,
-                    AppOpsManager.MODE_ERRORED);
-        }
+        final int uid = UserHandle.getUid(userId, appId);
+        appOpsManager.setMode(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
+                uid,
+                pkgName,
+                AppOpsManager.MODE_ERRORED);
     }
 
     /**
@@ -2820,13 +2811,10 @@
                     mPm.mRequiredInstallerPackage,
                     /* packageSender= */ mPm, launchedForRestore, killApp, update, archived);
 
-
             // Work that needs to happen on first install within each user
-            if (firstUserIds.length > 0) {
-                for (int userId : firstUserIds) {
-                    mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
-                            userId);
-                }
+            for (int userId : firstUserIds) {
+                mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
+                        userId);
             }
 
             if (request.isAllNewUsers() && !update) {
@@ -2835,6 +2823,16 @@
                 mPm.notifyPackageChanged(packageName, request.getAppId());
             }
 
+            for (int userId : firstUserIds) {
+                // Apply restricted settings on potentially dangerous packages. Needs to happen
+                // after appOpsManager is notified of the new package
+                if (request.getPackageSource() == PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE
+                        || request.getPackageSource()
+                        == PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE) {
+                    enableRestrictedSettings(packageName, request.getAppId(), userId);
+                }
+            }
+
             // Log current value of "unknown sources" setting
             EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
                     getUnknownSourcesSettings());
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c260be9..8b82a1c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -506,6 +506,9 @@
             if (!canAccessProfile(userId, "cannot get shouldHideFromSuggestions")) {
                 return false;
             }
+            if (Flags.archiving() && packageName != null && isPackageArchived(packageName, user)) {
+                return true;
+            }
             if (mPackageManagerInternal.filterAppAccess(
                     packageName, Binder.getCallingUid(), userId)) {
                 return false;
@@ -537,7 +540,7 @@
                     == 0) {
                 return launcherActivities;
             }
-            if (launcherActivities == null || launcherActivities.getList().isEmpty()) {
+            if (launcherActivities == null) {
                 // Cannot access profile, so we don't even return any hidden apps.
                 return null;
             }
@@ -758,6 +761,10 @@
             }
         }
 
+        private boolean isPackageArchived(@NonNull String packageName, UserHandle user) {
+            return !getApplicationInfoForArchivedApp(packageName, user).isEmpty();
+        }
+
         @NonNull
         private List<LauncherActivityInfoInternal> generateLauncherActivitiesForArchivedApp(
                 @Nullable String packageName, UserHandle user) {
@@ -969,11 +976,17 @@
             final int callingUid = injectBinderCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                final PackageInfo info = mPackageManagerInternal.getPackageInfo(packageName,
+                long callingFlag =
                         PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                        callingUid, user.getIdentifier());
-                return info != null && info.applicationInfo.enabled;
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+                if (Flags.archiving()) {
+                    callingFlag |= PackageManager.MATCH_ARCHIVED_PACKAGES;
+                }
+                final PackageInfo info =
+                        mPackageManagerInternal.getPackageInfo(
+                                packageName, callingFlag, callingUid, user.getIdentifier());
+                return info != null
+                        && (info.applicationInfo.enabled || info.applicationInfo.isArchived);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -1439,7 +1452,18 @@
             if (!canAccessProfile(user.getIdentifier(), "Cannot check component")) {
                 return false;
             }
-
+            if (Flags.archiving() && component != null && component.getPackageName() != null) {
+                List<LauncherActivityInfoInternal> archiveActivities =
+                        generateLauncherActivitiesForArchivedApp(component.getPackageName(), user);
+                if (!archiveActivities.isEmpty()) {
+                    for (int i = 0; i < archiveActivities.size(); i++) {
+                        if (archiveActivities.get(i).getComponentName().equals(component)) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            }
             final int callingUid = injectBinderCallingUid();
             final int state = mPackageManagerInternal.getComponentEnabledSetting(component,
                     callingUid, user.getIdentifier());
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 6a2ddc8..ea082cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -159,6 +159,9 @@
             if (pkgSetting.getPkg().isCoreApp()) {
                 throw new IllegalStateException("Found a core app that's not important");
             }
+            // Use REASON_FIRST_BOOT to query "pm.dexopt.first-boot" for the compiler filter, but
+            // the reason itself won't make it into the actual compiler reason because it will be
+            // overridden in otapreopt.cpp.
             mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.getPkg(), pkgSetting,
                     PackageManagerService.REASON_FIRST_BOOT));
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index b9b5908..305e353 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -44,6 +44,7 @@
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ArchivedPackageParcel;
+import android.content.pm.Flags;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
@@ -745,6 +746,22 @@
             params.installFlags &= ~PackageManager.INSTALL_DISABLE_VERIFICATION;
         }
 
+        if (Flags.rollbackLifetime()) {
+            if (params.rollbackLifetimeMillis > 0) {
+                if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) {
+                    throw new IllegalArgumentException(
+                            "Can't set rollbackLifetimeMillis when rollback is not enabled");
+                }
+                if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException(
+                            "Setting rollback lifetime requires the MANAGE_ROLLBACKS permission");
+                }
+            } else if (params.rollbackLifetimeMillis < 0) {
+                throw new IllegalArgumentException("rollbackLifetimeMillis can't be negative.");
+            }
+        }
+
         boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
         if (isApex) {
             if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5dc7dab..1be28ca 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1282,6 +1282,7 @@
             info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
             info.autoRevokePermissionsMode = params.autoRevokePermissionsMode;
             info.installFlags = params.installFlags;
+            info.rollbackLifetimeMillis = params.rollbackLifetimeMillis;
             info.isMultiPackage = params.isMultiPackage;
             info.isStaged = params.isStaged;
             info.rollbackDataPolicy = params.rollbackDataPolicy;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 978d8e4..3430bb4d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2138,6 +2138,19 @@
     }
 
     @Override
+    public boolean isForegroundUserAdmin() {
+        // No permission requirements for this API.
+        synchronized (mUsersLock) {
+            final int currentUserId = getCurrentUserId();
+            if (currentUserId != UserHandle.USER_NULL) {
+                final UserInfo userInfo = getUserInfoLU(currentUserId);
+                return userInfo != null && userInfo.isAdmin();
+            }
+        }
+        return false;
+    }
+
+    @Override
     public @NonNull String getUserName() {
         final int callingUid = Binder.getCallingUid();
         if (!hasQueryOrCreateUsersPermission()
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 85d93f4..a5b90f1 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -174,6 +174,11 @@
     @Nullable private final String mInstallerPackageName;
 
     /**
+     * Time after which rollback expires.
+     */
+    private long mRollbackLifetimeMillis = 0;
+
+    /**
      * Session ids for all packages in the install. For multi-package sessions, this is the list
      * of child session ids. For normal sessions, this list is a single element with the normal
      * session id.
@@ -286,6 +291,24 @@
     }
 
     /**
+     * Sets rollback lifetime in milliseconds, for purposes of expiring rollback data.
+     */
+    @WorkerThread
+    void setRollbackLifetimeMillis(long lifetimeMillis) {
+        assertInWorkerThread();
+        mRollbackLifetimeMillis = lifetimeMillis;
+    }
+
+    /**
+     * Returns rollback lifetime in milliseconds, for purposes of expiring rollback data.
+     */
+    @WorkerThread
+    long getRollbackLifetimeMillis() {
+        assertInWorkerThread();
+        return mRollbackLifetimeMillis;
+    }
+
+    /**
      * Returns the session ID associated with this rollback, or {@code -1} if unknown.
      */
     @AnyThread
@@ -930,6 +953,7 @@
         ipw.println("-state: " + getStateAsString());
         ipw.println("-stateDescription: " + mStateDescription);
         ipw.println("-timestamp: " + getTimestamp());
+        ipw.println("-rollbackLifetimeMillis: " + getRollbackLifetimeMillis());
         ipw.println("-isStaged: " + isStaged());
         ipw.println("-originalSessionId: " + getOriginalSessionId());
         ipw.println("-packages:");
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 720c773..8d93408 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -28,6 +28,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
@@ -702,6 +703,15 @@
     // Schedules future expiration as appropriate.
     @WorkerThread
     private void runExpiration() {
+        if (Flags.rollbackLifetime()) {
+            runExpirationCustomRollbackLifetime();
+        } else {
+            runExpirationDefaultRollbackLifetime();
+        }
+    }
+
+    @WorkerThread
+    private void runExpirationDefaultRollbackLifetime() {
         getHandler().removeCallbacks(mRunExpiration);
         assertInWorkerThread();
         Instant now = Instant.now();
@@ -729,6 +739,44 @@
         }
     }
 
+    @WorkerThread
+    private void runExpirationCustomRollbackLifetime() {
+        getHandler().removeCallbacks(mRunExpiration);
+        assertInWorkerThread();
+        Instant now = Instant.now();
+        long minDelay = 0;
+        Iterator<Rollback> iter = mRollbacks.iterator();
+        while (iter.hasNext()) {
+            Rollback rollback = iter.next();
+            if (!rollback.isAvailable() && !rollback.isCommitted()) {
+                continue;
+            }
+            long rollbackLifetimeMillis = rollback.getRollbackLifetimeMillis();
+            if (rollbackLifetimeMillis <= 0) {
+                rollbackLifetimeMillis = mRollbackLifetimeDurationInMillis;
+            }
+
+            Instant rollbackExpiryTimestamp = rollback.getTimestamp()
+                    .plusMillis(rollbackLifetimeMillis);
+            if (!now.isBefore(rollbackExpiryTimestamp)) {
+                Slog.i(TAG, "runExpiration id=" + rollback.info.getRollbackId());
+                iter.remove();
+                deleteRollback(rollback, "Expired by timeout");
+                continue;
+            }
+
+            long delay = now.until(
+                    rollbackExpiryTimestamp, ChronoUnit.MILLIS);
+            if (minDelay == 0 || delay < minDelay) {
+                minDelay = delay;
+            }
+        }
+
+        if (minDelay != 0) {
+            getHandler().postDelayed(mRunExpiration, minDelay);
+        }
+    }
+
     @AnyThread
     private Handler getHandler() {
         return mHandler;
@@ -1277,6 +1325,7 @@
         }
 
         final Rollback rollback;
+
         if (parentSession.isStaged()) {
             rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
                     installerPackageName, packageSessionIds, getExtensionVersions());
@@ -1285,6 +1334,11 @@
                     installerPackageName, packageSessionIds, getExtensionVersions());
         }
 
+        if (Flags.rollbackLifetime()) {
+            rollback.setRollbackLifetimeMillis(parentSession.rollbackLifetimeMillis);
+        }
+
+
         mRollbacks.add(rollback);
         return rollback;
     }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 8068c6f..0af137f 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -19,6 +19,7 @@
 import static com.android.server.rollback.Rollback.rollbackStateFromString;
 
 import android.annotation.NonNull;
+import android.content.pm.Flags;
 import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
@@ -312,6 +313,9 @@
             JSONObject dataJson = new JSONObject();
             dataJson.put("info", rollbackInfoToJson(rollback.info));
             dataJson.put("timestamp", rollback.getTimestamp().toString());
+            if (Flags.rollbackLifetime()) {
+                dataJson.put("rollbackLifetimeMillis", rollback.getRollbackLifetimeMillis());
+            }
             dataJson.put("originalSessionId", rollback.getOriginalSessionId());
             dataJson.put("state", rollback.getStateAsString());
             dataJson.put("stateDescription", rollback.getStateDescription());
@@ -375,7 +379,7 @@
     @VisibleForTesting
     static Rollback rollbackFromJson(JSONObject dataJson, File backupDir)
             throws JSONException, ParseException {
-        return new Rollback(
+        Rollback rollback = new Rollback(
                 rollbackInfoFromJson(dataJson.getJSONObject("info")),
                 backupDir,
                 Instant.parse(dataJson.getString("timestamp")),
@@ -388,6 +392,10 @@
                 dataJson.optInt("userId", UserHandle.SYSTEM.getIdentifier()),
                 dataJson.optString("installerPackageName", ""),
                 extensionVersionsFromJson(dataJson.optJSONArray("extensionVersions")));
+        if (Flags.rollbackLifetime()) {
+            rollback.setRollbackLifetimeMillis(dataJson.optLong("rollbackLifetimeMillis"));
+        }
+        return rollback;
     }
 
     private static JSONObject toJson(VersionedPackage pkg) throws JSONException {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 635e11b..f82f08b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -70,7 +70,6 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
-import android.view.Display;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -79,7 +78,6 @@
 import com.android.internal.infra.AndroidFuture;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
 
@@ -1523,57 +1521,13 @@
             mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
         }
 
-        /**
-         * @param uid: uid of the calling app (obtained via getCallingUid())
-         * @param displayId: the id of a Display
-         * @return Returns true if both of the following conditions hold -
-         * 1) the uid belongs to an app instead of a system core component; and
-         * 2) either the uid is running on a virtual device or the displayId
-         *    is owned by a virtual device
-         */
-        private boolean isAppOrDisplayOnAnyVirtualDevice(int uid, int displayId) {
-            if (UserHandle.isCore(uid)) {
-                return false;
-            }
-
-            if (mVirtualDeviceManager == null) {
-                mVirtualDeviceManager = LocalServices.getService(
-                        VirtualDeviceManagerInternal.class);
-                if (mVirtualDeviceManager == null) {
-                    // VirtualDeviceManager service may not have been published
-                    return false;
-                }
-            }
-
-            switch (displayId) {
-                case Display.INVALID_DISPLAY:
-                    // There is no Display object associated with the Context of the calling app.
-                    if (mVirtualDeviceManager.isAppRunningOnAnyVirtualDevice(uid)) {
-                        return true;
-                    }
-                    break;
-                case Display.DEFAULT_DISPLAY:
-                    // The DEFAULT_DISPLAY is by definition not virtual.
-                    break;
-                default:
-                    // Other display IDs can belong to logical displays created for other purposes.
-                    if (mVirtualDeviceManager.isDisplayOwnedByAnyVirtualDevice(displayId)) {
-                        return true;
-                    }
-                    break;
-            }
-            return false;
-        }
-
         @Override
-        public boolean isDeviceLocked(int userId, int displayId) throws RemoteException {
-            int uid = getCallingUid();
-            if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
-                // Virtual displays are considered insecure because they may be used for streaming
-                // to other devices.
+        public boolean isDeviceLocked(int userId, int deviceId) throws RemoteException {
+            if (deviceId != Context.DEVICE_ID_DEFAULT) {
+                // Virtual devices are considered insecure.
                 return false;
             }
-            userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
+            userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
 
             final long token = Binder.clearCallingIdentity();
@@ -1588,15 +1542,12 @@
         }
 
         @Override
-        public boolean isDeviceSecure(int userId, int displayId) throws RemoteException {
-            int uid = getCallingUid();
-            if (isAppOrDisplayOnAnyVirtualDevice(uid, displayId)) {
-                // Virtual displays are considered insecure because they may be used for streaming
-                // to other devices.
+        public boolean isDeviceSecure(int userId, int deviceId) throws RemoteException {
+            if (deviceId != Context.DEVICE_ID_DEFAULT) {
+                // Virtual devices are considered insecure.
                 return false;
             }
-
-            userId = ActivityManager.handleIncomingUser(getCallingPid(), uid, userId,
+            userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
 
             final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7893da..f314900 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4716,6 +4716,17 @@
             scheduleAnimation();
 
             mWmService.mH.post(() -> InputMethodManagerInternal.get().onImeParentChanged());
+        } else if (mImeControlTarget != null && mImeControlTarget == mImeLayeringTarget) {
+            // Even if the IME surface parent is not changed, the layer target belonging to the
+            // parent may have changes. Then attempt to reassign if the IME control target is
+            // possible to be the relative layer.
+            final SurfaceControl lastRelativeLayer = mImeWindowsContainer.getLastRelativeLayer();
+            if (lastRelativeLayer != mImeLayeringTarget.mSurfaceControl) {
+                assignRelativeLayerForIme(getSyncTransaction(), false /* forceUpdate */);
+                if (lastRelativeLayer != mImeWindowsContainer.getLastRelativeLayer()) {
+                    scheduleAnimation();
+                }
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index d2f6d16..6cad16c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -486,8 +486,6 @@
 
     private boolean mForceShowForAllUsers;
 
-    private boolean mForceTranslucent = false;
-
     // The display category name for this task.
     String mRequiredDisplayCategory;
 
@@ -3643,7 +3641,7 @@
      */
     TaskFragmentParentInfo getTaskFragmentParentInfo() {
         return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(),
-                shouldBeVisible(null /* starting */));
+                shouldBeVisible(null /* starting */), hasNonFinishingDirectActivity());
     }
 
     @Override
@@ -4502,10 +4500,6 @@
         return true;
     }
 
-    void setForceTranslucent(boolean set) {
-        mForceTranslucent = set;
-    }
-
     @Override
     public boolean isAlwaysOnTop() {
         return !isForceHidden() && super.isAlwaysOnTop();
@@ -4523,11 +4517,6 @@
     }
 
     @Override
-    protected boolean isForceTranslucent() {
-        return mForceTranslucent;
-    }
-
-    @Override
     long getProtoFieldId() {
         return TASK;
     }
@@ -6062,6 +6051,11 @@
             // Non-root task position changed.
             mRootWindowContainer.invalidateTaskLayers();
         }
+
+        if (child.asActivityRecord() != null) {
+            // Send for TaskFragmentParentInfo#hasDirectActivity change.
+            sendTaskFragmentParentInfoChangedIfNeeded();
+        }
     }
 
     void reparent(TaskDisplayArea newParent, boolean onTop) {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 82d3424..00f2b89 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -374,6 +374,8 @@
     @interface FlagForceHidden {}
     protected int mForceHiddenFlags = 0;
 
+    private boolean mForceTranslucent = false;
+
     final Point mLastSurfaceSize = new Point();
 
     private final Rect mTmpBounds = new Rect();
@@ -843,8 +845,12 @@
         return true;
     }
 
-    protected boolean isForceTranslucent() {
-        return false;
+    boolean isForceTranslucent() {
+        return mForceTranslucent;
+    }
+
+    void setForceTranslucent(boolean set) {
+        mForceTranslucent = set;
     }
 
     boolean isLeafTaskFragment() {
@@ -1049,6 +1055,10 @@
         return getActivity(ActivityRecord::canBeTopRunning);
     }
 
+    /**
+     * Reports non-finishing activity count including this TaskFragment's child embedded
+     * TaskFragments' children activities.
+     */
     int getNonFinishingActivityCount() {
         final int[] runningActivityCount = new int[1];
         forAllActivities(a -> {
@@ -1059,6 +1069,20 @@
         return runningActivityCount[0];
     }
 
+    /**
+     * Returns {@code true} if there's any non-finishing direct children activity, which is not
+     * embedded in TaskFragments
+     */
+    boolean hasNonFinishingDirectActivity() {
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityRecord activity = getChildAt(i).asActivityRecord();
+            if (activity != null && !activity.finishing) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     boolean isTopActivityFocusable() {
         final ActivityRecord r = topRunningActivity();
         return r != null ? r.isFocusable()
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4a0f44b..8f884d2f 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2706,6 +2706,10 @@
         return mLastLayer;
     }
 
+    SurfaceControl getLastRelativeLayer() {
+        return mLastRelativeToLayer;
+    }
+
     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
         if (mSurfaceFreezer.hasLeash()) {
             // When the freezer has created animation leash parent for the window, set the layer
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index eb60aab..a8b9417 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -37,6 +37,7 @@
 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
 import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN;
 import static android.window.WindowContainerTransaction.Change.CHANGE_FOCUSABLE;
+import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT;
 import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN;
 import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER;
@@ -768,8 +769,7 @@
             }
         }
 
-        if ((c.getChangeMask()
-                & WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT) != 0) {
+        if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {
             tr.setForceTranslucent(c.getForceTranslucent());
             effects = TRANSACT_EFFECTS_LIFECYCLE;
         }
@@ -877,6 +877,11 @@
                 effects |= TRANSACT_EFFECTS_LIFECYCLE;
             }
         }
+        if ((c.getChangeMask() & CHANGE_FORCE_TRANSLUCENT) != 0) {
+            taskFragment.setForceTranslucent(c.getForceTranslucent());
+            effects = TRANSACT_EFFECTS_LIFECYCLE;
+        }
+
         effects |= applyChanges(taskFragment, c);
 
         if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) {
@@ -2022,9 +2027,11 @@
 
         if (mTaskFragmentOrganizerController.isSystemOrganizer(organizer.asBinder())) {
             // System organizer is allowed to update the hidden and focusable state.
-            // We unset the CHANGE_HIDDEN and CHANGE_FOCUSABLE bits because they are checked here.
+            // We unset the CHANGE_HIDDEN, CHANGE_FOCUSABLE, and CHANGE_FORCE_TRANSLUCENT bits
+            // because they are checked here.
             changeMaskToBeChecked &= ~CHANGE_HIDDEN;
             changeMaskToBeChecked &= ~CHANGE_FOCUSABLE;
+            changeMaskToBeChecked &= ~CHANGE_FORCE_TRANSLUCENT;
         }
 
         // setRelativeBounds is allowed.
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 4e6dd06..ece3dfe 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -674,6 +674,17 @@
     }
 
     @Test
+    public void notifyPermissionRequestCancelled_forwardsToLogger() {
+        int hostUid = 123;
+        mService =
+                new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
+
+        mService.notifyPermissionRequestCancelled(hostUid);
+
+        verify(mMediaProjectionMetricsLogger).logProjectionPermissionRequestCancelled(hostUid);
+    }
+
+    @Test
     public void notifyAppSelectorDisplayed_forwardsToLogger() {
         int hostUid = 456;
         mService =
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
index 410604f..ad1cd6e 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionMetricsLoggerTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_APP_SELECTOR_DISPLAYED;
+import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CAPTURING_IN_PROGRESS;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED;
 import static com.android.internal.util.FrameworkStatsLog.MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_PERMISSION_REQUEST_DISPLAYED;
@@ -452,6 +453,63 @@
                 MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_STOPPED);
     }
 
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsStateChangedAtomId() {
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifyStateChangedAtomIdLogged();
+    }
+
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsExistingSessionId() {
+        int existingSessionId = 456;
+        when(mSessionIdGenerator.getCurrentSessionId()).thenReturn(existingSessionId);
+
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifySessionIdLogged(existingSessionId);
+    }
+
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsStateCancelled() {
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifyStateLogged(MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_CANCELLED);
+    }
+
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsPreviousState() {
+        mLogger.logInitiated(TEST_HOST_UID, TEST_CREATION_SOURCE);
+        verifyPreviousStateLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_UNKNOWN);
+
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+        verifyPreviousStateLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__STATE__MEDIA_PROJECTION_STATE_INITIATED);
+    }
+
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsHostUid() {
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifyHostUidLogged(TEST_HOST_UID);
+    }
+
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsUnknownTargetUid() {
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifyTargetUidLogged(-2);
+    }
+
+    @Test
+    public void logProjectionPermissionRequestCancelled_logsUnknownCreationSource() {
+        mLogger.logProjectionPermissionRequestCancelled(TEST_HOST_UID);
+
+        verifyCreationSourceLogged(
+                MEDIA_PROJECTION_STATE_CHANGED__CREATION_SOURCE__CREATION_SOURCE_UNKNOWN);
+    }
+
     private void verifyStateChangedAtomIdLogged() {
         verify(mFrameworkStatsLogWrapper)
                 .write(
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index fc27edc..a4d50f0 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -94,27 +94,31 @@
     public void testBugreportFileManagerFileExists() {
         Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
         mBugreportFileManager.addBugreportFileForCaller(
-                callingInfo, mBugreportFile);
+                callingInfo, mBugreportFile, /* keepOnRetrieval= */ false);
 
         assertThrows(IllegalArgumentException.class, () ->
                 mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                        callingInfo, "unknown-file.zip"));
+                        mContext, callingInfo, Process.myUserHandle().getIdentifier(),
+                        "unknown-file.zip"));
 
         // No exception should be thrown.
-        mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(callingInfo, mBugreportFile);
+        mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
+                mContext, callingInfo, mContext.getUserId(), mBugreportFile);
     }
 
     @Test
     public void testBugreportFileManagerMultipleFiles() {
         Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
         mBugreportFileManager.addBugreportFileForCaller(
-                callingInfo, mBugreportFile);
+                callingInfo, mBugreportFile, /* keepOnRetrieval= */ false);
         mBugreportFileManager.addBugreportFileForCaller(
-                callingInfo, mBugreportFile2);
+                callingInfo, mBugreportFile2, /* keepOnRetrieval= */ false);
 
         // No exception should be thrown.
-        mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(callingInfo, mBugreportFile);
-        mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(callingInfo, mBugreportFile2);
+        mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
+                mContext, callingInfo, mContext.getUserId(), mBugreportFile);
+        mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
+                mContext, callingInfo, mContext.getUserId(), mBugreportFile2);
     }
 
     @Test
@@ -122,7 +126,8 @@
         Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
         assertThrows(IllegalArgumentException.class,
                 () -> mBugreportFileManager.ensureCallerPreviouslyGeneratedFile(
-                        callingInfo, "test-file.zip"));
+                        mContext, callingInfo, Process.myUserHandle().getIdentifier(),
+                        "test-file.zip"));
     }
 
     @Test
@@ -130,7 +135,8 @@
         CountDownLatch latch = new CountDownLatch(1);
         Listener listener = new Listener(latch);
         mService.retrieveBugreport(Binder.getCallingUid(), mContext.getPackageName(),
-                new FileDescriptor(), mBugreportFile, listener);
+                mContext.getUserId(), new FileDescriptor(), mBugreportFile,
+                /* keepOnRetrieval= */ false, listener);
         assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue();
         assertThat(listener.getErrorCode()).isEqualTo(
                 BugreportCallback.BUGREPORT_ERROR_NO_BUGREPORT_TO_RETRIEVE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 6235b3b..c57b051 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -1742,6 +1742,7 @@
     private void testApplyTransaction_reorder_failsIfNotSystemOrganizer_common(
             @TaskFragmentOperation.OperationType int opType) {
         final Task task = createTask(mDisplayContent);
+        doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded();
         // Create a non-embedded Activity at the bottom.
         final ActivityRecord bottomActivity = new ActivityBuilder(mAtm)
                 .setTask(task)
@@ -1934,7 +1935,7 @@
     /** Setups the mock Task as the parent of the given TaskFragment. */
     private static void setupMockParent(TaskFragment taskFragment, Task mockParent) {
         doReturn(mockParent).when(taskFragment).getTask();
-        doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true))
+        doReturn(new TaskFragmentParentInfo(new Configuration(), DEFAULT_DISPLAY, true, true))
                 .when(mockParent).getTaskFragmentParentInfo();
 
         // Task needs to be visible
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 0c58069..435a835 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1568,6 +1568,7 @@
 
         final TaskFragment fragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
         final ActivityRecord embeddedActivity = fragment.getTopMostActivity();
+        doNothing().when(task).sendTaskFragmentParentInfoChangedIfNeeded();
         task.moveActivityToFront(activity);
         assertEquals("Activity must be moved to front", activity, task.getTopMostActivity());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index cd3fef6..699580a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -101,6 +101,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.function.BiConsumer;
 
 /**
  * Test class for {@link ITaskOrganizer} and {@link android.window.ITaskOrganizerController}.
@@ -583,7 +584,7 @@
     }
 
     @Test
-    public void testTaskFragmentHiddenAndFocusableChanges() {
+    public void testTaskFragmentHiddenFocusableTranslucentChanges() {
         removeGlobalMinSizeRestriction();
         final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
@@ -605,10 +606,12 @@
         assertTrue(taskFragment.shouldBeVisible(null));
         assertTrue(taskFragment.isFocusable());
         assertTrue(taskFragment.isTopActivityFocusable());
+        assertFalse(taskFragment.isForceTranslucent());
 
         // Apply transaction to the TaskFragment hidden and not focusable.
         t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), true);
         t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), false);
+        t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), true);
         mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
                 t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
                 false /* shouldApplyIndependently */);
@@ -617,10 +620,12 @@
         assertFalse(taskFragment.shouldBeVisible(null));
         assertFalse(taskFragment.isFocusable());
         assertFalse(taskFragment.isTopActivityFocusable());
+        assertTrue(taskFragment.isForceTranslucent());
 
         // Apply transaction to the TaskFragment not hidden and focusable.
         t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), false);
         t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), true);
+        t.setForceTranslucent(taskFragment.mRemoteToken.toWindowContainerToken(), false);
         mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
                 t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
                 false /* shouldApplyIndependently */);
@@ -629,10 +634,32 @@
         assertTrue(taskFragment.shouldBeVisible(null));
         assertTrue(taskFragment.isFocusable());
         assertTrue(taskFragment.isTopActivityFocusable());
+        assertFalse(taskFragment.isForceTranslucent());
     }
 
     @Test
-    public void testTaskFragmentHiddenAndFocusableChanges_throwsWhenNotSystemOrganizer() {
+    public void testTaskFragmentChangeHidden_throwsWhenNotSystemOrganizer() {
+        // Non-system organizers are not allow to update the hidden state.
+        testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+                (t, windowContainerToken) -> t.setHidden(windowContainerToken, true));
+    }
+
+    @Test
+    public void testTaskFragmentChangeFocusable_throwsWhenNotSystemOrganizer() {
+        // Non-system organizers are not allow to update the focusable state.
+        testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+                (t, windowContainerToken) -> t.setFocusable(windowContainerToken, false));
+    }
+
+    @Test
+    public void testTaskFragmentChangeTranslucent_throwsWhenNotSystemOrganizer() {
+        // Non-system organizers are not allow to update the translucent state.
+        testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+                (t, windowContainerToken) -> t.setForceTranslucent(windowContainerToken, true));
+    }
+
+    private void testTaskFragmentChangesWithoutSystemOrganizerThrowException(
+            BiConsumer<WindowContainerTransaction, WindowContainerToken> addOp) {
         removeGlobalMinSizeRestriction();
         final Task rootTask = new TaskBuilder(mSupervisor).setCreateActivity(true)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
@@ -641,21 +668,15 @@
         final TaskFragmentOrganizer organizer =
                 createTaskFragmentOrganizer(t, false /* isSystemOrganizer */);
 
-        final IBinder token = new Binder();
         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(rootTask)
-                .setFragmentToken(token)
+                .setFragmentToken(new Binder())
                 .setOrganizer(organizer)
                 .createActivityCount(1)
                 .build();
 
-        assertTrue(rootTask.shouldBeVisible(null));
-        assertTrue(taskFragment.shouldBeVisible(null));
+        addOp.accept(t, taskFragment.mRemoteToken.toWindowContainerToken());
 
-        t.setHidden(taskFragment.mRemoteToken.toWindowContainerToken(), true);
-        t.setFocusable(taskFragment.mRemoteToken.toWindowContainerToken(), false);
-
-        // Non-system organizers are not allow to update the hidden and focusable states.
         assertThrows(SecurityException.class, () ->
                 mWm.mAtmService.mWindowOrganizerController.applyTaskFragmentTransactionLocked(
                         t, TaskFragmentOrganizer.TASK_FRAGMENT_TRANSIT_CHANGE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 3ec6f42..973ab84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -448,7 +448,6 @@
         mDisplayContent.updateImeParent();
 
         // Ime should on top of the popup IME layering target window.
-        mDisplayContent.assignChildLayers(mTransaction);
         assertWindowHigher(mImeWindow, popupImeTargetWin);
     }
 
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index a1a39ff..359ef83 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -125,6 +125,17 @@
                 TUNNEL_CONNECTION_PARAMS);
     }
 
+    private static VcnGatewayConnectionConfig.Builder newBuilderMinimal() {
+        final VcnGatewayConnectionConfig.Builder builder =
+                new VcnGatewayConnectionConfig.Builder(
+                        "newBuilderMinimal", TUNNEL_CONNECTION_PARAMS);
+        for (int caps : EXPOSED_CAPS) {
+            builder.addExposedCapability(caps);
+        }
+
+        return builder;
+    }
+
     private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions(
             VcnGatewayConnectionConfig.Builder builder,
             Set<Integer> gatewayOptions,
@@ -273,6 +284,7 @@
 
         assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
         assertEquals(MAX_MTU, config.getMaxMtu());
+        assertTrue(config.isSafeModeEnabled());
 
         assertFalse(
                 config.hasGatewayOption(
@@ -290,6 +302,13 @@
     }
 
     @Test
+    public void testBuilderAndGettersSafeModeDisabled() {
+        final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build();
+
+        assertFalse(config.isSafeModeEnabled());
+    }
+
+    @Test
     public void testPersistableBundle() {
         final VcnGatewayConnectionConfig config = buildTestConfig();
 
@@ -305,6 +324,13 @@
     }
 
     @Test
+    public void testPersistableBundleSafeModeDisabled() {
+        final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build();
+
+        assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
+    }
+
+    @Test
     public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() {
         PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
         configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null);
@@ -411,4 +437,18 @@
         assertEquals(config, configEqual);
         assertNotEquals(config, configNotEqual);
     }
+
+    @Test
+    public void testSafeModeEnableDisableEquality() throws Exception {
+        final VcnGatewayConnectionConfig config = newBuilderMinimal().build();
+        final VcnGatewayConnectionConfig configEqual = newBuilderMinimal().build();
+
+        assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled());
+
+        final VcnGatewayConnectionConfig configNotEqual =
+                newBuilderMinimal().enableSafeMode(false).build();
+
+        assertEquals(config, configEqual);
+        assertNotEquals(config, configNotEqual);
+    }
 }