Merge "Move screenshot_context_url to sysui shared flags" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a60fd11..e724ab8 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12676,21 +12676,27 @@
 package android.security.advancedprotection {
 
   @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionFeature implements android.os.Parcelable {
-    ctor public AdvancedProtectionFeature(int);
+    ctor public AdvancedProtectionFeature(@NonNull String);
     method public int describeContents();
-    method public int getId();
+    method @NonNull public String getId();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.security.advancedprotection.AdvancedProtectionFeature> CREATOR;
   }
 
   @FlaggedApi("android.security.aapm_api") public final class AdvancedProtectionManager {
+    method @NonNull public android.content.Intent createSupportIntent(@NonNull String, @Nullable String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public java.util.List<android.security.advancedprotection.AdvancedProtectionFeature> getAdvancedProtectionFeatures();
     method @RequiresPermission(android.Manifest.permission.MANAGE_ADVANCED_PROTECTION_MODE) public void setAdvancedProtectionEnabled(boolean);
-    field public static final int FEATURE_ID_DISALLOW_CELLULAR_2G = 0; // 0x0
-    field public static final int FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = 1; // 0x1
-    field public static final int FEATURE_ID_DISALLOW_USB = 2; // 0x2
-    field public static final int FEATURE_ID_DISALLOW_WEP = 3; // 0x3
-    field public static final int FEATURE_ID_ENABLE_MTE = 4; // 0x4
+    field @FlaggedApi("android.security.aapm_api") public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG = "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
+    field public static final String EXTRA_SUPPORT_DIALOG_FEATURE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
+    field public static final String EXTRA_SUPPORT_DIALOG_TYPE = "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
+    field public static final String FEATURE_ID_DISALLOW_CELLULAR_2G = "android.security.advancedprotection.feature_disallow_2g";
+    field public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = "android.security.advancedprotection.feature_disallow_install_unknown_sources";
+    field public static final String FEATURE_ID_DISALLOW_USB = "android.security.advancedprotection.feature_disallow_usb";
+    field public static final String FEATURE_ID_DISALLOW_WEP = "android.security.advancedprotection.feature_disallow_wep";
+    field public static final String FEATURE_ID_ENABLE_MTE = "android.security.advancedprotection.feature_enable_mte";
+    field public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = "android.security.advancedprotection.type_blocked_interaction";
+    field public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING = "android.security.advancedprotection.type_disabled_setting";
   }
 
 }
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 4db3727..0e45902 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -38,6 +38,7 @@
 import android.os.PowerExemptionManager;
 import android.os.PowerExemptionManager.ReasonCode;
 import android.os.PowerExemptionManager.TempAllowListType;
+import android.os.Process;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -76,6 +77,7 @@
             FLAG_IS_ALARM_BROADCAST,
             FLAG_SHARE_IDENTITY,
             FLAG_INTERACTIVE,
+            FLAG_DEBUG_LOG,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flags {}
@@ -86,6 +88,7 @@
     private static final int FLAG_IS_ALARM_BROADCAST = 1 << 3;
     private static final int FLAG_SHARE_IDENTITY = 1 << 4;
     private static final int FLAG_INTERACTIVE = 1 << 5;
+    private static final int FLAG_DEBUG_LOG = 1 << 6;
 
     /**
      * Change ID which is invalid.
@@ -1082,6 +1085,34 @@
     }
 
     /**
+     * If enabled, additional debug messages for broadcast delivery will be logged.
+     *
+     * <p> This will only take effect when used by {@link Process#SHELL_UID}
+     * or {@link Process#ROOT_UID} or by apps under instrumentation.
+     *
+     * @hide
+     */
+    @NonNull
+    public BroadcastOptions setDebugLogEnabled(boolean enabled) {
+        if (enabled) {
+            mFlags |= FLAG_DEBUG_LOG;
+        } else {
+            mFlags &= ~FLAG_DEBUG_LOG;
+        }
+        return this;
+    }
+
+    /**
+     * @return if additional debug messages for broadcast delivery are enabled.
+     *
+     * @see #setDebugLogEnabled(boolean)
+     * @hide
+     */
+    public boolean isDebugLogEnabled() {
+        return (mFlags & FLAG_DEBUG_LOG) != 0;
+    }
+
+    /**
      * Returns the created options as a Bundle, which can be passed to
      * {@link android.content.Context#sendBroadcast(android.content.Intent)
      * Context.sendBroadcast(Intent)} and related methods.
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index a6c1a57..0451ac0 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -270,6 +270,6 @@
 
     int[] getAllowedAdjustmentKeyTypes();
     void setAssistantAdjustmentKeyTypeState(int type, boolean enabled);
-    String[] getTypeAdjustmentDeniedPackages();
-    void setTypeAdjustmentForPackageState(String pkg, boolean enabled);
+    int[] getAllowedAdjustmentKeyTypesForPackage(String pkg);
+    void setAssistantAdjustmentKeyTypeStateForPackage(String pkg, int type, boolean enabled);
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index ec10913..08bd854 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1986,10 +1986,12 @@
      * @hide
      */
     @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-    public void setTypeAdjustmentForPackageState(@NonNull String pkg, boolean enabled) {
+    public void setAssistantAdjustmentKeyTypeStateForPackage(@NonNull String pkg,
+                                                             @Adjustment.Types int type,
+                                                             boolean enabled) {
         INotificationManager service = service();
         try {
-            service.setTypeAdjustmentForPackageState(pkg, enabled);
+            service.setAssistantAdjustmentKeyTypeStateForPackage(pkg, type, enabled);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index f29e2e8..2ad9660 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -211,6 +211,16 @@
 }
 
 flag {
+    name: "place_add_user_dialog_within_activity"
+    namespace: "multiuser"
+    description: "Display dialog within activity to make it traversable by Accessibility"
+    bug: "383034393"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
     name: "property_invalidated_cache_bypass_mismatched_uids"
     namespace: "multiuser"
     description: "Bypass the cache when the process UID does not match the binder UID."
diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java
index da9d4f4..0e2c05f 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -246,10 +246,9 @@
         // The optimal pair is the pair which has the smallest deviation. The deviation consists of
         // an x-axis component and a y-axis component, called xDeviation and yDeviation.
         //
-        // The deviations are like distances but a little different. They are calculated in two
-        // steps. The first step calculates both axes in a similar way. The next step compares the
-        // two values and chooses which axis to attach along. Depending on which axis is chosen,
-        // the deviation for one axis is updated. See below for details.
+        // The deviations are like distances but a little different. When they are calculated, each
+        // dimension is treated differently, depending on which edges (left+right or top+bottom) are
+        // attached.
         while (!needsParent.isEmpty()) {
             double bestDist = Double.POSITIVE_INFINITY;
             TreeNode bestChild = null, bestParent = null;
@@ -263,33 +262,32 @@
                     float parentRight = parentPos.x + parent.getWidth();
                     float parentBottom = parentPos.y + parent.getHeight();
 
-                    // This is the smaller of the two ranges minus the amount of overlap shared
-                    // between them. The "amount of overlap" is negative if there is no overlap, but
-                    // this does not make a parenting ineligible, because we allow for attaching at
-                    // the corner and for floating point error. The overlap is more negative the
-                    // farther apart the closest corner pair is.
-                    //
-                    // For each axis, this calculates (SmallerRange - Overlap). If one range lies
-                    // completely in the other (or they are equal), the axis' deviation will be
-                    // zero.
-                    //
-                    // The "SmallerRange," which refers to smaller of the widths of the two rects,
-                    // or smaller of the heights of the two rects, is added to the deviation so that
-                    // a maximum overlap results in a deviation of zero.
-                    float xSmallerRange = Math.min(child.getWidth(), parent.getWidth());
-                    float ySmallerRange = Math.min(child.getHeight(), parent.getHeight());
-                    float xOverlap
-                            = Math.min(parentRight, childRight)
-                            - Math.max(parentPos.x, childPos.x);
-                    float yOverlap
-                            = Math.min(parentBottom, childBottom)
-                            - Math.max(parentPos.y, childPos.y);
-                    float xDeviation = xSmallerRange - xOverlap;
-                    float yDeviation = ySmallerRange - yOverlap;
+                    // The "amount of overlap" indicates how much of one display is within the other
+                    // (considering one axis only). It's zero if they only share an edge and
+                    // negative if they're away from each other.
+                    // A zero or negative overlap does not make a parenting ineligible, because we
+                    // allow for attaching at the corner and for floating point error.
+                    float xOverlap =
+                            Math.min(parentRight, childRight) - Math.max(parentPos.x, childPos.x);
+                    float yOverlap =
+                            Math.min(parentBottom, childBottom) - Math.max(parentPos.y, childPos.y);
+                    float xDeviation, yDeviation;
 
                     float offset;
                     int pos;
-                    if (xDeviation <= yDeviation) {
+                    if (Math.abs(xOverlap) > Math.abs(yOverlap)) {
+                        // Deviation in each dimension is a penalty in the potential parenting. To
+                        // get the X deviation, overlap is subtracted from the lesser width so that
+                        // a maximum overlap results in a deviation of zero.
+                        // Note that because xOverlap is *subtracted* from the lesser width, no
+                        // overlap in X becomes a *penalty* if we are attaching on the top+bottom
+                        // edges.
+                        //
+                        // The Y deviation is simply the distance from the clamping edges.
+                        //
+                        // Treatment of the X and Y deviations are swapped for
+                        // POSITION_LEFT/POSITION_RIGHT attachments in the "else" block below.
+                        xDeviation = Math.min(child.getWidth(), parent.getWidth()) - xOverlap;
                         if (childPos.y < parentPos.y) {
                             yDeviation = childBottom - parentPos.y;
                             pos = POSITION_TOP;
@@ -299,6 +297,7 @@
                         }
                         offset = childPos.x - parentPos.x;
                     } else {
+                        yDeviation = Math.min(child.getHeight(), parent.getHeight()) - yOverlap;
                         if (childPos.x < parentPos.x) {
                             xDeviation = childRight - parentPos.x;
                             pos = POSITION_LEFT;
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 34c88e9..8da630c 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -28,6 +28,7 @@
 import static com.android.hardware.input.Flags.mouseScrollingAcceleration;
 import static com.android.hardware.input.Flags.mouseReverseVerticalScrolling;
 import static com.android.hardware.input.Flags.mouseSwapPrimaryButton;
+import static com.android.hardware.input.Flags.pointerAcceleration;
 import static com.android.hardware.input.Flags.touchpadSystemGestureDisable;
 import static com.android.hardware.input.Flags.touchpadThreeFingerTapShortcut;
 import static com.android.hardware.input.Flags.touchpadVisualizer;
@@ -418,6 +419,15 @@
     }
 
     /**
+     * Returns true if the feature flag for the pointer acceleration toggle is
+     * enabled.
+     * @hide
+     */
+    public static boolean isPointerAccelerationFeatureFlagEnabled() {
+        return pointerAcceleration();
+    }
+
+    /**
      * Returns true if the touchpad visualizer is allowed to appear.
      *
      * @param context The application context.
@@ -720,6 +730,47 @@
     }
 
     /**
+     * Whether cursor acceleration is enabled or not for connected mice.
+     *
+     * @param context The application context.
+     *
+     * @hide
+     */
+    public static boolean isMousePointerAccelerationEnabled(@NonNull Context context) {
+        if (!isPointerAccelerationFeatureFlagEnabled()) {
+            return false;
+        }
+
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED, 1, UserHandle.USER_CURRENT)
+                == 1;
+    }
+
+   /**
+    * Sets whether mouse acceleration is enabled.
+    *
+    * When enabled, the mouse cursor moves farther when it is moved faster.
+    * When disabled, the mouse cursor speed becomes directly proportional to
+    * the speed at which the mouse is moved.
+    *
+    * @param context The application context.
+    * @param enabled Will enable mouse acceleration if true, disable it if
+    *                false.
+    * @hide
+    */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setMouseAccelerationEnabled(@NonNull Context context,
+            boolean enabled) {
+        if (!isPointerAccelerationFeatureFlagEnabled()) {
+            return;
+        }
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED, enabled ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+
+    /**
      * Whether Accessibility bounce keys feature is enabled.
      *
      * <p>
diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java
index 1cc64f9..4c90750 100644
--- a/core/java/android/inputmethodservice/InlineSuggestionSession.java
+++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.autofill.AutofillFeatureFlags;
 import android.view.autofill.AutofillId;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InlineSuggestionsResponse;
@@ -81,6 +82,7 @@
     @Nullable
     private Boolean mPreviousResponseIsEmpty;
 
+    private boolean mAlwaysNotifyAutofill = false;
 
     /**
      * Indicates whether {@link #makeInlineSuggestionRequestUncheck()} has been called or not,
@@ -105,6 +107,7 @@
         mResponseConsumer = responseConsumer;
         mInlineSuggestionSessionController = inlineSuggestionSessionController;
         mMainThreadHandler = mainThreadHandler;
+        mAlwaysNotifyAutofill = AutofillFeatureFlags.isImproveFillDialogEnabled();
     }
 
     @MainThread
@@ -176,6 +179,9 @@
         try {
             final InlineSuggestionsRequest request = mRequestSupplier.apply(
                     mRequestInfo.getUiExtras());
+            if (mAlwaysNotifyAutofill) {
+                mResponseCallback = new InlineSuggestionsResponseCallbackImpl(this);
+            }
             if (request == null) {
                 if (DEBUG) {
                     Log.d(TAG, "onCreateInlineSuggestionsRequest() returned null request");
@@ -184,7 +190,9 @@
             } else {
                 request.setHostInputToken(mHostInputTokenSupplier.get());
                 request.filterContentTypes();
-                mResponseCallback = new InlineSuggestionsResponseCallbackImpl(this);
+                if (!mAlwaysNotifyAutofill) {
+                    mResponseCallback = new InlineSuggestionsResponseCallbackImpl(this);
+                }
                 mCallback.onInlineSuggestionsRequest(request, mResponseCallback);
             }
         } catch (RemoteException e) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2ad6669..6e58780 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6362,6 +6362,16 @@
         public static final String MOUSE_SCROLLING_ACCELERATION = "mouse_scrolling_acceleration";
 
         /**
+         * Whether mouse acceleration is enabled.
+         *
+         * When enabled, the mouse cursor will accelerate as the mouse moves faster.
+         *
+         * @hide
+         */
+        public static final String MOUSE_POINTER_ACCELERATION_ENABLED =
+                "mouse_pointer_acceleration_enabled";
+
+        /**
          * Pointer fill style, specified by
          * {@link android.view.PointerIcon.PointerIconVectorStyleFill} constants.
          *
@@ -6610,6 +6620,7 @@
             PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
             PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING);
             PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON);
+            PRIVATE_SETTINGS.add(MOUSE_POINTER_ACCELERATION_ENABLED);
             PRIVATE_SETTINGS.add(PREFERRED_REGION);
             PRIVATE_SETTINGS.add(MOUSE_SCROLLING_ACCELERATION);
         }
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java
index d476d96..a086bf7 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionFeature.java
@@ -30,25 +30,26 @@
 @FlaggedApi(Flags.FLAG_AAPM_API)
 @SystemApi
 public final class AdvancedProtectionFeature implements Parcelable {
-    private final int mId;
+    private final String mId;
 
     /**
      * Create an object identifying an Advanced Protection feature for AdvancedProtectionManager
-     * @param id Feature identifier. It is used by Settings screens to display information about
-     *           this feature.
+     * @param id A unique ID to identify this feature. It is used by Settings screens to display
+     *           information about this feature.
      */
-    public AdvancedProtectionFeature(@AdvancedProtectionManager.FeatureId int id) {
+    public AdvancedProtectionFeature(@NonNull String id) {
         mId = id;
     }
 
     private AdvancedProtectionFeature(Parcel in) {
-        mId = in.readInt();
+        mId = in.readString8();
     }
 
     /**
      * @return the unique ID representing this feature
      */
-    public int getId() {
+    @NonNull
+    public String getId() {
         return mId;
     }
 
@@ -59,7 +60,7 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeInt(mId);
+        dest.writeString8(mId);
     }
 
     @NonNull
diff --git a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
index ea01fc9..59628e8 100644
--- a/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
+++ b/core/java/android/security/advancedprotection/AdvancedProtectionManager.java
@@ -24,18 +24,17 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
-import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
-import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.RemoteException;
-import android.os.UserManager;
 import android.security.Flags;
 import android.util.Log;
 
@@ -60,57 +59,54 @@
     private static final String TAG = "AdvancedProtectionMgr";
 
     /**
-     * Advanced Protection's identifier for setting policies or restrictions in
-     * {@link DevicePolicyManager}.
+     * Advanced Protection's identifier for setting policies or restrictions in DevicePolicyManager.
      *
      * @hide */
     public static final String ADVANCED_PROTECTION_SYSTEM_ENTITY =
             "android.security.advancedprotection";
 
     /**
-     * Feature identifier for disallowing connections to 2G networks.
+     * Feature identifier for disallowing 2G.
      *
-     * @see UserManager#DISALLOW_CELLULAR_2G
      * @hide */
     @SystemApi
-    public static final int FEATURE_ID_DISALLOW_CELLULAR_2G = 0;
+    public static final String FEATURE_ID_DISALLOW_CELLULAR_2G =
+            "android.security.advancedprotection.feature_disallow_2g";
 
     /**
-     * Feature identifier for disallowing installs of apps from unknown sources.
+     * Feature identifier for disallowing install of unknown sources.
      *
-     * @see UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY
      * @hide */
     @SystemApi
-    public static final int FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES = 1;
+    public static final String FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES =
+            "android.security.advancedprotection.feature_disallow_install_unknown_sources";
 
     /**
-     * Feature identifier for disallowing USB connections.
+     * Feature identifier for disallowing USB.
      *
      * @hide */
     @SystemApi
-    public static final int FEATURE_ID_DISALLOW_USB = 2;
+    public static final String FEATURE_ID_DISALLOW_USB =
+            "android.security.advancedprotection.feature_disallow_usb";
 
     /**
-     * Feature identifier for disallowing connections to Wi-Fi Wired Equivalent Privacy (WEP)
-     * networks.
+     * Feature identifier for disallowing WEP.
      *
-     * @see WifiManager#isWepSupported()
      * @hide */
     @SystemApi
-    public static final int FEATURE_ID_DISALLOW_WEP = 3;
+    public static final String FEATURE_ID_DISALLOW_WEP =
+            "android.security.advancedprotection.feature_disallow_wep";
 
     /**
-     * Feature identifier for enabling the Memory Tagging Extension (MTE). MTE is a CPU extension
-     * that allows to protect against certain classes of security problems at a small runtime
-     * performance cost overhead.
+     * Feature identifier for enabling MTE.
      *
-     * @see DevicePolicyManager#setMtePolicy(int)
      * @hide */
     @SystemApi
-    public static final int FEATURE_ID_ENABLE_MTE = 4;
+    public static final String FEATURE_ID_ENABLE_MTE =
+            "android.security.advancedprotection.feature_enable_mte";
 
     /** @hide */
-    @IntDef(prefix = { "FEATURE_ID_" }, value = {
+    @StringDef(prefix = { "FEATURE_ID_" }, value = {
             FEATURE_ID_DISALLOW_CELLULAR_2G,
             FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
             FEATURE_ID_DISALLOW_USB,
@@ -120,7 +116,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface FeatureId {}
 
-    private static final Set<Integer> ALL_FEATURE_IDS = Set.of(
+    private static final Set<String> ALL_FEATURE_IDS = Set.of(
             FEATURE_ID_DISALLOW_CELLULAR_2G,
             FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
             FEATURE_ID_DISALLOW_USB,
@@ -139,6 +135,9 @@
      * Output: Nothing.
      *
      * @hide */
+    @SystemApi
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    @FlaggedApi(android.security.Flags.FLAG_AAPM_API)
     public static final String ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG =
             "android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG";
 
@@ -148,6 +147,7 @@
      *
      * @hide */
     @FeatureId
+    @SystemApi
     public static final String EXTRA_SUPPORT_DIALOG_FEATURE =
             "android.security.advancedprotection.extra.SUPPORT_DIALOG_FEATURE";
 
@@ -157,41 +157,37 @@
      *
      * @hide */
     @SupportDialogType
+    @SystemApi
     public static final String EXTRA_SUPPORT_DIALOG_TYPE =
             "android.security.advancedprotection.extra.SUPPORT_DIALOG_TYPE";
 
     /**
-     * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating an unknown action was blocked by
-     * advanced protection, hence the support dialog should display a default explanation.
-     *
-     * @hide */
-    public static final int SUPPORT_DIALOG_TYPE_UNKNOWN = 0;
-
-    /**
      * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user performed an action that was
      * blocked by advanced protection.
      *
      * @hide */
-    public static final int SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION = 1;
+    @SystemApi
+    public static final String SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION =
+            "android.security.advancedprotection.type_blocked_interaction";
 
     /**
      * Type for {@link #EXTRA_SUPPORT_DIALOG_TYPE} indicating a user pressed on a setting toggle
      * that was disabled by advanced protection.
      *
      * @hide */
-    public static final int SUPPORT_DIALOG_TYPE_DISABLED_SETTING = 2;
+    @SystemApi
+    public static final String SUPPORT_DIALOG_TYPE_DISABLED_SETTING =
+            "android.security.advancedprotection.type_disabled_setting";
 
     /** @hide */
-    @IntDef(prefix = { "SUPPORT_DIALOG_TYPE_" }, value = {
-            SUPPORT_DIALOG_TYPE_UNKNOWN,
+    @StringDef(prefix = { "SUPPORT_DIALOG_TYPE_" }, value = {
             SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION,
             SUPPORT_DIALOG_TYPE_DISABLED_SETTING,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SupportDialogType {}
 
-    private static final Set<Integer> ALL_SUPPORT_DIALOG_TYPES = Set.of(
-            SUPPORT_DIALOG_TYPE_UNKNOWN,
+    private static final Set<String> ALL_SUPPORT_DIALOG_TYPES = Set.of(
             SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION,
             SUPPORT_DIALOG_TYPE_DISABLED_SETTING);
 
@@ -328,13 +324,15 @@
      *                disabled by advanced protection.
      * @hide
      */
-    public static @NonNull Intent createSupportIntent(@FeatureId int featureId,
-            @SupportDialogType int type) {
+    @SystemApi
+    public @NonNull Intent createSupportIntent(@NonNull @FeatureId String featureId,
+            @Nullable @SupportDialogType String type) {
+        Objects.requireNonNull(featureId);
         if (!ALL_FEATURE_IDS.contains(featureId)) {
             throw new IllegalArgumentException(featureId + " is not a valid feature ID. See"
                     + " FEATURE_ID_* APIs.");
         }
-        if (!ALL_SUPPORT_DIALOG_TYPES.contains(type)) {
+        if (type != null && !ALL_SUPPORT_DIALOG_TYPES.contains(type)) {
             throw new IllegalArgumentException(type + " is not a valid type. See"
                     + " SUPPORT_DIALOG_TYPE_* APIs.");
         }
@@ -342,19 +340,21 @@
         Intent intent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG);
         intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
         intent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, featureId);
-        intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type);
+        if (type != null) {
+            intent.putExtra(EXTRA_SUPPORT_DIALOG_TYPE, type);
+        }
         return intent;
     }
 
     /** @hide */
-    public static @NonNull Intent createSupportIntentForPolicyIdentifierOrRestriction(
-            @NonNull String identifier, @SupportDialogType int type) {
+    public @NonNull Intent createSupportIntentForPolicyIdentifierOrRestriction(
+            @NonNull String identifier, @Nullable @SupportDialogType String type) {
         Objects.requireNonNull(identifier);
-        if (!ALL_SUPPORT_DIALOG_TYPES.contains(type)) {
+        if (type != null && !ALL_SUPPORT_DIALOG_TYPES.contains(type)) {
             throw new IllegalArgumentException(type + " is not a valid type. See"
                     + " SUPPORT_DIALOG_TYPE_* APIs.");
         }
-        final int featureId;
+        final String featureId;
         if (DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY.equals(identifier)) {
             featureId = FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;
         } else if (DISALLOW_CELLULAR_2G.equals(identifier)) {
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 4f74198..880622a 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -221,13 +221,13 @@
 
     @Override
     public boolean setControl(@Nullable InsetsSourceControl control, int[] showTypes,
-            int[] hideTypes, int[] cancelTypes) {
+            int[] hideTypes, int[] cancelTypes, int[] transientTypes) {
         if (Flags.refactorInsetsController()) {
-            return super.setControl(control, showTypes, hideTypes, cancelTypes);
+            return super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
         } else {
             ImeTracing.getInstance().triggerClientDump("ImeInsetsSourceConsumer#setControl",
                     mController.getHost().getInputMethodManager(), null /* icProto */);
-            if (!super.setControl(control, showTypes, hideTypes, cancelTypes)) {
+            if (!super.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes)) {
                 return false;
             }
             if (control == null && !mIsRequestedVisibleAwaitingLeash) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index b0813f3..c174fbe 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -959,6 +959,7 @@
         final @InsetsType int[] showTypes = new int[1];
         final @InsetsType int[] hideTypes = new int[1];
         final @InsetsType int[] cancelTypes = new int[1];
+        final @InsetsType int[] transientTypes = new int[1];
         ImeTracker.Token statsToken = null;
 
         // Ensure to update all existing source consumers
@@ -984,7 +985,7 @@
 
             // control may be null, but we still need to update the control to null if it got
             // revoked.
-            consumer.setControl(control, showTypes, hideTypes, cancelTypes);
+            consumer.setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
         }
 
         // Ensure to create source consumers if not available yet.
@@ -992,7 +993,7 @@
             for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
                 final InsetsSourceControl control = mTmpControlArray.valueAt(i);
                 getSourceConsumer(control.getId(), control.getType())
-                        .setControl(control, showTypes, hideTypes, cancelTypes);
+                        .setControl(control, showTypes, hideTypes, cancelTypes, transientTypes);
             }
         }
 
@@ -1020,10 +1021,16 @@
                 handlePendingControlRequest(statsToken);
             } else {
                 if (showTypes[0] != 0) {
-                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
+                    applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
+                            false /* skipsCallbacks */, statsToken);
                 }
                 if (hideTypes[0] != 0) {
-                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
+                    applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
+                            // The animation of hiding transient types shouldn't be detected by the
+                            // app. Otherwise, it might be able to react to the callbacks and cause
+                            // flickering.
+                            (hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
+                            statsToken);
                 }
             }
         } else {
@@ -1033,7 +1040,8 @@
                                 ImeTracker.TYPE_SHOW, ImeTracker.ORIGIN_CLIENT,
                                 SoftInputShowHideReason.CONTROLS_CHANGED,
                                 mHost.isHandlingPointerEvent() /* fromUser */);
-                applyAnimation(showTypes[0], true /* show */, false /* fromIme */, newStatsToken);
+                applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
+                        false /* skipsCallbacks */, newStatsToken);
             }
             if (hideTypes[0] != 0) {
                 final var newStatsToken =
@@ -1041,7 +1049,12 @@
                                 ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
                                 SoftInputShowHideReason.CONTROLS_CHANGED,
                                 mHost.isHandlingPointerEvent() /* fromUser */);
-                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, newStatsToken);
+                applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
+                        // The animation of hiding transient types shouldn't be detected by the app.
+                        // Otherwise, it might be able to react to the callbacks and cause
+                        // flickering.
+                        (hideTypes[0] & ~transientTypes[0]) == 0 /* skipsCallbacks */,
+                        newStatsToken);
             }
         }
 
@@ -1174,7 +1187,8 @@
             // TODO(b/353463205) check if this is needed here
             ImeTracker.forLatency().onShown(statsToken, ActivityThread::currentApplication);
         }
-        applyAnimation(typesReady, true /* show */, fromIme, statsToken);
+        applyAnimation(typesReady, true /* show */, fromIme, false /* skipsCallbacks */,
+                statsToken);
     }
 
     /**
@@ -1287,7 +1301,8 @@
             handlePendingControlRequest(statsToken);
             getImeSourceConsumer().removeSurface();
         }
-        applyAnimation(typesReady, false /* show */, fromIme, statsToken);
+        applyAnimation(typesReady, false /* show */, fromIme, false /* skipsCallbacks */,
+                statsToken);
     }
 
     @Override
@@ -2007,24 +2022,24 @@
 
     @VisibleForTesting
     public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
-            @Nullable ImeTracker.Token statsToken) {
+            boolean skipsCallbacks, @Nullable ImeTracker.Token statsToken) {
         // TODO(b/166736352): We should only skip the animation of specific types, not all types.
-        boolean skipAnim = false;
+        boolean skipsAnim = false;
         if ((types & ime()) != 0) {
             final InsetsSourceControl imeControl = mImeSourceConsumer.getControl();
             // Skip showing animation once that made by system for some reason.
             // (e.g. starting window with IME snapshot)
             if (imeControl != null) {
-                skipAnim = imeControl.getAndClearSkipAnimationOnce() && show
+                skipsAnim = imeControl.getAndClearSkipAnimationOnce() && show
                         && mImeSourceConsumer.hasViewFocusWhenWindowFocusGain();
             }
         }
-        applyAnimation(types, show, fromIme, skipAnim, statsToken);
+        applyAnimation(types, show, fromIme, skipsAnim, skipsCallbacks, statsToken);
     }
 
     @VisibleForTesting
     public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme,
-            boolean skipAnim, @Nullable ImeTracker.Token statsToken) {
+            boolean skipsAnim, boolean skipsCallbacks, @Nullable ImeTracker.Token statsToken) {
         if (types == 0) {
             // nothing to animate.
             if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate. Stopping here");
@@ -2040,7 +2055,7 @@
         boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
         final InternalAnimationControlListener listener = new InternalAnimationControlListener(
                 show, hasAnimationCallbacks, types, mHost.getSystemBarsBehavior(),
-                skipAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
+                skipsAnim || mAnimationsDisabled, mHost.dipToPx(FLOATING_IME_BOTTOM_INSET_DP),
                 mLoggingListener, mJankContext);
 
         // We are about to playing the default animation (show/hide). Passing a null frame indicates
@@ -2050,7 +2065,7 @@
                 listener /* insetsAnimationSpec */,
                 show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
                 show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
-                !hasAnimationCallbacks /* useInsetsAnimationThread */, statsToken,
+                !hasAnimationCallbacks || skipsCallbacks /* useInsetsAnimationThread */, statsToken,
                 false /* fromPredictiveBack */);
     }
 
@@ -2173,12 +2188,12 @@
                         new InsetsSourceControl(ID_IME_CAPTION_BAR, captionBar(),
                                 null /* leash */, false /* initialVisible */,
                                 new Point(), Insets.NONE),
-                        new int[1], new int[1], new int[1]);
+                        new int[1], new int[1], new int[1], new int[1]);
             } else {
                 mState.removeSource(ID_IME_CAPTION_BAR);
                 InsetsSourceConsumer sourceConsumer = mSourceConsumers.get(ID_IME_CAPTION_BAR);
                 if (sourceConsumer != null) {
-                    sourceConsumer.setControl(null, new int[1], new int[1], new int[1]);
+                    sourceConsumer.setControl(null, new int[1], new int[1], new int[1], new int[1]);
                 }
             }
             mHost.notifyInsetsChanged();
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 17f33c1..e8e6621 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -130,7 +130,10 @@
      * @return Whether the control has changed from the server
      */
     public boolean setControl(@Nullable InsetsSourceControl control,
-            @InsetsType int[] showTypes, @InsetsType int[] hideTypes, int[] cancelTypes) {
+            @InsetsType int[] showTypes,
+            @InsetsType int[] hideTypes,
+            @InsetsType int[] cancelTypes,
+            @InsetsType int[] transientTypes) {
         if (Objects.equals(mSourceControl, control)) {
             if (mSourceControl != null && mSourceControl != control) {
                 mSourceControl.release(SurfaceControl::release);
@@ -185,6 +188,9 @@
                 } else {
                     hideTypes[0] |= mType;
                 }
+                if (lastControl != null && lastControl.isFake()) {
+                    transientTypes[0] |= mType;
+                }
             } else {
                 // We are gaining control, but don't need to run an animation.
                 // However make sure that the leash visibility is still up to date.
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index acbd95bf..7f2f0e8 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -142,6 +142,10 @@
         return mInsetsHint;
     }
 
+    public boolean isFake() {
+        return mLeash == null && Insets.NONE.equals(mInsetsHint);
+    }
+
     public void setSkipAnimationOnce(boolean skipAnimation) {
         mSkipAnimationOnce = skipAnimation;
     }
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index d527007..206e47f 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -16,6 +16,8 @@
 
 package android.view.autofill;
 
+import static android.service.autofill.Flags.improveFillDialogAconfig;
+
 import android.annotation.SuppressLint;
 import android.annotation.TestApi;
 import android.provider.DeviceConfig;
@@ -662,7 +664,7 @@
     public static boolean isImproveFillDialogEnabled() {
         // TODO(b/266379948): Add condition for checking whether device has PCC first
 
-        return DeviceConfig.getBoolean(
+        return improveFillDialogAconfig() && DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_AUTOFILL,
                 DEVICE_CONFIG_IMPROVE_FILL_DIALOG_ENABLED,
                 DEFAULT_IMPROVE_FILL_DIALOG_ENABLED);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index eaa8f60..e904345f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -992,23 +992,7 @@
         private void setCurrentRootViewLocked(ViewRootImpl rootView) {
             final boolean wasEmpty = mCurRootView == null;
             if (Flags.refactorInsetsController() && !wasEmpty && mCurRootView != rootView) {
-                final int softInputMode = mCurRootView.mWindowAttributes.softInputMode;
-                final int state =
-                        softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
-                if (state == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) {
-                    // when losing input focus (e.g., by going to another window), we reset the
-                    // requestedVisibleTypes of WindowInsetsController by hiding the IME
-                    final var statsToken = ImeTracker.forLogging().onStart(
-                            ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
-                            SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS,
-                            false /* fromUser */);
-                    if (DEBUG) {
-                        Log.d(TAG, "setCurrentRootViewLocked, hiding IME because "
-                                + "of STATE_ALWAYS_HIDDEN");
-                    }
-                    mCurRootView.getInsetsController().hide(WindowInsets.Type.ime(),
-                            false /* fromIme */, statsToken);
-                }
+                onImeFocusLost(mCurRootView);
             }
 
             mImeDispatcher.switchRootView(mCurRootView, rootView);
@@ -1019,6 +1003,26 @@
         }
     }
 
+    private void onImeFocusLost(@NonNull ViewRootImpl previousRootView) {
+        final int softInputMode = previousRootView.mWindowAttributes.softInputMode;
+        final int state =
+                softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE;
+        if (state == WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) {
+            // when losing input focus (e.g., by going to another window), we reset the
+            // requestedVisibleTypes of WindowInsetsController by hiding the IME
+            final var statsToken = ImeTracker.forLogging().onStart(
+                    ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_CLIENT,
+                    SoftInputShowHideReason.HIDE_WINDOW_LOST_FOCUS,
+                    false /* fromUser */);
+            if (DEBUG) {
+                Log.d(TAG, "onImeFocusLost, hiding IME because "
+                        + "of STATE_ALWAYS_HIDDEN");
+            }
+            previousRootView.getInsetsController().hide(WindowInsets.Type.ime(),
+                    false /* fromIme */, statsToken);
+        }
+    }
+
     /** @hide */
     public DelegateImpl getDelegate() {
         return mDelegate;
diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig
index d5ba32c..4b5adfc 100644
--- a/core/java/android/window/flags/responsible_apis.aconfig
+++ b/core/java/android/window/flags/responsible_apis.aconfig
@@ -75,4 +75,9 @@
     bug: "362575865"
 }
 
-
+flag {
+    name: "bal_strict_mode_grace_period"
+    namespace: "responsible_apis"
+    description: "Strict mode violation triggered by grace period usage"
+    bug: "384807495"
+}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index 751cfde..b7537ed 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -149,8 +149,10 @@
         setContentDescription(mContext.getText(contentDescriptionId));
         mIconView.setImageDrawable(getContext().getDrawable(drawableId));
 
-        // changing the expanded state can affect the number display
-        updateNumber();
+        if (!notificationsRedesignTemplates()) {
+            // changing the expanded state can affect the number display
+            updateNumber();
+        }
     }
 
     private void updateNumber() {
@@ -189,6 +191,9 @@
     }
 
     private boolean shouldShowNumber() {
+        if (notificationsRedesignTemplates()) {
+            return mNumber > 1;
+        }
         return !mExpanded && mNumber > 1;
     }
 
@@ -230,7 +235,7 @@
 
     /**
      * Sets the number shown inside the expand button.
-     * This only appears when the expand button is collapsed, and when greater than 1.
+     * This only appears when {@link this#shouldShowNumber()} is true.
      */
     @RemotableViewMethod
     public void setNumber(int number) {
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index dd9bfa5..0d99200 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -228,6 +228,7 @@
         optional SettingProto reverse_vertical_scrolling = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto swap_primary_button = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto scrolling_acceleration = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto pointer_acceleration_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
 
     optional Mouse mouse = 38;
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 3ef3dfd..d7c4212 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -73,6 +73,7 @@
         "frameworks-core-util-lib",
         "mockwebserver",
         "guava",
+        "guava-android-testlib",
         "android.app.usage.flags-aconfig-java",
         "android.view.accessibility.flags-aconfig-java",
         "androidx.core_core",
diff --git a/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java b/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java
index 931d646..f1925bb 100644
--- a/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java
+++ b/core/tests/coretests/src/android/app/BackgroundStartPrivilegesTest.java
@@ -29,6 +29,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.google.common.testing.EqualsTester;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -122,12 +124,16 @@
 
     @Test
     public void backgroundStartPrivilege_equals_works() {
-        assertThat(NONE).isEqualTo(NONE);
-        assertThat(ALLOW_BAL).isEqualTo(ALLOW_BAL);
-        assertThat(ALLOW_FGS).isEqualTo(ALLOW_FGS);
-        assertThat(BSP_ALLOW_A).isEqualTo(BSP_ALLOW_A);
-        assertThat(NONE).isNotEqualTo(ALLOW_BAL);
-        assertThat(ALLOW_FGS).isNotEqualTo(ALLOW_BAL);
-        assertThat(BSP_ALLOW_A).isNotEqualTo(BSP_ALLOW_B);
+        Binder token = new Binder();
+        Binder anotherToken = new Binder();
+        new EqualsTester()
+                .addEqualityGroup(NONE)
+                .addEqualityGroup(ALLOW_BAL)
+                .addEqualityGroup(ALLOW_FGS)
+                .addEqualityGroup(BackgroundStartPrivileges.allowBackgroundActivityStarts(token),
+                        BackgroundStartPrivileges.allowBackgroundActivityStarts(token))
+                .addEqualityGroup(
+                        BackgroundStartPrivileges.allowBackgroundActivityStarts(anotherToken))
+                .testEquals();
     }
 }
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
index b7d2562..008db5e 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
+++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt
@@ -643,13 +643,65 @@
         verifyDisplay(
                 root.children[0], id = 1, width = 30f, height = 30f, POSITION_RIGHT, offset = 10f,
                 noOfChildren = 1)
-        // In the case of corner adjacency, we prefer a left/right attachment.
         verifyDisplay(
                 root.children[0].children[0], id = 2, width = 29.5f, height = 30f, POSITION_BOTTOM,
                 offset = 30f, noOfChildren = 0)
     }
 
     @Test
+    fun rearrange_preferLessShiftInOverlapDimension() {
+        val root = rearrangeRects(
+            // '*' represents overlap
+            // Clamping requires moving display 2 and 1 slightly to avoid overlap with 0. We should
+            // shift the minimal amount to avoid overlap - e.g. display 2 shifts left (10 pixels)
+            // rather than up (20 pixels).
+            // 222
+            // 22*00
+            // 22*00
+            //   0**1
+            //    111
+            //    111
+            RectF(20f, 10f, 50f, 40f),
+            RectF(30f, 30f, 60f, 60f),
+            RectF(0f, 0f, 30f, 30f),
+        )
+
+        verifyDisplay(root, id = 0, width = 30f, height = 30f, noOfChildren = 2)
+        verifyDisplay(
+                root.children[0], id = 1, width = 30f, height = 30f, POSITION_BOTTOM, offset = 10f,
+                noOfChildren = 0)
+        verifyDisplay(
+                root.children[1], id = 2, width = 30f, height = 30f, POSITION_LEFT, offset = -10f,
+                noOfChildren = 0)
+    }
+
+    @Test
+    fun rearrange_doNotAttachCornerForShortOverlapOnLongEdgeBottom() {
+        val root = rearrangeRects(
+            RectF(0f, 0f, 1920f, 1080f),
+            RectF(1850f, 1070f, 3770f, 2150f),
+        )
+
+        verifyDisplay(root, id = 0, width = 1920f, height = 1080f, noOfChildren = 1)
+        verifyDisplay(
+                root.children[0], id = 1, width = 1920f, height = 1080f, POSITION_BOTTOM,
+                offset = 1850f, noOfChildren = 0)
+    }
+
+    @Test
+    fun rearrange_doNotAttachCornerForShortOverlapOnLongEdgeLeft() {
+        val root = rearrangeRects(
+            RectF(0f, 0f, 1080f, 1920f),
+            RectF(-1070f, -1880f, 10f, 40f),
+        )
+
+        verifyDisplay(root, id = 0, width = 1080f, height = 1920f, noOfChildren = 1)
+        verifyDisplay(
+                root.children[0], id = 1, width = 1080f, height = 1920f, POSITION_LEFT,
+                offset = -1880f, noOfChildren = 0)
+    }
+
+    @Test
     fun copy() {
         val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f,
             /* height= */ 600f, /* position= */ 0, /* offset= */ 0f)
diff --git a/core/tests/coretests/src/android/security/advancedprotection/AdvancedProtectionManagerTest.java b/core/tests/coretests/src/android/security/advancedprotection/AdvancedProtectionManagerTest.java
deleted file mode 100644
index 45864b0..0000000
--- a/core/tests/coretests/src/android/security/advancedprotection/AdvancedProtectionManagerTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.advancedprotection;
-
-import static android.security.advancedprotection.AdvancedProtectionManager.ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG;
-import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_FEATURE;
-import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_TYPE;
-import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G;
-import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION;
-import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING;
-import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_UNKNOWN;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThrows;
-
-import android.content.Intent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public class AdvancedProtectionManagerTest {
-    private static final int FEATURE_ID_INVALID = -1;
-    private static final int SUPPORT_DIALOG_TYPE_INVALID = -1;
-
-    @Test
-    public void testCreateSupportIntent_validFeature_validTypeUnknown_createsIntent() {
-        Intent intent = AdvancedProtectionManager.createSupportIntent(
-                FEATURE_ID_DISALLOW_CELLULAR_2G, SUPPORT_DIALOG_TYPE_UNKNOWN);
-
-        assertEquals(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG, intent.getAction());
-        assertEquals(FEATURE_ID_DISALLOW_CELLULAR_2G, intent.getIntExtra(
-                EXTRA_SUPPORT_DIALOG_FEATURE, FEATURE_ID_INVALID));
-        assertEquals(SUPPORT_DIALOG_TYPE_UNKNOWN, intent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE,
-                SUPPORT_DIALOG_TYPE_INVALID));
-    }
-
-    @Test
-    public void testCreateSupportIntent_validFeature_validTypeBlockedInteraction_createsIntent() {
-        Intent intent = AdvancedProtectionManager.createSupportIntent(
-                FEATURE_ID_DISALLOW_CELLULAR_2G, SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION);
-
-        assertEquals(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG, intent.getAction());
-        assertEquals(FEATURE_ID_DISALLOW_CELLULAR_2G, intent.getIntExtra(
-                EXTRA_SUPPORT_DIALOG_FEATURE, FEATURE_ID_INVALID));
-        assertEquals(SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION, intent.getIntExtra(
-                EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_INVALID));
-    }
-
-    @Test
-    public void testCreateSupportIntent_validFeature_validTypeDisabledSetting_createsIntent() {
-        Intent intent = AdvancedProtectionManager.createSupportIntent(
-                FEATURE_ID_DISALLOW_CELLULAR_2G, SUPPORT_DIALOG_TYPE_DISABLED_SETTING);
-
-        assertEquals(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG, intent.getAction());
-        assertEquals(FEATURE_ID_DISALLOW_CELLULAR_2G, intent.getIntExtra(
-                EXTRA_SUPPORT_DIALOG_FEATURE, FEATURE_ID_INVALID));
-        assertEquals(SUPPORT_DIALOG_TYPE_DISABLED_SETTING, intent.getIntExtra(
-                EXTRA_SUPPORT_DIALOG_TYPE, SUPPORT_DIALOG_TYPE_INVALID));
-    }
-
-    @Test
-    public void testCreateSupportIntent_validFeature_invalidType_throwsIllegalArgument() {
-        assertThrows(IllegalArgumentException.class, () ->
-                AdvancedProtectionManager.createSupportIntent(FEATURE_ID_DISALLOW_CELLULAR_2G,
-                        SUPPORT_DIALOG_TYPE_INVALID));
-    }
-
-    @Test
-    public void testCreateSupportIntent_invalidFeature_validType_throwsIllegalArgument() {
-        assertThrows(IllegalArgumentException.class, () ->
-                AdvancedProtectionManager.createSupportIntent(FEATURE_ID_INVALID,
-                        SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION));
-    }
-
-    @Test
-    public void testCreateSupportIntent_invalidFeature_invalidType_throwsIllegalArgument() {
-        assertThrows(IllegalArgumentException.class, () ->
-                AdvancedProtectionManager.createSupportIntent(FEATURE_ID_INVALID,
-                        SUPPORT_DIALOG_TYPE_INVALID));
-    }
-}
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 248db65..4a54f6b 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -133,7 +133,7 @@
             // Called once through the show flow.
             verify(mController).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
-                    eq(statsToken));
+                    eq(false) /* skipsCallbacks */, eq(statsToken));
 
             // set control and verify visibility is applied.
             InsetsSourceControl control = new InsetsSourceControl(ID_IME,
@@ -142,10 +142,10 @@
             // IME show animation should be triggered when control becomes available.
             verify(mController).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
-                    and(not(eq(statsToken)), notNull()));
+                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
             verify(mController, never()).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
-                    and(not(eq(statsToken)), notNull()));
+                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
         });
     }
 
@@ -163,7 +163,7 @@
             // Called once through the show flow.
             verify(mController).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
-                    eq(statsToken));
+                    eq(false) /* skipsCallbacks */, eq(statsToken));
             // Clear previous invocations to verify this is never called with control without leash.
             clearInvocations(mController);
 
@@ -175,10 +175,10 @@
             // as we have no leash.
             verify(mController, never()).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
-                    and(not(eq(statsToken)), notNull()));
+                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
             verify(mController, never()).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
-                    and(not(eq(statsToken)), notNull()));
+                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
 
             // set control with leash and verify visibility is applied.
             InsetsSourceControl controlWithLeash = new InsetsSourceControl(ID_IME,
@@ -187,10 +187,10 @@
             // IME show animation should be triggered when control with leash becomes available.
             verify(mController).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(false) /* fromIme */,
-                    and(not(eq(statsToken)), notNull()));
+                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
             verify(mController, never()).applyAnimation(
                     eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(false) /* fromIme */,
-                    and(not(eq(statsToken)), notNull()));
+                    eq(false) /* skipsCallbacks */, and(not(eq(statsToken)), notNull()));
         });
     }
 
@@ -223,7 +223,8 @@
                 // Called once through the show flow.
                 verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                         eq(true) /* show */, eq(true) /* fromIme */,
-                        eq(false) /* skipAnim */, eq(statsToken));
+                        eq(false) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+                        eq(statsToken));
             }
 
             // set control and verify visibility is applied.
@@ -241,7 +242,8 @@
                 // so the statsToken won't match.
                 verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                         eq(true) /* show */, eq(false) /* fromIme */,
-                        eq(expectSkipAnim) /* skipAnim */, and(not(eq(statsToken)), notNull()));
+                        eq(expectSkipAnim) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+                        and(not(eq(statsToken)), notNull()));
             }
 
             // If previously hasViewFocus is false, verify when requesting the IME visible next
@@ -252,14 +254,16 @@
                 // Called once through the show flow.
                 verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                         eq(true) /* show */, eq(true) /* fromIme */,
-                        eq(false) /* skipAnim */, eq(statsTokenNext));
+                        eq(false) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+                        eq(statsTokenNext));
                 mController.onControlsChanged(new InsetsSourceControl[]{ control });
                 // Verify IME show animation should be triggered when control becomes available and
                 // the animation will be skipped by getAndClearSkipAnimationOnce invoked.
                 verify(control).getAndClearSkipAnimationOnce();
                 verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
                         eq(true) /* show */, eq(false) /* fromIme */,
-                        eq(true) /* skipAnim */, and(not(eq(statsToken)), notNull()));
+                        eq(true) /* skipsAnim */, eq(false) /* skipsCallbacks */,
+                        and(not(eq(statsToken)), notNull()));
             }
         });
     }
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index d7f6a29..905d897 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -100,14 +100,14 @@
         topConsumer.setControl(
                 new InsetsSourceControl(ID_STATUS_BAR, WindowInsets.Type.statusBars(),
                         mStatusLeash, true, new Point(0, 0), Insets.of(0, 100, 0, 0)),
-                new int[1], new int[1], new int[1]);
+                new int[1], new int[1], new int[1], new int[1]);
 
         InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ID_NAVIGATION_BAR,
                 WindowInsets.Type.navigationBars(), mInsetsState, mMockController);
         navConsumer.setControl(
                 new InsetsSourceControl(ID_NAVIGATION_BAR, WindowInsets.Type.navigationBars(),
                         mNavLeash, true, new Point(400, 0), Insets.of(0, 0, 100, 0)),
-                new int[1], new int[1], new int[1]);
+                new int[1], new int[1], new int[1], new int[1]);
         mMockController.setRequestedVisibleTypes(0, WindowInsets.Type.navigationBars());
         navConsumer.applyLocalVisibilityOverride();
 
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 3a8f7ee..45d66e8 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -117,7 +117,7 @@
         mConsumer.setControl(
                 new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
                         true /* initialVisible */, new Point(), Insets.NONE),
-                new int[1], new int[1], new int[1]);
+                new int[1], new int[1], new int[1], new int[1]);
     }
 
     @Test
@@ -129,7 +129,7 @@
             newControl.setInsetsHint(Insets.of(0, 0, 0, 100));
 
             int[] cancelTypes = {0};
-            mConsumer.setControl(newControl, new int[1], new int[1], cancelTypes);
+            mConsumer.setControl(newControl, new int[1], new int[1], cancelTypes, new int[1]);
 
             assertEquals(statusBars(), cancelTypes[0]);
         });
@@ -196,7 +196,7 @@
     @Test
     public void testRestore() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
-            mConsumer.setControl(null, new int[1], new int[1], new int[1]);
+            mConsumer.setControl(null, new int[1], new int[1], new int[1], new int[1]);
             mSurfaceParamsApplied = false;
             mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
             assertFalse(mSurfaceParamsApplied);
@@ -204,7 +204,7 @@
             mConsumer.setControl(
                     new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
                             true /* initialVisible */, new Point(), Insets.NONE),
-                    new int[1], hideTypes, new int[1]);
+                    new int[1], hideTypes, new int[1], new int[1]);
             assertEquals(statusBars(), hideTypes[0]);
             assertFalse(mRemoveSurfaceCalled);
         });
@@ -214,7 +214,7 @@
     public void testRestore_noAnimation() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
             mController.setRequestedVisibleTypes(0 /* visibleTypes */, statusBars());
-            mConsumer.setControl(null, new int[1], new int[1], new int[1]);
+            mConsumer.setControl(null, new int[1], new int[1], new int[1], new int[1]);
             mLeash = new SurfaceControl.Builder(mSession)
                     .setName("testSurface")
                     .build();
@@ -223,7 +223,7 @@
             mConsumer.setControl(
                     new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash,
                             false /* initialVisible */, new Point(), Insets.NONE),
-                    new int[1], hideTypes, new int[1]);
+                    new int[1], hideTypes, new int[1], new int[1]);
             assertTrue(mRemoveSurfaceCalled);
             assertEquals(0, hideTypes[0]);
         });
@@ -252,7 +252,7 @@
             // Initial IME insets source control with its leash.
             imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
                     false /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1],
-                    new int[1]);
+                    new int[1], new int[1]);
             mSurfaceParamsApplied = false;
 
             // Verify when the app requests controlling show IME animation, the IME leash
@@ -262,7 +262,7 @@
             assertEquals(ANIMATION_TYPE_USER, insetsController.getAnimationType(ime()));
             imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,
                     true /* initialVisible */, new Point(), Insets.NONE), new int[1], new int[1],
-                    new int[1]);
+                    new int[1], new int[1]);
             assertFalse(mSurfaceParamsApplied);
         });
     }
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 7e87462..166b388 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -276,16 +276,19 @@
     /**
      * Sets preferred default picture profile.
      *
-     * @param id the ID of the default profile. {@code null} to unset the default profile.
+     * @param pictureProfileId the ID of the default profile. {@code null} to unset the default
+     *                         profile.
      * @return {@code true} if it's set successfully; {@code false} otherwise.
      *
+     * @see PictureProfile#getProfileId()
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
-    public boolean setDefaultPictureProfile(@Nullable String id) {
+    public boolean setDefaultPictureProfile(@Nullable String pictureProfileId) {
         try {
-            return mService.setDefaultPictureProfile(id, mUserHandle);
+            return mService.setDefaultPictureProfile(pictureProfileId, mUserHandle);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -467,16 +470,19 @@
     /**
      * Sets preferred default sound profile.
      *
-     * @param id the ID of the default profile. {@code null} to unset the default profile.
+     * @param soundProfileId the ID of the default profile. {@code null} to unset the default
+     *                       profile.
      * @return {@code true} if it's set successfully; {@code false} otherwise.
      *
+     * @see SoundProfile#getProfileId()
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
-    public boolean setDefaultSoundProfile(@Nullable String id) {
+    public boolean setDefaultSoundProfile(@Nullable String soundProfileId) {
         try {
-            return mService.setDefaultSoundProfile(id, mUserHandle);
+            return mService.setDefaultSoundProfile(soundProfileId, mUserHandle);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index b4afb7d..7374f80 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -444,12 +444,23 @@
     }
 
     /**
-     * @return {@code true} if {@code cachedBluetoothDevice} is hearing aid device
+     * @return {@code true} if {@code cachedBluetoothDevice} is hearing aid device.
+     * @deprecated use {@link #isHearingDevice() }
+     * // TODO: b/385679160 - Target to deprecate it and replace  with #isHearingDevice()
      */
+    @Deprecated
     public boolean isHearingAidDevice() {
         return mHearingAidInfo != null;
     }
 
+    /**
+     * @return {@code true} if {@code cachedBluetoothDevice} support any of hearing device profile.
+     */
+    public boolean isHearingDevice() {
+        return getProfiles().stream().anyMatch(
+                p -> (p instanceof HearingAidProfile || p instanceof HapClientProfile));
+    }
+
     public int getDeviceSide() {
         return mHearingAidInfo != null
                 ? mHearingAidInfo.getSide() : HearingAidInfo.DeviceSide.SIDE_INVALID;
@@ -910,12 +921,33 @@
         }
     }
 
+    /**
+     * Checks if the device is connected to the specified Bluetooth profile.
+     *
+     * @param profile The Bluetooth profile to check.
+     * @return {@code true} if the device is connected to the profile.
+     */
     public boolean isConnectedProfile(LocalBluetoothProfile profile) {
         int status = getProfileConnectionState(profile);
         return status == BluetoothProfile.STATE_CONNECTED;
 
     }
 
+    /**
+     * Checks if the device is connected to the Bluetooth profile with the given ID.
+     *
+     * @param profileId The ID of the Bluetooth profile to check.
+     * @return {@code true} if the device is connected to the profile.
+     */
+    public boolean isConnectedProfile(int profileId) {
+        for (LocalBluetoothProfile profile : getProfiles()) {
+            if (profile.getProfileId() == profileId) {
+                return isConnectedProfile(profile);
+            }
+        }
+        return false;
+    }
+
     public boolean isBusy() {
         synchronized (mProfileLock) {
             for (LocalBluetoothProfile profile : mProfiles) {
@@ -1891,13 +1923,6 @@
     }
 
     /**
-     * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio hearing aid device
-     */
-    public boolean isConnectedLeAudioHearingAidDevice() {
-        return isConnectedHapClientDevice() && isConnectedLeAudioDevice();
-    }
-
-    /**
      * @return {@code true} if {@code cachedBluetoothDevice} is hearing aid device
      *
      * The device may be an ASHA hearing aid that supports {@link HearingAidProfile} or a LeAudio
@@ -1908,6 +1933,13 @@
     }
 
     /**
+     * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio hearing aid device
+     */
+    public boolean isConnectedLeAudioHearingAidDevice() {
+        return isConnectedHapClientDevice() && isConnectedLeAudioDevice();
+    }
+
+    /**
      * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio device
      */
     public boolean isConnectedLeAudioDevice() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index b754706..313013c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -24,7 +24,10 @@
 import android.content.Context;
 import android.util.Log;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.flags.Flags;
 
 import java.sql.Timestamp;
 import java.util.ArrayList;
@@ -46,7 +49,7 @@
     private final LocalBluetoothManager mBtManager;
 
     @VisibleForTesting
-    final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
+    final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<>();
     @VisibleForTesting
     HearingAidDeviceManager mHearingAidDeviceManager;
     @VisibleForTesting
@@ -192,6 +195,20 @@
     }
 
     /**
+     * Notifies the connection status if device is hearing device.
+     *
+     * @param device The {@link CachedBluetoothDevice} need to be hearing device
+     */
+    public synchronized void notifyHearingDevicesConnectionStatusChangedIfNeeded(
+            @NonNull CachedBluetoothDevice device) {
+        if (!device.isHearingDevice()) {
+            return;
+        }
+
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+    }
+
+    /**
      * Search for existing sub device {@link CachedBluetoothDevice}.
      *
      * @param device the address of the Bluetooth device
@@ -388,8 +405,14 @@
 
     /** Handles when the device been set as active/inactive. */
     public synchronized void onActiveDeviceChanged(CachedBluetoothDevice cachedBluetoothDevice) {
-        if (cachedBluetoothDevice.isHearingAidDevice()) {
+        if (cachedBluetoothDevice == null) {
+            return;
+        }
+        if (cachedBluetoothDevice.isHearingDevice()) {
             mHearingAidDeviceManager.onActiveDeviceChanged(cachedBluetoothDevice);
+            if (Flags.hearingDeviceSetConnectionStatusReport()) {
+                mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+            }
         }
     }
 
@@ -421,6 +444,14 @@
             mainDevice.unpair();
             mainDevice.setSubDevice(null);
         }
+
+        // TODO: b/386121967 - Should change to use isHearingDevice but mProfile get clear here.
+        //  Need to consider where to put this logic when using isHearingDevice()
+        if (device.isHearingAidDevice()) {
+            if (Flags.hearingDeviceSetConnectionStatusReport()) {
+                mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+            }
+        }
     }
 
     /**
@@ -579,6 +610,11 @@
         return mOngoingSetMemberPair != null && mOngoingSetMemberPair.equals(device);
     }
 
+    @NonNull
+    public HearingAidDeviceManager getHearingAidDeviceManager() {
+        return mHearingAidDeviceManager;
+    }
+
     private void log(String msg) {
         if (DEBUG) {
             Log.d(TAG, msg);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index ad34e83..b2c2794 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -15,7 +15,11 @@
  */
 package com.android.settingslib.bluetooth;
 
+import static android.bluetooth.BluetoothDevice.BOND_BONDED;
+
+import android.annotation.CallbackExecutor;
 import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
@@ -30,15 +34,25 @@
 import android.util.FeatureFlagUtils;
 import android.util.Log;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.collection.ArraySet;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants.RoutingValue;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
 
 /**
- * HearingAidDeviceManager manages the set of remote HearingAid(ASHA) Bluetooth devices.
+ * HearingAidDeviceManager manages the set of remote bluetooth hearing devices.
  */
 public class HearingAidDeviceManager {
     private static final String TAG = "HearingAidDeviceManager";
@@ -49,6 +63,12 @@
     private final LocalBluetoothManager mBtManager;
     private final List<CachedBluetoothDevice> mCachedDevices;
     private final HearingAidAudioRoutingHelper mRoutingHelper;
+    private static final Map<ConnectionStatusListener, Executor>
+            mConnectionStatusListeners = new ConcurrentHashMap<>();
+    @ConnectionStatus
+    private int mDevicesConnectionStatus = ConnectionStatus.NO_DEVICE_BONDED;
+    private boolean mInitialDevicesConnectionStatusUpdate = false;
+
     HearingAidDeviceManager(Context context, LocalBluetoothManager localBtManager,
             List<CachedBluetoothDevice> CachedDevices) {
         mContext = context;
@@ -68,6 +88,191 @@
         mRoutingHelper = routingHelper;
     }
 
+    /**
+     * Defines the connection status for hearing devices.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            ConnectionStatus.NO_DEVICE_BONDED,
+            ConnectionStatus.DISCONNECTED,
+            ConnectionStatus.CONNECTED,
+            ConnectionStatus.CONNECTING_OR_DISCONNECTING,
+            ConnectionStatus.ACTIVE
+    })
+    public @interface ConnectionStatus {
+        int NO_DEVICE_BONDED = -1;
+        int DISCONNECTED = 0;
+        int CONNECTED = 1;
+        int CONNECTING_OR_DISCONNECTING = 2;
+        int ACTIVE = 3;
+    }
+    /**
+     * Interface for connection status listener.
+     */
+    public interface ConnectionStatusListener {
+        /**
+         * Callback when hearing devices connection status change.
+         *
+         * <p>devices here means singular device or binaural device.
+         * E.g. One of hearing device is in CONNECTED status and another is in DISCONNECTED,
+         * it will callback CONNECTED status.
+         *
+         * @param status Updated {@link ConnectionStatus}
+         */
+        void onDevicesConnectionStatusChanged(@ConnectionStatus int status);
+    }
+
+    /**
+     * Registers a listener to be notified of connection status changes.
+     *
+     * @param listener The listener to register.
+     * @param executor The executor on which the listener's callback will be run.
+     */
+    public void registerConnectionStatusListener(
+            @NonNull ConnectionStatusListener listener,
+            @NonNull @CallbackExecutor Executor executor) {
+        mConnectionStatusListeners.put(listener, executor);
+    }
+
+    /**
+     * Unregisters a listener previously registered with
+     * {@link #registerConnectionStatusListener(ConnectionStatusListener, Executor)}.
+     *
+     * @param listener The listener to unregister.
+     */
+    public void unregisterConnectionStatusListener(
+            @NonNull ConnectionStatusListener listener) {
+        mConnectionStatusListeners.remove(listener);
+    }
+
+    private void notifyDevicesConnectionStatusChanged(int status) {
+        mConnectionStatusListeners.forEach((listener, executor) ->
+                executor.execute(() -> listener.onDevicesConnectionStatusChanged(status)));
+    }
+
+    /**
+     * Updates the connection status of the hearing devices based on the currently bonded
+     * hearing aid devices.
+     */
+    synchronized void notifyDevicesConnectionStatusChanged() {
+        final int prevVal = mDevicesConnectionStatus;
+        updateDevicesConnectionStatus();
+        if (mDevicesConnectionStatus != prevVal) {
+            notifyDevicesConnectionStatusChanged(mDevicesConnectionStatus);
+        }
+    }
+
+    private void updateDevicesConnectionStatus() {
+        mInitialDevicesConnectionStatusUpdate = true;
+        // Add all hearing devices including sub and member into a set.
+        Set<CachedBluetoothDevice> allHearingDevices = mCachedDevices.stream()
+                .filter(d -> d.getBondState() == BluetoothDevice.BOND_BONDED
+                        && d.isHearingDevice())
+                .flatMap(d -> getAssociatedCachedDevice(d).stream())
+                .collect(Collectors.toSet());
+
+        // Status sequence matters here. If one of the hearing devices is in previous
+        // ConnectionStatus, we will treat whole hearing devices is in this status.
+        // E.g. One of hearing device is in CONNECTED status and another is in DISCONNECTED
+        // status, the hearing devices connection status will notify CONNECTED status.
+        if (isConnectingOrDisconnectingConnectionStatus(allHearingDevices)) {
+            mDevicesConnectionStatus = ConnectionStatus.CONNECTING_OR_DISCONNECTING;
+        } else if (isActiveConnectionStatus(allHearingDevices)) {
+            mDevicesConnectionStatus = ConnectionStatus.ACTIVE;
+        } else if (isConnectedStatus(allHearingDevices)) {
+            mDevicesConnectionStatus = ConnectionStatus.CONNECTED;
+        } else if (isDisconnectedStatus(allHearingDevices)) {
+            mDevicesConnectionStatus = ConnectionStatus.DISCONNECTED;
+        } else {
+            mDevicesConnectionStatus = ConnectionStatus.NO_DEVICE_BONDED;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "updateDevicesConnectionStatus: " + mDevicesConnectionStatus);
+        }
+    }
+
+    /**
+     * @return all the related CachedBluetoothDevices for this device.
+     */
+    @NonNull
+    public Set<CachedBluetoothDevice> getAssociatedCachedDevice(
+            @NonNull CachedBluetoothDevice device) {
+        ArraySet<CachedBluetoothDevice> cachedDeviceSet = new ArraySet<>();
+        cachedDeviceSet.add(device);
+        // Associated device should be added into memberDevice if it support CSIP profile.
+        Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+        if (!memberDevices.isEmpty()) {
+            cachedDeviceSet.addAll(memberDevices);
+            return cachedDeviceSet;
+        }
+        // If not support CSIP profile, it should be ASHA hearing device and added into subDevice.
+        CachedBluetoothDevice subDevice = device.getSubDevice();
+        if (subDevice != null) {
+            cachedDeviceSet.add(subDevice);
+            return cachedDeviceSet;
+        }
+
+        return cachedDeviceSet;
+    }
+
+    private boolean isConnectingOrDisconnectingConnectionStatus(
+            Set<CachedBluetoothDevice> devices) {
+        HearingAidProfile hearingAidProfile = mBtManager.getProfileManager().getHearingAidProfile();
+        HapClientProfile hapClientProfile = mBtManager.getProfileManager().getHapClientProfile();
+
+        for (CachedBluetoothDevice device : devices) {
+            if (hearingAidProfile != null) {
+                int status = device.getProfileConnectionState(hearingAidProfile);
+                if (status == BluetoothProfile.STATE_DISCONNECTING
+                        || status == BluetoothProfile.STATE_CONNECTING) {
+                    return true;
+                }
+            }
+            if (hapClientProfile != null) {
+                int status = device.getProfileConnectionState(hapClientProfile);
+                if (status == BluetoothProfile.STATE_DISCONNECTING
+                        || status == BluetoothProfile.STATE_CONNECTING) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean isActiveConnectionStatus(Set<CachedBluetoothDevice> devices) {
+        for (CachedBluetoothDevice device : devices) {
+            if ((device.isActiveDevice(BluetoothProfile.HEARING_AID)
+                    && device.isConnectedProfile(BluetoothProfile.HEARING_AID))
+                    || (device.isActiveDevice(BluetoothProfile.LE_AUDIO)
+                    && device.isConnectedProfile(BluetoothProfile.LE_AUDIO))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isConnectedStatus(Set<CachedBluetoothDevice> devices) {
+        return devices.stream().anyMatch(CachedBluetoothDevice::isConnected);
+    }
+
+    private boolean isDisconnectedStatus(Set<CachedBluetoothDevice> devices) {
+        return devices.stream().anyMatch(
+                d -> (!d.isConnected() && d.getBondState() == BOND_BONDED));
+    }
+
+    /**
+     * Gets the connection status for hearing device set. Will update connection status first if
+     * never updated.
+     */
+    @ConnectionStatus
+    public int getDevicesConnectionStatus() {
+        if (!mInitialDevicesConnectionStatusUpdate) {
+            updateDevicesConnectionStatus();
+        }
+        return mDevicesConnectionStatus;
+    }
+
     void initHearingAidDeviceIfNeeded(CachedBluetoothDevice newDevice,
             List<ScanFilter> leScanFilters) {
         HearingAidInfo info = generateHearingAidInfo(newDevice);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 8dfeb55..7c24df9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -47,12 +47,14 @@
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
+import com.android.settingslib.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 
@@ -345,11 +347,17 @@
                     oldState == BluetoothProfile.STATE_CONNECTING) {
                 Log.i(TAG, "Failed to connect " + mProfile + " device");
             }
+            final boolean isAshaProfile = getHearingAidProfile() != null
+                    && mProfile instanceof HearingAidProfile;
+            final boolean isHapClientProfile = getHapClientProfile() != null
+                    && mProfile instanceof HapClientProfile;
+            final boolean isLeAudioProfile = getLeAudioProfile() != null
+                    && mProfile instanceof LeAudioProfile;
+            final boolean isHapClientOrLeAudioProfile = isHapClientProfile || isLeAudioProfile;
+            final boolean isCsipProfile = getCsipSetCoordinatorProfile() != null
+                    && mProfile instanceof CsipSetCoordinatorProfile;
 
-            if (getHearingAidProfile() != null
-                    && mProfile instanceof HearingAidProfile
-                    && (newState == BluetoothProfile.STATE_CONNECTED)) {
-
+            if (isAshaProfile && (newState == BluetoothProfile.STATE_CONNECTED)) {
                 // Check if the HiSyncID has being initialized
                 if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                     long newHiSyncId = getHearingAidProfile().getHiSyncId(cachedDevice.getDevice());
@@ -366,11 +374,6 @@
                 HearingAidStatsLogUtils.logHearingAidInfo(cachedDevice);
             }
 
-            final boolean isHapClientProfile = getHapClientProfile() != null
-                    && mProfile instanceof HapClientProfile;
-            final boolean isLeAudioProfile = getLeAudioProfile() != null
-                    && mProfile instanceof LeAudioProfile;
-            final boolean isHapClientOrLeAudioProfile = isHapClientProfile || isLeAudioProfile;
             if (isHapClientOrLeAudioProfile && newState == BluetoothProfile.STATE_CONNECTED) {
 
                 // Checks if both profiles are connected to the device. Hearing aid info need
@@ -385,9 +388,7 @@
                 }
             }
 
-            if (getCsipSetCoordinatorProfile() != null
-                    && mProfile instanceof CsipSetCoordinatorProfile
-                    && newState == BluetoothProfile.STATE_CONNECTED) {
+            if (isCsipProfile && (newState == BluetoothProfile.STATE_CONNECTED)) {
                 // Check if the GroupID has being initialized
                 if (cachedDevice.getGroupId() == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
                     final Map<Integer, ParcelUuid> groupIdMap = getCsipSetCoordinatorProfile()
@@ -403,6 +404,21 @@
                 }
             }
 
+            // LE_AUDIO, CSIP_SET_COORDINATOR profiles will also impact the connection status
+            // change, e.g. device need to active on LE_AUDIO to become active connection status.
+            final Set<Integer> hearingDeviceConnectionStatusProfileId = Set.of(
+                    BluetoothProfile.HEARING_AID,
+                    BluetoothProfile.HAP_CLIENT,
+                    BluetoothProfile.LE_AUDIO,
+                    BluetoothProfile.CSIP_SET_COORDINATOR
+            );
+            if (Flags.hearingDeviceSetConnectionStatusReport()) {
+                if (hearingDeviceConnectionStatusProfileId.contains(mProfile.getProfileId())) {
+                    mDeviceManager.notifyHearingDevicesConnectionStatusChangedIfNeeded(
+                            cachedDevice);
+                }
+            }
+
             cachedDevice.onProfileStateChanged(mProfile, newState);
             // Dispatch profile changed after device update
             boolean needDispatchProfileConnectionState = true;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
index c71b19c..e01f279 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
@@ -501,7 +501,7 @@
                 val wifiManager = context.getSystemService(WifiManager::class.java) ?: return@launch
                 val aapmManager = context.getSystemService(AdvancedProtectionManager::class.java)
                 if (isAdvancedProtectionEnabled(aapmManager)) {
-                    val intent = AdvancedProtectionManager.createSupportIntent(
+                    val intent = aapmManager.createSupportIntent(
                         AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP,
                         AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_BLOCKED_INTERACTION)
                     onStartActivity(intent)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 05f471f..69e99c6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -33,21 +33,37 @@
 import android.content.Context;
 import android.os.Parcel;
 import android.os.ParcelUuid;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
 
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 @RunWith(RobolectricTestRunner.class)
 public class CachedBluetoothDeviceManagerTest {
+    @Rule
+    public MockitoRule mMockitoRule = MockitoJUnit.rule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+
     private final static String DEVICE_NAME_1 = "TestName_1";
     private final static String DEVICE_NAME_2 = "TestName_2";
     private final static String DEVICE_NAME_3 = "TestName_3";
@@ -82,6 +98,8 @@
     @Mock
     private HearingAidProfile mHearingAidProfile;
     @Mock
+    private HapClientProfile mHapClientProfile;
+    @Mock
     private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile;
     @Mock
     private BluetoothDevice mDevice1;
@@ -89,12 +107,11 @@
     private BluetoothDevice mDevice2;
     @Mock
     private BluetoothDevice mDevice3;
+    private HearingAidDeviceManager mHearingAidDeviceManager;
     private CachedBluetoothDevice mCachedDevice1;
     private CachedBluetoothDevice mCachedDevice2;
     private CachedBluetoothDevice mCachedDevice3;
     private CachedBluetoothDeviceManager mCachedDeviceManager;
-    private HearingAidDeviceManager mHearingAidDeviceManager;
-    private Context mContext;
 
     private BluetoothClass createBtClass(int deviceClass) {
         Parcel p = Parcel.obtain();
@@ -108,8 +125,6 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
         when(mDevice1.getAddress()).thenReturn(DEVICE_ADDRESS_1);
         when(mDevice2.getAddress()).thenReturn(DEVICE_ADDRESS_2);
         when(mDevice3.getAddress()).thenReturn(DEVICE_ADDRESS_3);
@@ -129,13 +144,15 @@
         when(mA2dpProfile.isProfileReady()).thenReturn(true);
         when(mPanProfile.isProfileReady()).thenReturn(true);
         when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+        when(mHapClientProfile.isProfileReady()).thenReturn(true);
         when(mCsipSetCoordinatorProfile.isProfileReady())
                 .thenReturn(true);
         doAnswer((invocation) -> mHearingAidProfile).
                 when(mLocalProfileManager).getHearingAidProfile();
         doAnswer((invocation) -> mCsipSetCoordinatorProfile)
                 .when(mLocalProfileManager).getCsipSetCoordinatorProfile();
-        mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager);
+        mCachedDeviceManager = spy(
+                new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager));
         mCachedDevice1 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1));
         mCachedDevice2 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2));
         mCachedDevice3 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice3));
@@ -621,12 +638,55 @@
     public void onActiveDeviceChanged_validHiSyncId_callExpectedFunction() {
         doNothing().when(mHearingAidDeviceManager).onActiveDeviceChanged(any());
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
-        cachedDevice1.setHearingAidInfo(
-                new HearingAidInfo.Builder().setHiSyncId(HISYNCID1).build());
+        when(mCachedDevice1.getProfiles()).thenReturn(
+                ImmutableList.of(mHapClientProfile, mHearingAidProfile));
 
-        mCachedDeviceManager.onActiveDeviceChanged(cachedDevice1);
+        mCachedDeviceManager.onActiveDeviceChanged(mCachedDevice1);
 
-        verify(mHearingAidDeviceManager).onActiveDeviceChanged(cachedDevice1);
+        verify(mHearingAidDeviceManager).onActiveDeviceChanged(mCachedDevice1);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(
+            com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICE_SET_CONNECTION_STATUS_REPORT)
+    public void onActiveDeviceChanged_hearingDevice_callReportConnectionStatus() {
+        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(
+                ImmutableList.of(mHapClientProfile, mHearingAidProfile));
+
+        mCachedDeviceManager.onActiveDeviceChanged(mCachedDevice1);
+
+        verify(mHearingAidDeviceManager).notifyDevicesConnectionStatusChanged();
+    }
+
+    @Test
+    @RequiresFlagsEnabled(
+            com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICE_SET_CONNECTION_STATUS_REPORT)
+    public void onDeviceUnpaired_hearingDevice_callReportConnectionStatus() {
+        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(
+                ImmutableList.of(mHapClientProfile, mHearingAidProfile));
+
+        mCachedDeviceManager.onDeviceUnpaired(mCachedDevice1);
+
+        verify(mHearingAidDeviceManager).notifyDevicesConnectionStatusChanged();
+    }
+
+    @Test
+    public void notifyHearingDevicesConnectionStatusChanged_nonHearingDevice_notCallFunction() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mA2dpProfile));
+
+        mCachedDeviceManager.notifyHearingDevicesConnectionStatusChangedIfNeeded(mCachedDevice1);
+
+        verify(mHearingAidDeviceManager, never()).notifyDevicesConnectionStatusChanged();
+    }
+
+    @Test
+    public void notifyHearingDevicesConnectionStatusChanged_hearingDeviceProfile_callFunction() {
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile));
+
+        mCachedDeviceManager.notifyHearingDevicesConnectionStatusChangedIfNeeded(mCachedDevice1);
+
+        verify(mHearingAidDeviceManager).notifyDevicesConnectionStatusChanged();
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 30f8a79..d933a1c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -2074,6 +2074,21 @@
         assertThat(mCachedDevice.getConnectionSummary(false)).isNull();
     }
 
+    @Test
+    public void isHearingDevice_supportHearingRelatedProfiles_returnTrue() {
+        when(mCachedDevice.getProfiles()).thenReturn(
+                ImmutableList.of(mHapClientProfile, mHearingAidProfile));
+
+        assertThat(mCachedDevice.isHearingDevice()).isTrue();
+    }
+
+    @Test
+    public void isHearingDevice_supportOnlyLeAudioProfile_returnFalse() {
+        when(mCachedDevice.getProfiles()).thenReturn(ImmutableList.of(mLeAudioProfile));
+
+        assertThat(mCachedDevice.isHearingDevice()).isFalse();
+    }
+
     private void updateProfileStatus(LocalBluetoothProfile profile, int status) {
         doReturn(status).when(profile).getConnectionStatus(mDevice);
         mCachedDevice.onProfileStateChanged(profile, status);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index 2458c5b..21dde1f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -54,6 +54,8 @@
 
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager.ConnectionStatus;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -112,7 +114,10 @@
     private BluetoothDevice mDevice1;
     @Mock
     private BluetoothDevice mDevice2;
-
+    @Mock
+    private HearingAidDeviceManager.ConnectionStatusListener mConnectionStatusListener;
+    @Mock
+    private HearingAidDeviceManager.ConnectionStatusListener mConnectionStatusListener2;
 
     private BluetoothClass createBtClass(int deviceClass) {
         Parcel p = Parcel.obtain();
@@ -140,6 +145,8 @@
         when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
         when(mLocalProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
         when(mLocalProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+        when(mHapClientProfile.getProfileId()).thenReturn(BluetoothProfile.HAP_CLIENT);
+        when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
         when(mAudioStrategy.getAudioAttributesForLegacyStreamType(
                 AudioManager.STREAM_MUSIC))
                 .thenReturn((new AudioAttributes.Builder()).build());
@@ -826,6 +833,125 @@
         verify(mHapClientProfile).selectPreset(mDevice2, PRESET_INDEX_1);
     }
 
+    @Test
+    public void getAssociatedCachedDevice_existSubDevice_returnSize2() {
+        mCachedDevice1.setSubDevice(mCachedDevice2);
+
+        //including self device
+        assertThat(mHearingAidDeviceManager.getAssociatedCachedDevice(
+                mCachedDevice1).size()).isEqualTo(2);
+    }
+
+    @Test
+    public void getAssociatedCachedDevice_existMemberDevice_returnSize2() {
+        mCachedDevice1.addMemberDevice(mCachedDevice2);
+
+        //including self device
+        assertThat(mHearingAidDeviceManager.getAssociatedCachedDevice(
+                mCachedDevice1).size()).isEqualTo(2);
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_connecting_connectingStatus() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile));
+        when(mHapClientProfile.getConnectionStatus(mDevice1)).thenReturn(
+                BluetoothProfile.STATE_CONNECTING);
+
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        assertThat(mHearingAidDeviceManager.getDevicesConnectionStatus()).isEqualTo(
+                ConnectionStatus.CONNECTING_OR_DISCONNECTING);
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_activeConnectedProfile_activeStatus() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile));
+        when(mLeAudioProfile.getConnectionStatus(mDevice1)).thenReturn(
+                BluetoothProfile.STATE_CONNECTED);
+        when(mCachedDevice1.isActiveDevice(BluetoothProfile.LE_AUDIO)).thenReturn(true);
+
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        assertThat(mHearingAidDeviceManager.getDevicesConnectionStatus()).isEqualTo(
+                ConnectionStatus.ACTIVE);
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_isConnected_connectedStatus() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile));
+        when(mCachedDevice1.isConnected()).thenReturn(true);
+
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        assertThat(mHearingAidDeviceManager.getDevicesConnectionStatus()).isEqualTo(
+                ConnectionStatus.CONNECTED);
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_bondedNotConnected_disconnectedStatus() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.isConnected()).thenReturn(false);
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile));
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        assertThat(mHearingAidDeviceManager.getDevicesConnectionStatus()).isEqualTo(
+                ConnectionStatus.DISCONNECTED);
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_bondNone_noDeviceBondedStatus() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        assertThat(mHearingAidDeviceManager.getDevicesConnectionStatus()).isEqualTo(
+                ConnectionStatus.NO_DEVICE_BONDED);
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_noRegisteredListener_noCallback() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile));
+        when(mCachedDevice1.isConnected()).thenReturn(true);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.registerConnectionStatusListener(
+                mConnectionStatusListener, mContext.getMainExecutor());
+        mHearingAidDeviceManager.unregisterConnectionStatusListener(
+                mConnectionStatusListener);
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        verify(mConnectionStatusListener, never()).onDevicesConnectionStatusChanged(anyInt());
+    }
+
+    @Test
+    public void notifyDevicesConnectionStatusChanged_twoRegisteredListener_callbackEachConnected() {
+        when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile));
+        when(mCachedDevice1.isConnected()).thenReturn(true);
+        mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
+        mHearingAidDeviceManager.registerConnectionStatusListener(
+                mConnectionStatusListener, mContext.getMainExecutor());
+        mHearingAidDeviceManager.registerConnectionStatusListener(
+                mConnectionStatusListener2, mContext.getMainExecutor());
+        mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged();
+
+        verify(mConnectionStatusListener).onDevicesConnectionStatusChanged(
+                ConnectionStatus.CONNECTED);
+        verify(mConnectionStatusListener2).onDevicesConnectionStatusChanged(
+                ConnectionStatus.CONNECTED);
+    }
+
     private HearingAidInfo getLeftAshaHearingAidInfo(long hiSyncId) {
         return new HearingAidInfo.Builder()
                 .setAshaDeviceSide(HearingAidInfo.DeviceSide.SIDE_LEFT)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index 6ff90ba..219bfe0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -37,10 +37,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.ParcelUuid;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 
 import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -56,6 +60,9 @@
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = {ShadowBluetoothAdapter.class})
 public class LocalBluetoothProfileManagerTest {
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static final long HISYNCID = 10;
 
     private static final int GROUP_ID = 1;
@@ -305,6 +312,25 @@
         verify(mCachedBluetoothDevice).refresh();
     }
 
+    @Test
+    @RequiresFlagsEnabled(
+            com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICE_SET_CONNECTION_STATUS_REPORT)
+    public void stateChangedHandler_hapProfileStateChanged_notifyHearingDevicesConnectionStatus() {
+        mShadowBluetoothAdapter.setSupportedProfiles(generateList(
+                new int[] {BluetoothProfile.HAP_CLIENT}));
+        mProfileManager.updateLocalProfiles();
+
+        mIntent = new Intent(BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        mIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
+        mIntent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTING);
+        mIntent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
+
+        mContext.sendBroadcast(mIntent);
+
+        verify(mDeviceManager).notifyHearingDevicesConnectionStatusChangedIfNeeded(
+                mCachedBluetoothDevice);
+    }
+
     private List<Integer> generateList(int[] profiles) {
         if (profiles == null) {
             return null;
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index f1bbfc6..5b4ee8b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -110,6 +110,7 @@
                 Settings.System.MOUSE_REVERSE_VERTICAL_SCROLLING,
                 Settings.System.MOUSE_SCROLLING_ACCELERATION,
                 Settings.System.MOUSE_SWAP_PRIMARY_BUTTON,
+                Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED,
                 Settings.System.TOUCHPAD_POINTER_SPEED,
                 Settings.System.TOUCHPAD_NATURAL_SCROLLING,
                 Settings.System.TOUCHPAD_TAP_TO_CLICK,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 6abd9b7..0432eea 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -226,6 +226,7 @@
         VALIDATORS.put(System.MOUSE_REVERSE_VERTICAL_SCROLLING, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.MOUSE_SWAP_PRIMARY_BUTTON, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.MOUSE_SCROLLING_ACCELERATION, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(System.MOUSE_POINTER_ACCELERATION_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
         VALIDATORS.put(System.TOUCHPAD_NATURAL_SCROLLING, BOOLEAN_VALIDATOR);
         VALIDATORS.put(System.TOUCHPAD_TAP_TO_CLICK, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 3ee2db1..b88ae37 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -278,13 +278,13 @@
         "tests/src/**/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt",
         "tests/src/**/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt",
         "tests/src/**/systemui/qs/tiles/HotspotTileTest.java",
-        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java",
+        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateLegacyTest.java",
         "tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
         "tests/src/**/systemui/wmshell/BubblesTest.java",
         "tests/src/**/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java",
         "tests/src/**/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java",
         "tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
-        "tests/src/**/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java",
+        "tests/src/**/systemui/qs/tiles/dialog/InternetDetailsContentControllerTest.java",
         "tests/src/**/systemui/qs/external/TileLifecycleManagerTest.java",
         "tests/src/**/systemui/ScreenDecorationsTest.java",
         "tests/src/**/systemui/statusbar/policy/BatteryControllerStartableTest.java",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a93e4a0..7d201c1 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -492,7 +492,7 @@
     name: "status_bar_notification_chips"
     namespace: "systemui"
     description: "Show promoted ongoing notifications as chips in the status bar"
-    bug: "361346412"
+    bug: "364653005"
 }
 
 flag {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/ContentOverscrollEffect.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt
similarity index 75%
rename from packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/ContentOverscrollEffect.kt
rename to packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt
index 2233deb..4ee6db3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/ContentOverscrollEffect.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/ContentOverscrollEffect.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.compose.animation.scene.effect
+package com.android.compose.gesture.effect
 
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationSpec
@@ -118,56 +118,3 @@
         }
     }
 }
-
-/** An overscroll effect that ensures only a single fling animation is triggered. */
-internal class GestureEffect(private val delegate: ContentOverscrollEffect) :
-    ContentOverscrollEffect by delegate {
-    private var shouldFling = false
-
-    override fun applyToScroll(
-        delta: Offset,
-        source: NestedScrollSource,
-        performScroll: (Offset) -> Offset,
-    ): Offset {
-        shouldFling = true
-        return delegate.applyToScroll(delta, source, performScroll)
-    }
-
-    override suspend fun applyToFling(
-        velocity: Velocity,
-        performFling: suspend (Velocity) -> Velocity,
-    ) {
-        if (!shouldFling) {
-            performFling(velocity)
-            return
-        }
-        shouldFling = false
-        delegate.applyToFling(velocity, performFling)
-    }
-
-    suspend fun ensureApplyToFlingIsCalled() {
-        applyToFling(Velocity.Zero) { Velocity.Zero }
-    }
-}
-
-/**
- * An overscroll effect that only applies visual effects and does not interfere with the actual
- * scrolling or flinging behavior.
- */
-internal class VisualEffect(private val delegate: ContentOverscrollEffect) :
-    ContentOverscrollEffect by delegate {
-    override fun applyToScroll(
-        delta: Offset,
-        source: NestedScrollSource,
-        performScroll: (Offset) -> Offset,
-    ): Offset {
-        return performScroll(delta)
-    }
-
-    override suspend fun applyToFling(
-        velocity: Velocity,
-        performFling: suspend (Velocity) -> Velocity,
-    ) {
-        performFling(velocity)
-    }
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffect.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt
similarity index 71%
rename from packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffect.kt
rename to packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt
index f459c46..d992403 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffect.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/effect/OffsetOverscrollEffect.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.compose.animation.scene.effect
+package com.android.compose.gesture.effect
 
 import androidx.annotation.VisibleForTesting
 import androidx.compose.animation.core.AnimationSpec
@@ -34,7 +34,6 @@
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.dp
-import com.android.compose.animation.scene.ProgressConverter
 import kotlin.math.roundToInt
 import kotlinx.coroutines.CoroutineScope
 
@@ -80,7 +79,7 @@
             )
 
         @VisibleForTesting
-        internal fun computeOffset(density: Density, overscrollDistance: Float): Int {
+        fun computeOffset(density: Density, overscrollDistance: Float): Int {
             val maxDistancePx = with(density) { MaxDistance.toPx() }
             val progress = ProgressConverter.Default.convert(overscrollDistance / maxDistancePx)
             return (progress * maxDistancePx).roundToInt()
@@ -98,3 +97,35 @@
         OffsetOverscrollEffect(orientation, animationScope, animationSpec)
     }
 }
+
+/** This converter lets you change a linear progress into a function of your choice. */
+fun interface ProgressConverter {
+    fun convert(progress: Float): Float
+
+    companion object {
+        /** Starts linearly with some resistance and slowly approaches to 0.2f */
+        val Default = tanh(maxProgress = 0.2f, tilt = 3f)
+
+        /**
+         * The scroll stays linear, with [factor] you can control how much resistance there is.
+         *
+         * @param factor If you choose a value between 0f and 1f, the progress will grow more
+         *   slowly, like there's resistance. A value of 1f means there's no resistance.
+         */
+        fun linear(factor: Float = 1f) = ProgressConverter { it * factor }
+
+        /**
+         * This function starts linear and slowly approaches [maxProgress].
+         *
+         * See a [visual representation](https://www.desmos.com/calculator/usgvvf0z1u) of this
+         * function.
+         *
+         * @param maxProgress is the maximum progress value.
+         * @param tilt behaves similarly to the factor in the [linear] function, and allows you to
+         *   control how quickly you get to the [maxProgress].
+         */
+        fun tanh(maxProgress: Float, tilt: Float = 1f) = ProgressConverter {
+            maxProgress * kotlin.math.tanh(x = it / (maxProgress * tilt))
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt b/packages/SystemUI/compose/core/src/com/android/compose/ui/util/SpaceVectorConverter.kt
similarity index 100%
rename from packages/SystemUI/compose/scene/src/com/android/compose/ui/util/SpaceVectorConverter.kt
rename to packages/SystemUI/compose/core/src/com/android/compose/ui/util/SpaceVectorConverter.kt
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt
similarity index 98%
rename from packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt
rename to packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt
index da8fe30..5a3f240 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/effect/OffsetOverscrollEffectTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.compose.animation.scene.effect
+package com.android.compose.gesture.effect
 
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.rememberScrollableState
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index 7956d02..9643f19 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -34,7 +34,6 @@
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.modifiers.padding
-import com.android.compose.modifiers.thenIf
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
 import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
@@ -97,18 +96,15 @@
                             )
                         }
 
-                        Box {
+                        Box(modifier = Modifier.fillMaxWidth()) {
                             with(topAreaSection) {
                                 DefaultClockLayout(
                                     smartSpacePaddingTop = viewModel::getSmartSpacePaddingTop,
                                     isShadeLayoutWide = isShadeLayoutWide,
                                     modifier =
-                                        Modifier.thenIf(isShadeLayoutWide) {
-                                                Modifier.fillMaxWidth(0.5f)
-                                            }
-                                            .graphicsLayer {
-                                                translationX = unfoldTranslations.start
-                                            },
+                                        Modifier.fillMaxWidth().graphicsLayer {
+                                            translationX = unfoldTranslations.start
+                                        },
                                 )
                             }
                             if (isShadeLayoutWide && !isBypassEnabled) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index eae46e9..fb01e70 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -81,10 +81,7 @@
                     .padding(horizontal = dimensionResource(R.dimen.clock_padding_start))
                     .padding(top = { smallTopMargin })
                     .onTopPlacementChanged(onTopChanged)
-                    .burnInAware(
-                        viewModel = aodBurnInViewModel,
-                        params = burnInParams,
-                    )
+                    .burnInAware(viewModel = aodBurnInViewModel, params = burnInParams)
                     .element(smallClockElementKey),
         )
     }
@@ -114,10 +111,7 @@
             val dir = if (transition.toContent == splitShadeLargeClockScene) -1f else 1f
             val distance = dir * getClockCenteringDistance()
             val largeClock = checkNotNull(currentClock).largeClock
-            largeClock.animations.onPositionUpdated(
-                distance = distance,
-                fraction = progress,
-            )
+            largeClock.animations.onPositionUpdated(distance = distance, fraction = progress)
         }
 
         Element(key = largeClockElementKey, modifier = modifier) {
@@ -125,6 +119,16 @@
                 AndroidView(
                     factory = { context ->
                         FrameLayout(context).apply {
+                            // By default, ViewGroups like FrameLayout clip their children. Turning
+                            // off the clipping allows the child view to render outside of its
+                            // bounds - letting the step animation of the clock push the digits out
+                            // when needed.
+                            //
+                            // Note that, in Compose, clipping is actually disabled by default so
+                            // there's no need to propagate this up the composable hierarchy.
+                            clipChildren = false
+                            clipToPadding = false
+
                             ensureClockViewExists(checkNotNull(currentClock).largeClock.view)
                         }
                     },
@@ -136,8 +140,8 @@
                             .burnInAware(
                                 viewModel = aodBurnInViewModel,
                                 params = burnInParams,
-                                isClock = true
-                            )
+                                isClock = true,
+                            ),
                 )
             }
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index cfbe667..ffdf509 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -58,7 +58,7 @@
 import com.android.compose.animation.scene.ContentScope
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexContentPicker
-import com.android.compose.animation.scene.effect.rememberOffsetOverscrollEffect
+import com.android.compose.gesture.effect.rememberOffsetOverscrollEffect
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.res.R
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
index 1480db9..5f991fb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
@@ -101,20 +101,21 @@
     Column(modifier) {
         Row(
             horizontalArrangement = Arrangement.spacedBy(12.dp),
-            modifier = Modifier.fillMaxWidth(),
+            modifier = Modifier.fillMaxWidth().height(40.dp),
+            verticalAlignment = Alignment.CenterVertically,
         ) {
             state.icon?.let {
                 Icon(
                     icon = it,
                     tint = MaterialTheme.colorScheme.onSurface,
-                    modifier = Modifier.size(40.dp).padding(8.dp),
+                    modifier = Modifier.size(24.dp),
                 )
             }
             Text(
                 text = state.label,
                 style = MaterialTheme.typography.titleMedium,
                 color = MaterialTheme.colorScheme.onSurface,
-                modifier = Modifier.weight(1f).align(Alignment.CenterVertically),
+                modifier = Modifier.weight(1f),
             )
             button?.invoke()
         }
@@ -125,43 +126,47 @@
             onValueChangeFinished = onValueChangeFinished,
             enabled = state.isEnabled,
             modifier =
-                Modifier.height(40.dp).sysuiResTag(state.label).clearAndSetSemantics {
-                    if (state.isEnabled) {
-                        contentDescription = state.label
-                        state.a11yClickDescription?.let {
-                            customActions =
-                                listOf(
-                                    CustomAccessibilityAction(it) {
-                                        onIconTapped()
-                                        true
-                                    }
-                                )
-                        }
-
-                        state.a11yStateDescription?.let { stateDescription = it }
-                        progressBarRangeInfo = ProgressBarRangeInfo(state.value, state.valueRange)
-                    } else {
-                        disabled()
-                        contentDescription =
-                            state.disabledMessage?.let { "${state.label}, $it" } ?: state.label
-                    }
-                    setProgress { targetValue ->
-                        val targetDirection =
-                            when {
-                                targetValue > value -> 1
-                                targetValue < value -> -1
-                                else -> 0
+                Modifier.height(40.dp)
+                    .padding(vertical = 8.dp)
+                    .sysuiResTag(state.label)
+                    .clearAndSetSemantics {
+                        if (state.isEnabled) {
+                            contentDescription = state.label
+                            state.a11yClickDescription?.let {
+                                customActions =
+                                    listOf(
+                                        CustomAccessibilityAction(it) {
+                                            onIconTapped()
+                                            true
+                                        }
+                                    )
                             }
 
-                        val newValue =
-                            (value + targetDirection * state.a11yStep).coerceIn(
-                                state.valueRange.start,
-                                state.valueRange.endInclusive,
-                            )
-                        onValueChange(newValue)
-                        true
-                    }
-                },
+                            state.a11yStateDescription?.let { stateDescription = it }
+                            progressBarRangeInfo =
+                                ProgressBarRangeInfo(state.value, state.valueRange)
+                        } else {
+                            disabled()
+                            contentDescription =
+                                state.disabledMessage?.let { "${state.label}, $it" } ?: state.label
+                        }
+                        setProgress { targetValue ->
+                            val targetDirection =
+                                when {
+                                    targetValue > value -> 1
+                                    targetValue < value -> -1
+                                    else -> 0
+                                }
+
+                            val newValue =
+                                (value + targetDirection * state.a11yStep).coerceIn(
+                                    state.valueRange.start,
+                                    state.valueRange.endInclusive,
+                                )
+                            onValueChange(newValue)
+                            true
+                        }
+                    },
         )
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 7b30a2a..c704a3e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -35,7 +35,7 @@
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
-import com.android.compose.animation.scene.effect.ContentOverscrollEffect
+import com.android.compose.gesture.effect.ContentOverscrollEffect
 
 /**
  * [SceneTransitionLayout] is a container that automatically animates its content whenever its state
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index 8794df0..fda6fab 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -25,7 +25,6 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.content.state.TransitionState
 import com.android.compose.animation.scene.transformation.Transformation
-import kotlin.math.tanh
 
 /** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
 fun transitions(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
@@ -476,35 +475,3 @@
     /** Apply a [transformation] to the element(s) matching [matcher]. */
     fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory)
 }
-
-/** This converter lets you change a linear progress into a function of your choice. */
-fun interface ProgressConverter {
-    fun convert(progress: Float): Float
-
-    companion object {
-        /** Starts linearly with some resistance and slowly approaches to 0.2f */
-        val Default = tanh(maxProgress = 0.2f, tilt = 3f)
-
-        /**
-         * The scroll stays linear, with [factor] you can control how much resistance there is.
-         *
-         * @param factor If you choose a value between 0f and 1f, the progress will grow more
-         *   slowly, like there's resistance. A value of 1f means there's no resistance.
-         */
-        fun linear(factor: Float = 1f) = ProgressConverter { it * factor }
-
-        /**
-         * This function starts linear and slowly approaches [maxProgress].
-         *
-         * See a [visual representation](https://www.desmos.com/calculator/usgvvf0z1u) of this
-         * function.
-         *
-         * @param maxProgress is the maximum progress value.
-         * @param tilt behaves similarly to the factor in the [linear] function, and allows you to
-         *   control how quickly you get to the [maxProgress].
-         */
-        fun tanh(maxProgress: Float, tilt: Float = 1f) = ProgressConverter {
-            maxProgress * tanh(x = it / (maxProgress * tilt))
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 8c5a727..4c15f7a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -53,10 +53,10 @@
 import com.android.compose.animation.scene.ValueKey
 import com.android.compose.animation.scene.animateSharedValueAsState
 import com.android.compose.animation.scene.effect.GestureEffect
-import com.android.compose.animation.scene.effect.OffsetOverscrollEffect
 import com.android.compose.animation.scene.effect.VisualEffect
 import com.android.compose.animation.scene.element
 import com.android.compose.animation.scene.modifiers.noResizeDuringTransitions
+import com.android.compose.gesture.effect.OffsetOverscrollEffect
 import com.android.compose.modifiers.thenIf
 import com.android.compose.ui.graphics.ContainerState
 import com.android.compose.ui.graphics.container
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt
new file mode 100644
index 0000000..2db45aa
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/effect/GestureEffect.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.effect
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.nestedscroll.NestedScrollSource
+import androidx.compose.ui.unit.Velocity
+import com.android.compose.gesture.effect.ContentOverscrollEffect
+
+/** An overscroll effect that ensures only a single fling animation is triggered. */
+internal class GestureEffect(private val delegate: ContentOverscrollEffect) :
+    ContentOverscrollEffect by delegate {
+    private var shouldFling = false
+
+    override fun applyToScroll(
+        delta: Offset,
+        source: NestedScrollSource,
+        performScroll: (Offset) -> Offset,
+    ): Offset {
+        shouldFling = true
+        return delegate.applyToScroll(delta, source, performScroll)
+    }
+
+    override suspend fun applyToFling(
+        velocity: Velocity,
+        performFling: suspend (Velocity) -> Velocity,
+    ) {
+        if (!shouldFling) {
+            performFling(velocity)
+            return
+        }
+        shouldFling = false
+        delegate.applyToFling(velocity, performFling)
+    }
+
+    suspend fun ensureApplyToFlingIsCalled() {
+        applyToFling(Velocity.Zero) { Velocity.Zero }
+    }
+}
+
+/**
+ * An overscroll effect that only applies visual effects and does not interfere with the actual
+ * scrolling or flinging behavior.
+ */
+internal class VisualEffect(private val delegate: ContentOverscrollEffect) :
+    ContentOverscrollEffect by delegate {
+    override fun applyToScroll(
+        delta: Offset,
+        source: NestedScrollSource,
+        performScroll: (Offset) -> Offset,
+    ): Offset {
+        return performScroll(delta)
+    }
+
+    override suspend fun applyToFling(
+        velocity: Velocity,
+        performFling: suspend (Velocity) -> Velocity,
+    ) {
+        performFling(velocity)
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 6769032..53495be 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -70,8 +70,8 @@
 import com.android.compose.animation.scene.TestScenes.SceneA
 import com.android.compose.animation.scene.TestScenes.SceneB
 import com.android.compose.animation.scene.TestScenes.SceneC
-import com.android.compose.animation.scene.effect.OffsetOverscrollEffect
 import com.android.compose.animation.scene.subjects.assertThat
+import com.android.compose.gesture.effect.OffsetOverscrollEffect
 import com.android.compose.test.assertSizeIsEqualTo
 import com.android.compose.test.setContentAndCreateMainScope
 import com.android.compose.test.transition
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
index 80de087..2665910 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java
@@ -29,6 +29,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.utils.TestUtils;
@@ -58,13 +59,15 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
 
     @Before
     public void setUp() throws Exception {
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
         final SecureSettings mockSecureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                mockSecureSettings);
+                mockSecureSettings, mHearingAidDeviceManager);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 stubWindowManager);
         final MenuView stubMenuView = spy(new MenuView(mContext, stubMenuViewModel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java
index 24f3a29..785493f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -25,11 +26,13 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.platform.test.annotations.EnableFlags;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -45,6 +48,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.Executor;
 
 /** Tests for {@link MenuInfoRepository}. */
 @RunWith(AndroidJUnit4.class)
@@ -55,9 +59,10 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
-
     @Mock
-    private MenuInfoRepository.OnSettingsContentsChanged mMockSettingsContentsChanged;
+    private HearingAidDeviceManager mHearingAidDeviceManager;
+    @Mock
+    private MenuInfoRepository.OnContentsChanged mMockSettingsContentsChanged;
     @Mock
     private SecureSettings mSecureSettings;
 
@@ -72,7 +77,7 @@
                 anyInt());
 
         mMenuInfoRepository = new MenuInfoRepository(mContext, mAccessibilityManager,
-                mMockSettingsContentsChanged, mSecureSettings);
+                mMockSettingsContentsChanged, mSecureSettings, mHearingAidDeviceManager);
     }
 
     @After
@@ -103,4 +108,16 @@
 
         verify(mMockSettingsContentsChanged).onTargetFeaturesChanged(any());
     }
+
+    @Test
+    @EnableFlags(
+            com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICE_SET_CONNECTION_STATUS_REPORT)
+    public void registerObservers_addHearingDeviceTarget_verifyRegisterConnectionStatusListener() {
+        mShortcutTargets.add(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
+        mMenuInfoRepository.registerObserversAndCallbacks();
+
+        verify(mHearingAidDeviceManager).registerConnectionStatusListener(
+                any(HearingAidDeviceManager.ConnectionStatusListener.class), any(
+                        Executor.class));
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index 157cccc..241da5f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -41,6 +41,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.utils.TestUtils;
@@ -68,6 +69,8 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
     private final SecureSettings mSecureSettings = TestUtils.mockSecureSettings();
     private RecyclerView mStubListView;
     private MenuView mMenuView;
@@ -84,7 +87,7 @@
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 stubWindowManager);
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                mSecureSettings);
+                mSecureSettings, mHearingAidDeviceManager);
 
         final int halfScreenHeight =
                 stubWindowManager.getCurrentWindowMetrics().getBounds().height() / 2;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
index 46f076a..fbd8a71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuListViewTouchHandlerTest.java
@@ -41,6 +41,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.MotionEventHelper;
@@ -82,13 +83,15 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
 
     @Before
     public void setUp() throws Exception {
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
         final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                secureSettings);
+                secureSettings, mHearingAidDeviceManager);
         final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext,
                 windowManager);
         mStubMenuView = new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
index fcdeff9..4f04310 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerControllerTest.java
@@ -41,6 +41,7 @@
 
 import com.android.app.viewcapture.ViewCapture;
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.util.settings.SecureSettings;
@@ -68,6 +69,8 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
 
     @Mock
     private SecureSettings mSecureSettings;
@@ -93,7 +96,7 @@
         when(mWindowMetrics.getWindowInsets()).thenReturn(stubDisplayInsets());
         mMenuViewLayerController = new MenuViewLayerController(mContext, mWindowManager,
                 viewCaptureAwareWm, mAccessibilityManager, mSecureSettings,
-                mock(NavigationModeController.class));
+                mock(NavigationModeController.class), mHearingAidDeviceManager);
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index ee8ce17..cb7c205 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -37,6 +37,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Flags;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysuiTestCase;
@@ -70,6 +71,8 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
 
     private SysuiTestableContext mSpyContext;
 
@@ -90,7 +93,7 @@
 
         final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                secureSettings);
+                secureSettings, mHearingAidDeviceManager);
         final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class);
         mStubMenuViewAppearance = new MenuViewAppearance(mSpyContext, stubWindowManager);
         mMenuView = spy(new MenuView(mSpyContext, stubMenuViewModel, mStubMenuViewAppearance,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
index f68a1b5..eae5728 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.display.data.repository
 
-import android.content.testableContext
+import android.content.Context
 import android.platform.test.annotations.EnableFlags
 import android.view.Display
 import android.view.layoutInflater
@@ -24,6 +24,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.SysuiTestableContext
 import com.android.systemui.display.shared.model.DisplayWindowProperties
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
@@ -36,8 +37,12 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.doAnswer
+import org.mockito.kotlin.any
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
 
 @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
 @RunWith(AndroidJUnit4::class)
@@ -48,7 +53,8 @@
     private val fakeDisplayRepository = kosmos.displayRepository
     private val testScope = kosmos.testScope
 
-    private val applicationContext = kosmos.testableContext
+    private val applicationContext = spy(context)
+
     private val applicationWindowManager = kosmos.mockWindowManager
     private val applicationLayoutInflater = kosmos.layoutInflater
 
@@ -64,6 +70,22 @@
     }
 
     @Before
+    fun setUpContext() {
+        doAnswer { createContextForDisplay(it.arguments[0] as Display) }
+            .whenever(applicationContext)
+            .createWindowContext(any(), any(), any())
+    }
+
+    private fun createContextForDisplay(display: Display): Context {
+        if (display.displayId == BEING_REMOVED_DISPLAY_ID) {
+            // Simulate what happens when a display is being removed.
+            // Return a context with the same display id as the original context.
+            return mContext
+        }
+        return SysuiTestableContext(mContext).also { it.display = display }
+    }
+
+    @Before
     fun start() {
         repo.start()
     }
@@ -72,6 +94,7 @@
     fun addDisplays() = runBlocking {
         fakeDisplayRepository.addDisplay(createDisplay(DEFAULT_DISPLAY_ID))
         fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
+        fakeDisplayRepository.addDisplay(createDisplay(BEING_REMOVED_DISPLAY_ID))
     }
 
     @Test
@@ -94,7 +117,7 @@
     @Test
     fun get_nonDefaultDisplayId_returnsNewStatusBarContext() =
         testScope.runTest {
-            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)!!
 
             assertThat(displayContext.context).isNotSameInstanceAs(applicationContext)
         }
@@ -102,7 +125,7 @@
     @Test
     fun get_nonDefaultDisplayId_returnsNewWindowManager() =
         testScope.runTest {
-            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)!!
 
             assertThat(displayContext.windowManager).isNotSameInstanceAs(applicationWindowManager)
         }
@@ -110,7 +133,7 @@
     @Test
     fun get_nonDefaultDisplayId_returnsNewLayoutInflater() =
         testScope.runTest {
-            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+            val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)!!
 
             assertThat(displayContext.layoutInflater).isNotSameInstanceAs(applicationLayoutInflater)
         }
@@ -154,17 +177,26 @@
                 .isNotSameInstanceAs(displayContext)
         }
 
-    @Test(expected = IllegalArgumentException::class)
-    fun get_nonExistingDisplayId_throws() =
-        testScope.runTest { repo.get(NON_EXISTING_DISPLAY_ID, WINDOW_TYPE_FOO) }
+    @Test
+    fun get_nonExistingDisplayId_returnsNull() =
+        testScope.runTest {
+            assertThat(repo.get(NON_EXISTING_DISPLAY_ID, WINDOW_TYPE_FOO)).isNull()
+        }
+
+    @Test
+    fun get_displayBeingRemoved_returnsNull() =
+        testScope.runTest {
+            assertThat(repo.get(BEING_REMOVED_DISPLAY_ID, WINDOW_TYPE_FOO)).isNull()
+        }
 
     private fun createDisplay(displayId: Int) =
-        mock<Display> { on { getDisplayId() } doReturn displayId }
+        mock<Display> { on { getDisplayId() } doReturn (displayId) }
 
     companion object {
         private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
         private const val NON_DEFAULT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1
         private const val NON_EXISTING_DISPLAY_ID = DEFAULT_DISPLAY_ID + 2
+        private const val BEING_REMOVED_DISPLAY_ID = DEFAULT_DISPLAY_ID + 4
         private const val WINDOW_TYPE_FOO = 123
         private const val WINDOW_TYPE_BAR = 321
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
index 6a0781b..73957eb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
@@ -80,9 +80,9 @@
             assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(instance)
         }
 
-    @Test(expected = IllegalArgumentException::class)
-    fun forDisplay_nonExistingDisplayId_throws() =
-        testScope.runTest { store.forDisplay(NON_EXISTING_DISPLAY_ID) }
+    @Test
+    fun forDisplay_nonExistingDisplayId_returnsNull() =
+        testScope.runTest { assertThat(store.forDisplay(NON_EXISTING_DISPLAY_ID)).isNull() }
 
     @Test
     fun forDisplay_afterDisplayRemoved_onDisplayRemovalActionInvoked() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/shared/QSSettingsPackageRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/shared/QSSettingsPackageRepositoryTest.kt
new file mode 100644
index 0000000..765c02a
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/shared/QSSettingsPackageRepositoryTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.shared
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyInt
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class QSSettingsPackageRepositoryTest : SysuiTestCase() {
+
+    @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var context: Context
+    @Mock private lateinit var packageManager: PackageManager
+    @Mock private lateinit var resolveInfo: ResolveInfo
+    @Mock private lateinit var activityInfo: ActivityInfo
+
+    private val kosmos = testKosmos()
+    private val scope = kosmos.testScope
+    private val userRepository = kosmos.fakeUserRepository
+
+    private lateinit var underTest: QSSettingsPackageRepository
+
+    @Before
+    fun setUp() {
+        whenever(context.createContextAsUser(any(), anyInt())).thenReturn(context)
+        whenever(context.packageManager).thenReturn(packageManager)
+        whenever(packageManager.queryIntentActivities(any(Intent::class.java), anyInt()))
+            .thenReturn(listOf(resolveInfo))
+        resolveInfo.activityInfo = activityInfo
+
+        underTest = QSSettingsPackageRepository(context, scope, userRepository)
+    }
+
+    @Test
+    fun getSettingsPackageName_noInit_returnsDefaultPackageName() {
+        assertThat(underTest.getSettingsPackageName()).isEqualTo(DEFAULT_SETTINGS_PACKAGE_NAME)
+    }
+
+    @Test
+    fun getSettingsPackageName_repositoryWithCustomPackage_returnsCustomPackageName() {
+        scope.runTest {
+            activityInfo.packageName = CUSTOM_SETTINGS_PACKAGE_NAME
+
+            underTest.init()
+            runCurrent()
+
+            assertThat(underTest.getSettingsPackageName()).isEqualTo(CUSTOM_SETTINGS_PACKAGE_NAME)
+        }
+    }
+
+    @Test
+    fun getSettingsPackageName_noMatchingActivity_returnsDefaultPackageName() {
+        scope.runTest {
+            whenever(packageManager.queryIntentActivities(any(Intent::class.java), anyInt()))
+                .thenReturn(emptyList())
+
+            underTest.init()
+            runCurrent()
+
+            assertThat(underTest.getSettingsPackageName()).isEqualTo(DEFAULT_SETTINGS_PACKAGE_NAME)
+        }
+    }
+
+    @Test
+    fun getSettingsPackageName_nullActivityInfo_returnsDefaultPackageName() {
+        scope.runTest {
+            resolveInfo.activityInfo = null
+
+            underTest.init()
+            runCurrent()
+
+            assertThat(underTest.getSettingsPackageName()).isEqualTo(DEFAULT_SETTINGS_PACKAGE_NAME)
+        }
+    }
+
+    companion object {
+        private const val DEFAULT_SETTINGS_PACKAGE_NAME = "com.android.settings"
+        private const val CUSTOM_SETTINGS_PACKAGE_NAME = "com.android.test.settings"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
index 028beb5..e5e8d4a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java
@@ -39,6 +39,7 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.shared.QSSettingsPackageRepository;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.settings.FakeSettings;
 import com.android.systemui.util.settings.SecureSettings;
@@ -55,6 +56,7 @@
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class ColorCorrectionTileTest extends SysuiTestCase {
+    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
 
     @Mock
     private QSHost mHost;
@@ -70,6 +72,8 @@
     private QsEventLogger mUiEventLogger;
     @Mock
     private UserTracker mUserTracker;
+    @Mock
+    private QSSettingsPackageRepository mQSSettingsPackageRepository;
 
     private TestableLooper mTestableLooper;
     private SecureSettings mSecureSettings;
@@ -83,6 +87,8 @@
         mTestableLooper = TestableLooper.get(this);
 
         when(mHost.getContext()).thenReturn(mContext);
+        when(mQSSettingsPackageRepository.getSettingsPackageName())
+                .thenReturn(SETTINGS_PACKAGE_NAME);
 
         mTile = new ColorCorrectionTile(
                 mHost,
@@ -95,7 +101,8 @@
                 mActivityStarter,
                 mQSLogger,
                 mUserTracker,
-                mSecureSettings
+                mSecureSettings,
+                mQSSettingsPackageRepository
         );
 
         mTile.initialize();
@@ -119,5 +126,6 @@
                 anyInt(), any());
         assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
                 Settings.ACTION_COLOR_CORRECTION_SETTINGS);
+        assertThat(IntentCaptor.getValue().getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME);
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
index a58dd63..cbde998 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.flags.QsInCompose;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.shared.QSSettingsPackageRepository;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
@@ -59,15 +60,16 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.List;
-
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
 import platform.test.runner.parameterized.Parameters;
 
+import java.util.List;
+
 @RunWith(ParameterizedAndroidJunit4.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class ColorInversionTileTest extends SysuiTestCase {
+    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final Integer COLOR_INVERSION_DISABLED = 0;
     private static final Integer COLOR_INVERSION_ENABLED = 1;
 
@@ -90,6 +92,8 @@
     private QsEventLogger mUiEventLogger;
     @Mock
     private UserTracker mUserTracker;
+    @Mock
+    private QSSettingsPackageRepository mQSSettingsPackageRepository;
 
     private TestableLooper mTestableLooper;
     private SecureSettings mSecureSettings;
@@ -108,6 +112,8 @@
         mTestableLooper = TestableLooper.get(this);
 
         when(mHost.getContext()).thenReturn(mContext);
+        when(mQSSettingsPackageRepository.getSettingsPackageName())
+                .thenReturn(SETTINGS_PACKAGE_NAME);
 
         mTile = new ColorInversionTile(
                 mHost,
@@ -120,7 +126,8 @@
                 mActivityStarter,
                 mQSLogger,
                 mUserTracker,
-                mSecureSettings
+                mSecureSettings,
+                mQSSettingsPackageRepository
         );
 
         mTile.initialize();
@@ -144,6 +151,7 @@
                 anyInt(), any());
         assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
                 Settings.ACTION_COLOR_INVERSION_SETTINGS);
+        assertThat(IntentCaptor.getValue().getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME);
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index c854920..ae4da9d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -32,11 +32,10 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
@@ -49,8 +48,10 @@
 import org.mockito.Mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -68,21 +69,24 @@
     @Mock private lateinit var dialog: SystemUIDialog
     @Mock private lateinit var expandable: Expandable
     @Mock private lateinit var controller: DialogTransitionAnimator.Controller
+    @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository
+
+    @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
 
     private lateinit var testableLooper: TestableLooper
     private lateinit var systemClock: FakeSystemClock
     private lateinit var backgroundDelayableExecutor: FakeExecutor
     private lateinit var fontScalingTile: FontScalingTile
 
-    @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
-
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
-        `when`(qsHost.getContext()).thenReturn(mContext)
-        `when`(fontScalingDialogDelegate.createDialog()).thenReturn(dialog)
-        `when`(expandable.dialogTransitionController(any())).thenReturn(controller)
+        whenever(qsHost.getContext()).thenReturn(mContext)
+        whenever(fontScalingDialogDelegate.createDialog()).thenReturn(dialog)
+        whenever(expandable.dialogTransitionController(any())).thenReturn(controller)
+        whenever(settingsPackageRepository.getSettingsPackageName())
+            .thenReturn(SETTINGS_PACKAGE_NAME)
         systemClock = FakeSystemClock()
         backgroundDelayableExecutor = FakeExecutor(systemClock)
 
@@ -100,6 +104,7 @@
                 keyguardStateController,
                 mDialogTransitionAnimator,
                 { fontScalingDialogDelegate },
+                settingsPackageRepository,
             )
         fontScalingTile.initialize()
         testableLooper.processAllMessages()
@@ -120,7 +125,7 @@
 
     @Test
     fun clickTile_screenUnlocked_showDialogAnimationFromView() {
-        `when`(keyguardStateController.isShowing).thenReturn(false)
+        whenever(keyguardStateController.isShowing).thenReturn(false)
         fontScalingTile.click(expandable)
         testableLooper.processAllMessages()
 
@@ -130,7 +135,7 @@
                 eq(null),
                 eq(true),
                 eq(true),
-                eq(false)
+                eq(false),
             )
         argumentCaptor.value.run()
         verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean())
@@ -138,7 +143,7 @@
 
     @Test
     fun clickTile_onLockScreen_neverShowDialogAnimationFromView() {
-        `when`(keyguardStateController.isShowing).thenReturn(true)
+        whenever(keyguardStateController.isShowing).thenReturn(true)
         fontScalingTile.click(expandable)
         testableLooper.processAllMessages()
 
@@ -148,7 +153,7 @@
                 eq(null),
                 eq(true),
                 eq(true),
-                eq(false)
+                eq(false),
             )
         argumentCaptor.value.run()
         verify(mDialogTransitionAnimator, never()).show(any(), any(), anyBoolean())
@@ -159,5 +164,10 @@
         val intent: Intent? = fontScalingTile.getLongClickIntent()
 
         assertThat(intent!!.action).isEqualTo(Settings.ACTION_TEXT_READING_SETTINGS)
+        assertThat(intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME)
+    }
+
+    companion object {
+        private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index 5c6657b..cfbc812 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -1,6 +1,6 @@
 package com.android.systemui.qs.tiles.dialog;
 
-import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
+import static com.android.systemui.qs.tiles.dialog.InternetDetailsContentController.MAX_WIFI_ENTRY_COUNT;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -63,7 +63,7 @@
     @Mock
     private WifiEntry mWifiEntry;
     @Mock
-    private InternetDialogController mInternetDialogController;
+    private InternetDetailsContentController mInternetDetailsContentController;
     @Mock
     private Drawable mWifiDrawable;
     @Mock
@@ -86,7 +86,7 @@
         when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
         when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
 
-        mInternetAdapter = new InternetAdapter(mInternetDialogController, mScope);
+        mInternetAdapter = new InternetAdapter(mInternetDetailsContentController, mScope);
         mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0);
         mInternetAdapter.setWifiEntries(Arrays.asList(mWifiEntry), 1 /* wifiEntriesCount */);
     }
@@ -124,7 +124,7 @@
 
     @Test
     public void onBindViewHolder_getWifiDrawableNull_noCrash() {
-        when(mInternetDialogController.getWifiDrawable(any())).thenReturn(null);
+        when(mInternetDetailsContentController.getWifiDrawable(any())).thenReturn(null);
 
         mInternetAdapter.onBindViewHolder(mViewHolder, 0);
 
@@ -133,7 +133,7 @@
 
     @Test
     public void onBindViewHolder_getWifiDrawableNotNull_setWifiIconDrawable() {
-        when(mInternetDialogController.getWifiDrawable(any())).thenReturn(mWifiDrawable);
+        when(mInternetDetailsContentController.getWifiDrawable(any())).thenReturn(mWifiDrawable);
 
         mInternetAdapter.onBindViewHolder(mViewHolder, 0);
 
@@ -232,7 +232,7 @@
 
         mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
 
-        verify(mInternetDialogController).startActivityForDialog(any());
+        verify(mInternetDetailsContentController).startActivityForDialog(any());
         verify(mSpyContext, never()).startActivity(any());
     }
 
@@ -242,7 +242,7 @@
 
         mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
 
-        verify(mInternetDialogController).connect(mWifiEntry);
+        verify(mInternetDetailsContentController).connect(mWifiEntry);
     }
 
     @Test
@@ -252,7 +252,7 @@
 
         mViewHolder.onWifiClick(mWifiEntry, mock(View.class));
 
-        verify(mInternetDialogController).launchWifiDetailsSetting(anyString(), any());
+        verify(mInternetDetailsContentController).launchWifiDetailsSetting(anyString(), any());
     }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
index 3bc53b27..0cf3734 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
@@ -23,29 +23,45 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
 import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
 import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() {
 
+    @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository
+
     private val testUser = UserHandle.CURRENT
     private val repository = FakeColorCorrectionRepository()
     private val inputHandler = FakeQSTileIntentUserInputHandler()
 
-    private val underTest =
-        ColorCorrectionUserActionInteractor(
-            repository,
-            inputHandler,
-        )
+    private lateinit var underTest: ColorCorrectionUserActionInteractor
+
+    @Before
+    fun setUp() {
+        whenever(settingsPackageRepository.getSettingsPackageName())
+            .thenReturn(SETTINGS_PACKAGE_NAME)
+
+        underTest =
+            ColorCorrectionUserActionInteractor(repository, inputHandler, settingsPackageRepository)
+    }
 
     @Test
     fun handleClickWhenEnabled() = runTest {
@@ -86,6 +102,11 @@
 
         QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
             assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+            assertThat(it.intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME)
         }
     }
+
+    companion object {
+        private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt
index d309554..9bd4895 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.actions.intentInputs
 import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
@@ -36,11 +37,7 @@
 import com.android.systemui.qs.tiles.impl.fontscaling.domain.model.FontScalingTileModel
 import com.android.systemui.statusbar.phone.FakeKeyguardStateController
 import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -51,15 +48,14 @@
 import org.mockito.Mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class FontScalingUserActionInteractorTest : SysuiTestCase() {
-    private val kosmos = Kosmos()
-    private val qsTileIntentUserActionHandler = FakeQSTileIntentUserInputHandler()
-    private val keyguardStateController = FakeKeyguardStateController()
-
-    private lateinit var underTest: FontScalingTileUserActionInteractor
 
     @Mock private lateinit var fontScalingDialogDelegate: FontScalingDialogDelegate
     @Mock private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator
@@ -67,35 +63,47 @@
     @Mock private lateinit var activityStarter: ActivityStarter
     @Mock private lateinit var expandable: Expandable
     @Mock private lateinit var controller: DialogTransitionAnimator.Controller
+    @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository
 
     @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable>
 
+    private val kosmos = Kosmos()
+    private val scope = kosmos.testScope
+    private val qsTileIntentUserActionHandler = FakeQSTileIntentUserInputHandler()
+    private val keyguardStateController = FakeKeyguardStateController()
+
+    private lateinit var underTest: FontScalingTileUserActionInteractor
+
     @Before
     fun setup() {
         activityStarter = mock<ActivityStarter>()
         mDialogTransitionAnimator = mock<DialogTransitionAnimator>()
         dialog = mock<SystemUIDialog>()
-        fontScalingDialogDelegate =
-            mock<FontScalingDialogDelegate> { whenever(createDialog()).thenReturn(dialog) }
+        fontScalingDialogDelegate = mock<FontScalingDialogDelegate>()
+        whenever(fontScalingDialogDelegate.createDialog()).thenReturn(dialog)
         controller = mock<DialogTransitionAnimator.Controller>()
-        expandable =
-            mock<Expandable> { whenever(dialogTransitionController(any())).thenReturn(controller) }
+        expandable = mock<Expandable>()
+        whenever(expandable.dialogTransitionController(any())).thenReturn(controller)
+        settingsPackageRepository = mock<QSSettingsPackageRepository>()
+        whenever(settingsPackageRepository.getSettingsPackageName())
+            .thenReturn(SETTINGS_PACKAGE_NAME)
         argumentCaptor = ArgumentCaptor.forClass(Runnable::class.java)
 
         underTest =
             FontScalingTileUserActionInteractor(
-                kosmos.testScope.coroutineContext,
+                scope.coroutineContext,
                 qsTileIntentUserActionHandler,
                 { fontScalingDialogDelegate },
                 keyguardStateController,
                 mDialogTransitionAnimator,
-                activityStarter
+                activityStarter,
+                settingsPackageRepository,
             )
     }
 
     @Test
     fun clickTile_screenUnlocked_showDialogAnimationFromView() =
-        kosmos.testScope.runTest {
+        scope.runTest {
             keyguardStateController.isShowing = false
 
             underTest.handleInput(click(FontScalingTileModel, expandable = expandable))
@@ -106,7 +114,7 @@
                     eq(null),
                     eq(true),
                     eq(true),
-                    eq(false)
+                    eq(false),
                 )
             argumentCaptor.value.run()
             verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean())
@@ -114,7 +122,7 @@
 
     @Test
     fun clickTile_onLockScreen_neverShowDialogAnimationFromView_butShowsDialog() =
-        kosmos.testScope.runTest {
+        scope.runTest {
             keyguardStateController.isShowing = true
 
             underTest.handleInput(click(FontScalingTileModel, expandable = expandable))
@@ -125,7 +133,7 @@
                     eq(null),
                     eq(true),
                     eq(true),
-                    eq(false)
+                    eq(false),
                 )
             argumentCaptor.value.run()
             verify(mDialogTransitionAnimator, never()).show(any(), any(), anyBoolean())
@@ -134,17 +142,20 @@
 
     @Test
     fun handleLongClick() =
-        kosmos.testScope.runTest {
+        scope.runTest {
             underTest.handleInput(QSTileInputTestKtx.longClick(FontScalingTileModel))
 
-            Truth.assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1)
-            val intentInput = qsTileIntentUserActionHandler.intentInputs.last()
-            val actualIntentAction = intentInput.intent.action
-            val expectedIntentAction = Settings.ACTION_TEXT_READING_SETTINGS
-            Truth.assertThat(actualIntentAction).isEqualTo(expectedIntentAction)
+            assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1)
+            val it = qsTileIntentUserActionHandler.intentInputs.last()
+            assertThat(it.intent.action).isEqualTo(Settings.ACTION_TEXT_READING_SETTINGS)
+            assertThat(it.intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME)
         }
 
     private class FontScalingTileTestView(context: Context) : View(context), LaunchableView {
         override fun setShouldBlockVisibilityChanges(block: Boolean) {}
     }
+
+    companion object {
+        private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
index f574f79..3f77b86 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
@@ -23,29 +23,45 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.accessibility.data.repository.FakeColorInversionRepository
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
 import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
 import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class ColorInversionUserActionInteractorTest : SysuiTestCase() {
 
+    @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository
+
     private val testUser = UserHandle.CURRENT
     private val repository = FakeColorInversionRepository()
     private val inputHandler = FakeQSTileIntentUserInputHandler()
 
-    private val underTest =
-        ColorInversionUserActionInteractor(
-            repository,
-            inputHandler,
-        )
+    private lateinit var underTest: ColorInversionUserActionInteractor
+
+    @Before
+    fun setUp() {
+        whenever(settingsPackageRepository.getSettingsPackageName())
+            .thenReturn(SETTINGS_PACKAGE_NAME)
+
+        underTest =
+            ColorInversionUserActionInteractor(repository, inputHandler, settingsPackageRepository)
+    }
 
     @Test
     fun handleClickWhenEnabled() = runTest {
@@ -86,6 +102,11 @@
 
         QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
             assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_INVERSION_SETTINGS)
+            assertThat(it.intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME)
         }
     }
+
+    companion object {
+        private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerStateTest.kt
new file mode 100644
index 0000000..e68045f
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerStateTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ui.compose
+
+import android.text.format.DateUtils.formatElapsedTime
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ChronometerStateTest : SysuiTestCase() {
+
+    private lateinit var mockTimeSource: MutableTimeSource
+
+    @Before
+    fun setup() {
+        mockTimeSource = MutableTimeSource()
+    }
+
+    @Test
+    fun initialText_isCorrect() = runTest {
+        val state = ChronometerState(mockTimeSource, 0L)
+        assertThat(state.currentTimeText).isEqualTo(formatElapsedTime(0))
+    }
+
+    @Test
+    fun textUpdates_withTime() = runTest {
+        val startTime = 1000L
+        val state = ChronometerState(mockTimeSource, startTime)
+        val job = launch { state.run() }
+
+        val elapsedTime = 5000L
+        mockTimeSource.time = startTime + elapsedTime
+        advanceTimeBy(elapsedTime)
+        assertThat(state.currentTimeText).isEqualTo(formatElapsedTime(elapsedTime / 1000))
+
+        job.cancelAndJoin()
+    }
+
+    @Test
+    fun textUpdates_toLargerValue() = runTest {
+        val startTime = 1000L
+        val state = ChronometerState(mockTimeSource, startTime)
+        val job = launch { state.run() }
+
+        val elapsedTime = 15000L
+        mockTimeSource.time = startTime + elapsedTime
+        advanceTimeBy(elapsedTime)
+        assertThat(state.currentTimeText).isEqualTo(formatElapsedTime(elapsedTime / 1000))
+
+        job.cancelAndJoin()
+    }
+
+    @Test
+    fun textUpdates_afterResettingBase() = runTest {
+        val initialElapsedTime = 30000L
+        val startTime = 50000L
+        val state = ChronometerState(mockTimeSource, startTime)
+        val job = launch { state.run() }
+
+        mockTimeSource.time = startTime + initialElapsedTime
+        advanceTimeBy(initialElapsedTime)
+        assertThat(state.currentTimeText).isEqualTo(formatElapsedTime(initialElapsedTime / 1000))
+
+        job.cancelAndJoin()
+
+        val newElapsedTime = 5000L
+        val newStartTime = 100000L
+        val newState = ChronometerState(mockTimeSource, newStartTime)
+        val newJob = launch { newState.run() }
+
+        mockTimeSource.time = newStartTime + newElapsedTime
+        advanceTimeBy(newElapsedTime)
+        assertThat(newState.currentTimeText).isEqualTo(formatElapsedTime(newElapsedTime / 1000))
+
+        newJob.cancelAndJoin()
+    }
+}
+
+/** A fake implementation of [TimeSource] that allows the caller to set the current time */
+class MutableTimeSource(var time: Long = 0L) : TimeSource {
+    override fun getCurrentTime(): Long {
+        return time
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
index 009b33b..3515c56 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
@@ -26,10 +26,12 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.fragments.FragmentHostManager
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.plugins.fakeDarkIconDispatcher
 import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
 import com.android.systemui.statusbar.pipeline.shared.ui.composable.StatusBarRootFactory
+import com.android.systemui.statusbar.policy.statusBarConfigurationController
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.testKosmos
@@ -77,6 +79,8 @@
             componentFactory = mock(HomeStatusBarComponent.Factory::class.java),
             creationListeners = setOf(),
             statusBarModePerDisplayRepository = statusBarModePerDisplayRepository,
+            darkIconDispatcher = kosmos.fakeDarkIconDispatcher,
+            statusBarConfigurationController = kosmos.statusBarConfigurationController,
         )
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
index 18eef33..884c35c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
@@ -51,7 +51,7 @@
     @Test
     fun forDisplay_startsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance).start()
         }
@@ -59,7 +59,7 @@
     @Test
     fun beforeDisplayRemoved_doesNotStopInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance, never()).stop()
         }
@@ -67,7 +67,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
index a2c3c66..f37648a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
@@ -56,7 +56,7 @@
     @Test
     fun beforeDisplayRemoved_doesNotStopInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance, never()).stop()
         }
@@ -64,7 +64,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
index 4a26fdf..e0a1f27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
@@ -51,7 +51,7 @@
     @Test
     fun forDisplay_startsInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance).start()
         }
@@ -59,7 +59,7 @@
     @Test
     fun beforeDisplayRemoved_doesNotStopInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance, never()).stop()
         }
@@ -67,7 +67,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
index a9920ec5..11fd902 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
@@ -53,7 +53,7 @@
     @Test
     fun forDisplay_startsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance).start()
         }
@@ -61,7 +61,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
index e65c04c..3cc592c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
@@ -56,7 +56,7 @@
     @Test
     fun beforeDisplayRemoved_doesNotStopInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance, never()).stop()
         }
@@ -64,7 +64,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt
index d38fb50..5f154ac 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt
@@ -48,7 +48,7 @@
 import com.android.systemui.statusbar.notification.domain.interactor.lockScreenShowOnlyUnseenNotificationsSetting
 import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
 import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.testKosmos
 import com.android.systemui.util.settings.FakeSettings
@@ -625,7 +625,7 @@
         val keyguardCoordinator =
             OriginalUnseenKeyguardCoordinator(
                 dumpManager = kosmos.dumpManager,
-                headsUpManager = kosmos.headsUpManager,
+                headsUpManager = kosmos.mockHeadsUpManager,
                 keyguardRepository = kosmos.keyguardRepository,
                 keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
                 logger = KeyguardCoordinatorLogger(logcatLogBuffer()),
@@ -663,7 +663,8 @@
 
         val onHeadsUpChangedListener: OnHeadsUpChangedListener
             get() =
-                argumentCaptor { verify(kosmos.headsUpManager).addListener(capture()) }.lastValue
+                argumentCaptor { verify(kosmos.mockHeadsUpManager).addListener(capture()) }
+                    .lastValue
     }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index be20bc1..d86c6ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -225,7 +225,7 @@
             val displayId = 123
             darkIconRepository.darkState(displayId).value =
                 SysuiDarkIconDispatcher.DarkChange(emptyList(), 0f, 0xAABBCC)
-            val iconColors by collectLastValue(underTest.iconColors(displayId))
+            val iconColors by collectLastValue(underTest.iconColors(displayId)!!)
             assertThat(iconColors).isNotNull()
 
             assertThat(iconColors!!.tint).isEqualTo(0xAABBCC)
@@ -241,7 +241,7 @@
             val displayId = 321
             darkIconRepository.darkState(displayId).value =
                 SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC)
-            val iconColors by collectLastValue(underTest.iconColors(displayId))
+            val iconColors by collectLastValue(underTest.iconColors(displayId)!!)
             val staticDrawableColor = iconColors?.staticDrawableColor(Rect(6, 6, 7, 7))
             assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
         }
@@ -252,7 +252,7 @@
             val displayId = 987
             darkIconRepository.darkState(displayId).value =
                 SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC)
-            val iconColors by collectLastValue(underTest.iconColors(displayId))
+            val iconColors by collectLastValue(underTest.iconColors(displayId)!!)
             assertThat(iconColors!!.staticDrawableColor(Rect(6, 6, 7, 7)))
                 .isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 87abd0a..256da253 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism
+import com.android.systemui.statusbar.notification.shelf.NotificationShelfIconContainer
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState
 import com.android.systemui.util.mockito.mock
 import junit.framework.Assert.assertEquals
@@ -134,89 +135,208 @@
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testAlignment_splitShade_LTR() {
         // Given: LTR mode, split shade
+        val width = 100
+        val actualWidth = 40
+        val iconContainerPadding = 16f
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = false, splitShade = true, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = false,
+                splitShade = true,
+                width = width,
+                actualWidth = actualWidth,
+                iconContainerPadding = iconContainerPadding,
+            )
 
         // Then: shelf should align to end
         assertTrue(shelfSpy.isAlignedToEnd)
         assertTrue(shelfSpy.isAlignedToRight)
         assertTrue(shelfSpy.mBackgroundNormal.alignToEnd)
-        assertTrue(shelfSpy.mShelfIcons.alignToEnd)
+
+        // Then: icon container should align to end, right
+        val iconContainer = shelfSpy.shelfIcons as NotificationShelfIconContainer
+        assertTrue(iconContainer.alignToEnd)
+        assertTrue(iconContainer.isAlignedToRight)
+
+        // Then: icon container bounds are updated based on the widths and paddings
+        val actualPaddingStart = iconContainerPadding
+        val actualPaddingEnd = iconContainerPadding
+        val expectedLeftBound = width - actualWidth + actualPaddingStart
+        val expectedRightBound = width - actualPaddingEnd
+        assertEquals(expectedLeftBound, iconContainer.leftBound)
+        assertEquals(expectedRightBound, iconContainer.rightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testAlignment_nonSplitShade_LTR() {
         // Given: LTR mode, non split shade
+        val width = 100
+        val actualWidth = 40
+        val iconContainerPadding = 16f
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = false, splitShade = false, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = false,
+                splitShade = false,
+                width = width,
+                actualWidth = actualWidth,
+                iconContainerPadding = iconContainerPadding,
+            )
 
         // Then: shelf should not align to end
+        // left bound of icon container should be 16f (actualPaddingStart)
+        // right bound of icon container should be 24f (actualWidth - actualPaddingEnd)
         assertFalse(shelfSpy.isAlignedToEnd)
         assertFalse(shelfSpy.isAlignedToRight)
         assertFalse(shelfSpy.mBackgroundNormal.alignToEnd)
-        assertFalse(shelfSpy.mShelfIcons.alignToEnd)
+
+        // Then: icon container should align to start, left
+
+        val iconContainer = shelfSpy.shelfIcons as NotificationShelfIconContainer
+        assertFalse(iconContainer.alignToEnd)
+        assertFalse(iconContainer.isAlignedToRight)
+
+        // Then: icon container bounds are updated based on the widths and paddings
+        val actualPaddingStart = iconContainerPadding
+        val actualPaddingEnd = iconContainerPadding
+        val expectedLeftBound = actualPaddingStart
+        val expectedRightBound = actualWidth - actualPaddingEnd
+        assertEquals(expectedLeftBound, iconContainer.leftBound)
+        assertEquals(expectedRightBound, iconContainer.rightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testAlignment_splitShade_RTL() {
         // Given: RTL mode, split shade
+        val width = 100
+        val actualWidth = 40
+        val iconContainerPadding = 16f
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = true, splitShade = true, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = true,
+                splitShade = true,
+                width = width,
+                actualWidth = actualWidth,
+                iconContainerPadding = iconContainerPadding,
+            )
 
         // Then: shelf should align to end, but to left due to RTL
+        // left bound of icon container should be 16f (actualPaddingStart)
+        // right bound of icon container should be 24f (actualWidth - actualPaddingEnd)
         assertTrue(shelfSpy.isAlignedToEnd)
         assertFalse(shelfSpy.isAlignedToRight)
         assertTrue(shelfSpy.mBackgroundNormal.alignToEnd)
-        assertTrue(shelfSpy.mShelfIcons.alignToEnd)
+
+        // Then: icon container should align to end, left
+        val iconContainer = shelfSpy.shelfIcons as NotificationShelfIconContainer
+        assertTrue(iconContainer.alignToEnd)
+        assertFalse(iconContainer.isAlignedToRight)
+
+        // Then: icon container bounds are updated based on the widths and paddings
+        val actualPaddingStart = iconContainerPadding
+        val actualPaddingEnd = iconContainerPadding
+        val expectedLeftBound = actualPaddingStart
+        val expectedRightBound = actualWidth - actualPaddingEnd
+        assertEquals(expectedLeftBound, iconContainer.leftBound)
+        assertEquals(expectedRightBound, iconContainer.rightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testAlignment_nonSplitShade_RTL() {
         // Given: RTL mode, non split shade
+        val width = 100
+        val actualWidth = 40
+        val iconContainerPadding = 16f
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = true, splitShade = false, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = true,
+                splitShade = false,
+                width = width,
+                actualWidth = actualWidth,
+                iconContainerPadding = iconContainerPadding,
+            )
 
         // Then: shelf should not align to end, but to right due to RTL
         assertFalse(shelfSpy.isAlignedToEnd)
         assertTrue(shelfSpy.isAlignedToRight)
         assertFalse(shelfSpy.mBackgroundNormal.alignToEnd)
-        assertFalse(shelfSpy.mShelfIcons.alignToEnd)
+
+        // Then: icon container should align to start, right
+        val iconContainer = shelfSpy.shelfIcons as NotificationShelfIconContainer
+        assertFalse(iconContainer.alignToEnd)
+        assertTrue(iconContainer.isAlignedToRight)
+
+        // Then: icon container bounds are updated based on the widths and paddings
+        val actualPaddingStart = iconContainerPadding
+        val actualPaddingEnd = iconContainerPadding
+        val expectedLeftBound = width - actualWidth + actualPaddingStart
+        val expectedRightBound = width - actualPaddingEnd
+        assertEquals(expectedLeftBound, iconContainer.leftBound)
+        assertEquals(expectedRightBound, iconContainer.rightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfLeftBound_splitShade_LTR() {
         // Given: LTR mode, split shade
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = false, splitShade = true, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = false,
+                splitShade = true,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // When: get the left bound of the shelf
         val shelfLeftBound = shelfSpy.shelfLeftBound
 
         // Then: should be equal to shelf's width - actual width
-        assertEquals(60f, shelfLeftBound)
+        val expectedLeftBound = (width - actualWidth).toFloat()
+        assertEquals(expectedLeftBound, shelfLeftBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfRightBound_splitShade_LTR() {
         // Given: LTR mode, split shade, width 100, actual width 40
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = false, splitShade = true, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = false,
+                splitShade = true,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // Then: the right bound of the shelf should be equal to shelf's width
-        assertEquals(100f, shelfSpy.shelfRightBound)
+        val expectedRightBound = width.toFloat()
+        assertEquals(expectedRightBound, shelfSpy.shelfRightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfLeftBound_nonSplitShade_LTR() {
         // Given: LTR mode, non split shade
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = false, splitShade = false, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = false,
+                splitShade = false,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // When: get the left bound of the shelf
         val shelfLeftBound = shelfSpy.shelfLeftBound
@@ -229,19 +349,35 @@
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfRightBound_nonSplitShade_LTR() {
         // Given: LTR mode, non split shade, width 100, actual width 40
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = false, splitShade = false, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = false,
+                splitShade = false,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // Then: the right bound of the shelf should be equal to shelf's actual width
-        assertEquals(40f, shelfSpy.shelfRightBound)
+        assertEquals(actualWidth.toFloat(), shelfSpy.shelfRightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfLeftBound_splitShade_RTL() {
         // Given: RTL mode, split shade
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = true, splitShade = true, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = true,
+                splitShade = true,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // When: get the left bound of the shelf
         val shelfLeftBound = shelfSpy.shelfLeftBound
@@ -254,36 +390,61 @@
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfRightBound_splitShade_RTL() {
         // Given: RTL mode, split shade, width 100, actual width 40
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = true, splitShade = true, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = true,
+                splitShade = true,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // Then: the right bound of the shelf should be equal to shelf's actual width
-        assertEquals(40f, shelfSpy.shelfRightBound)
+        assertEquals(actualWidth.toFloat(), shelfSpy.shelfRightBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfLeftBound_nonSplitShade_RTL() {
         // Given: RTL mode, non split shade
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = true, splitShade = false, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = true,
+                splitShade = false,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // When: get the left bound of the shelf
         val shelfLeftBound = shelfSpy.shelfLeftBound
 
         // Then: should be equal to shelf's width - actual width
-        assertEquals(60f, shelfLeftBound)
+        val expectedLeftBound = (width - actualWidth).toFloat()
+        assertEquals(expectedLeftBound, shelfLeftBound)
     }
 
     @Test
     @EnableFlags(NotificationMinimalism.FLAG_NAME)
     fun testGetShelfRightBound_nonSplitShade_RTL() {
         // Given: LTR mode, non split shade, width 100, actual width 40
+        val width = 100
+        val actualWidth = 40
         val shelfSpy =
-            prepareShelfSpy(shelf, rtl = true, splitShade = false, width = 100, actualWidth = 40)
+            prepareShelfSpy(
+                shelf,
+                rtl = true,
+                splitShade = false,
+                width = width,
+                actualWidth = actualWidth,
+            )
 
         // Then: the right bound of the shelf should be equal to shelf's width
-        assertEquals(100f, shelfSpy.shelfRightBound)
+        assertEquals(width.toFloat(), shelfSpy.shelfRightBound)
     }
 
     private fun prepareShelfSpy(
@@ -292,12 +453,23 @@
         splitShade: Boolean,
         width: Int,
         actualWidth: Int,
+        iconContainerPadding: Float? = null,
     ): NotificationShelf {
         val shelfSpy = spy(shelf)
         whenever(shelfSpy.isLayoutRtl).thenReturn(rtl)
         whenever(ambientState.useSplitShade).thenReturn(splitShade)
-        whenever(shelfSpy.width).thenReturn(width)
+        shelfSpy.layout(0, 0, width, 5)
+        shelfSpy.mShelfIcons.layout(0, 0, width, 5)
+        iconContainerPadding?.let {
+            shelfSpy.mShelfIcons.actualPaddingStart = it
+            shelfSpy.mShelfIcons.setActualPaddingEnd(it)
+        }
         shelfSpy.setActualWidth(actualWidth.toFloat())
+
+        val iconContainerSpy = spy(shelf.mShelfIcons)
+        whenever(iconContainerSpy.isLayoutRtl).thenReturn(rtl)
+        whenever(shelfSpy.shelfIcons).thenReturn(iconContainerSpy)
+
         return shelfSpy
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
index f4c2545..216f51d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
@@ -38,7 +38,7 @@
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor
 import com.android.systemui.statusbar.notification.headsup.PinnedStatus
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation
@@ -75,7 +75,7 @@
     private val keyguardStateController = kosmos.keyguardStateController
     private val commandQueue = kosmos.commandQueue
     private val notificationRoundnessManager = mock<NotificationRoundnessManager>()
-    private var headsUpManager = kosmos.headsUpManager
+    private var headsUpManager = kosmos.mockHeadsUpManager
 
     private lateinit var testHelper: NotificationTestHelper
     private lateinit var row: ExpandableNotificationRow
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
index 90506a1..d163726 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
@@ -56,7 +56,7 @@
     @Test
     fun beforeDisplayRemoved_doesNotStopInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance, never()).stop()
         }
@@ -64,7 +64,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
index 2d9880a..659d91a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
@@ -39,7 +39,7 @@
     fun isLowProfile_lightsOutStatusBarMode_false() = runTest {
         statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.LIGHTS_OUT
 
-        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID)!!)
 
         assertThat(actual).isTrue()
     }
@@ -49,7 +49,7 @@
         statusBarModeRepository.defaultDisplay.statusBarMode.value =
             StatusBarMode.LIGHTS_OUT_TRANSPARENT
 
-        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID)!!)
 
         assertThat(actual).isTrue()
     }
@@ -58,7 +58,7 @@
     fun isLowProfile_transparentStatusBarMode_false() = runTest {
         statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
 
-        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID)!!)
 
         assertThat(actual).isFalse()
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
index 7a9d017..769f012 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -53,7 +53,7 @@
     @Test
     fun beforeDisplayRemoved_doesNotStopInstances() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             verify(instance, never()).stop()
         }
@@ -61,7 +61,7 @@
     @Test
     fun displayRemoved_stopsInstance() =
         testScope.runTest {
-            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
             fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt
index 8972f3e..8b526bb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt
@@ -30,12 +30,14 @@
 import com.android.systemui.touchpad.ui.gesture.FakeVelocityTracker
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
 
 @SmallTest
+@Ignore("b/386412866")
 @RunWith(ParameterizedAndroidJunit4::class)
 class ThreeFingerGestureRecognizerTest(
     private val recognizer: GestureRecognizer,
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index bad5711..3270759 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -33,15 +33,25 @@
         app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
         app:layout_constraintTop_toTopOf="@id/volume_ringer_drawer" />
 
+    <View
+        android:id="@+id/volume_ringer_horizontal_background"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:background="@drawable/volume_dialog_background"
+        app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toEndOf="@id/volume_ringer_drawer"
+        app:layout_constraintStart_toStartOf="@id/volume_ringer_drawer"
+        app:layout_constraintTop_toTopOf="@id/volume_dialog_background" />
+
     <include
         android:id="@id/volume_ringer_drawer"
         layout="@layout/volume_ringer_drawer"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
+        android:layout_marginRight="@dimen/volume_dialog_ringer_drawer_diff_right_margin"
         app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
         app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
-        app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintVertical_bias="1" />
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6994a55..11327b6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -2116,6 +2116,8 @@
 
     <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
 
+    <dimen name="volume_dialog_ringer_drawer_left_margin">10dp</dimen>
+    <dimen name="volume_dialog_ringer_drawer_diff_right_margin">6dp</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_size">@dimen/volume_dialog_button_size</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
     <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 41b9d33..5f0acfa 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -19,6 +19,7 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
@@ -35,6 +36,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode;
 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
@@ -61,6 +63,7 @@
     private final ViewCaptureAwareWindowManager mViewCaptureAwareWindowManager;
     private final DisplayManager mDisplayManager;
     private final AccessibilityManager mAccessibilityManager;
+    private final HearingAidDeviceManager mHearingAidDeviceManager;
 
     private final SecureSettings mSecureSettings;
     private final DisplayTracker mDisplayTracker;
@@ -107,6 +110,7 @@
             AccessibilityManager accessibilityManager,
             AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
             AccessibilityButtonModeObserver accessibilityButtonModeObserver,
+            @Nullable HearingAidDeviceManager hearingAidDeviceManager,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             SecureSettings secureSettings,
             DisplayTracker displayTracker,
@@ -119,6 +123,7 @@
         mAccessibilityManager = accessibilityManager;
         mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
         mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
+        mHearingAidDeviceManager = hearingAidDeviceManager;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mSecureSettings = secureSettings;
         mDisplayTracker = displayTracker;
@@ -201,7 +206,7 @@
                     TYPE_NAVIGATION_BAR_PANEL, /* options= */ null);
             mFloatingMenu = new MenuViewLayerController(windowContext, mWindowManager,
                     mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
-                    mNavigationModeController);
+                    mNavigationModeController, mHearingAidDeviceManager);
         }
 
         mFloatingMenu.show();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
index ffb5f3d..121b51f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
@@ -30,6 +30,7 @@
 
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -49,6 +50,8 @@
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Prefs;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -80,8 +83,11 @@
     private final AccessibilityManager mAccessibilityManager;
     private final AccessibilityManager.AccessibilityServicesStateChangeListener
             mA11yServicesStateChangeListener = manager -> onTargetFeaturesChanged();
+    private final HearingAidDeviceManager mHearingAidDeviceManager;
+    private final HearingAidDeviceManager.ConnectionStatusListener
+            mHearingDeviceStatusListener = this::onDevicesConnectionStatusChanged;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
-    private final OnSettingsContentsChanged mSettingsContentsCallback;
+    private final OnContentsChanged mSettingsContentsCallback;
     private final SecureSettings mSecureSettings;
     private Position mPercentagePosition;
 
@@ -148,12 +154,14 @@
     };
 
     MenuInfoRepository(Context context, AccessibilityManager accessibilityManager,
-            OnSettingsContentsChanged settingsContentsChanged, SecureSettings secureSettings) {
+            OnContentsChanged settingsContentsChanged, SecureSettings secureSettings,
+            @Nullable HearingAidDeviceManager hearingAidDeviceManager) {
         mContext = context;
         mAccessibilityManager = accessibilityManager;
         mConfiguration = new Configuration(context.getResources().getConfiguration());
         mSettingsContentsCallback = settingsContentsChanged;
         mSecureSettings = secureSettings;
+        mHearingAidDeviceManager = hearingAidDeviceManager;
 
         mPercentagePosition = getStartPosition();
     }
@@ -185,6 +193,14 @@
         callback.onReady(getTargets(mContext, SOFTWARE));
     }
 
+    void loadHearingDeviceStatus(OnInfoReady<Integer> callback) {
+        if (mHearingAidDeviceManager != null) {
+            callback.onReady(mHearingAidDeviceManager.getDevicesConnectionStatus());
+        } else {
+            callback.onReady(HearingAidDeviceManager.ConnectionStatus.NO_DEVICE_BONDED);
+        }
+    }
+
     void loadMenuSizeType(OnInfoReady<Integer> callback) {
         callback.onReady(getMenuSizeTypeFromSettings());
     }
@@ -222,8 +238,8 @@
     }
 
     private void onTargetFeaturesChanged() {
-        mSettingsContentsCallback.onTargetFeaturesChanged(
-                getTargets(mContext, SOFTWARE));
+        List<AccessibilityTarget> targets = getTargets(mContext, SOFTWARE);
+        mSettingsContentsCallback.onTargetFeaturesChanged(targets);
     }
 
     private Position getStartPosition() {
@@ -269,6 +285,24 @@
             mAccessibilityManager.addAccessibilityServicesStateChangeListener(
                     mA11yServicesStateChangeListener);
         }
+
+        if (com.android.settingslib.flags.Flags.hearingDeviceSetConnectionStatusReport()) {
+            registerConnectionStatusListener();
+        }
+    }
+
+    private void registerConnectionStatusListener() {
+        if (mHearingAidDeviceManager != null) {
+            mHearingAidDeviceManager.registerConnectionStatusListener(
+                    mHearingDeviceStatusListener, ThreadUtils.getBackgroundExecutor());
+        }
+    }
+
+    private void unregisterConnectionStatusListener() {
+        if (mHearingAidDeviceManager != null) {
+            mHearingAidDeviceManager.unregisterConnectionStatusListener(
+                    mHearingDeviceStatusListener);
+        }
     }
 
     void unregisterObserversAndCallbacks() {
@@ -281,14 +315,18 @@
             mAccessibilityManager.removeAccessibilityServicesStateChangeListener(
                     mA11yServicesStateChangeListener);
         }
+
+        unregisterConnectionStatusListener();
     }
 
-    interface OnSettingsContentsChanged {
+    interface OnContentsChanged {
         void onTargetFeaturesChanged(List<AccessibilityTarget> newTargetFeatures);
 
         void onSizeTypeChanged(int newSizeType);
 
         void onFadeEffectInfoChanged(MenuFadeEffectInfo fadeEffectInfo);
+
+        void onDevicesConnectionStatusChanged(@HearingAidDeviceManager.ConnectionStatus int status);
     }
 
     interface OnInfoReady<T> {
@@ -311,4 +349,9 @@
                 ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_OPACITY_VALUE,
                 UserHandle.USER_CURRENT);
     }
+
+    private void onDevicesConnectionStatusChanged(
+            @HearingAidDeviceManager.ConnectionStatus int status) {
+        mSettingsContentsCallback.onDevicesConnectionStatusChanged(status);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 9d9e7df..23fc546 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -37,6 +37,7 @@
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.modules.expresslog.Counter;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Flags;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -65,8 +66,11 @@
     private final Observer<Integer> mSizeTypeObserver = this::onSizeTypeChanged;
     private final Observer<List<AccessibilityTarget>> mTargetFeaturesObserver =
             this::onTargetFeaturesChanged;
+    private final Observer<Integer> mHearingDeviceStatusObserver =
+            this::updateHearingDeviceStatus;
+    private final Observer<Integer> mHearingDeviceTargetIndexObserver =
+            this::updateHearingDeviceTargetIndex;
     private final MenuViewAppearance mMenuViewAppearance;
-
     private boolean mIsMoveToTucked;
 
     private final MenuAnimationController mMenuAnimationController;
@@ -357,6 +361,11 @@
         mMenuViewModel.getTargetFeaturesData().observeForever(mTargetFeaturesObserver);
         mMenuViewModel.getSizeTypeData().observeForever(mSizeTypeObserver);
         mMenuViewModel.getMoveToTuckedData().observeForever(mMoveToTuckedObserver);
+        if (com.android.settingslib.flags.Flags.hearingDeviceSetConnectionStatusReport()) {
+            mMenuViewModel.loadHearingDeviceStatus().observeForever(mHearingDeviceStatusObserver);
+            mMenuViewModel.getHearingDeviceTargetIndexData().observeForever(
+                    mHearingDeviceTargetIndexObserver);
+        }
         setVisibility(VISIBLE);
         mMenuViewModel.registerObserversAndCallbacks();
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
@@ -371,6 +380,9 @@
         mMenuViewModel.getTargetFeaturesData().removeObserver(mTargetFeaturesObserver);
         mMenuViewModel.getSizeTypeData().removeObserver(mSizeTypeObserver);
         mMenuViewModel.getMoveToTuckedData().removeObserver(mMoveToTuckedObserver);
+        mMenuViewModel.getHearingDeviceStatusData().removeObserver(mHearingDeviceStatusObserver);
+        mMenuViewModel.getHearingDeviceTargetIndexData().removeObserver(
+                mHearingDeviceTargetIndexObserver);
         mMenuViewModel.unregisterObserversAndCallbacks();
         getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
         getViewTreeObserver().removeOnDrawListener(mSystemGestureExcludeUpdater);
@@ -421,6 +433,14 @@
         parentView.setSystemGestureExclusionRects(Collections.singletonList(mBoundsInParent));
     }
 
+    private void updateHearingDeviceStatus(@HearingAidDeviceManager.ConnectionStatus int status) {
+        // TODO: b/357882387 - To update status drawable according to the status here.
+    }
+
+    private void updateHearingDeviceTargetIndex(int position) {
+        // TODO: b/357882387 - To update status drawable according to the status here.
+    }
+
     /**
      * Interface definition for the {@link AccessibilityTarget} list changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
index cb96e78..184518a 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
@@ -24,6 +24,7 @@
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -39,11 +40,12 @@
     MenuViewLayerController(Context context, WindowManager windowManager,
             ViewCaptureAwareWindowManager viewCaptureAwareWindowManager,
             AccessibilityManager accessibilityManager, SecureSettings secureSettings,
-            NavigationModeController navigationModeController) {
+            NavigationModeController navigationModeController,
+            HearingAidDeviceManager hearingAidDeviceManager) {
         mWindowManager = viewCaptureAwareWindowManager;
 
         MenuViewModel menuViewModel = new MenuViewModel(
-                context, accessibilityManager, secureSettings);
+                context, accessibilityManager, secureSettings, hearingAidDeviceManager);
         MenuViewAppearance menuViewAppearance = new MenuViewAppearance(context, windowManager);
 
         mMenuViewLayer = new MenuViewLayer(context, windowManager, accessibilityManager,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java
index f924784..8b7d6a1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewModel.java
@@ -16,13 +16,20 @@
 
 package com.android.systemui.accessibility.floatingmenu;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
+
+import static java.util.Collections.emptyList;
+
+import android.content.ComponentName;
 import android.content.Context;
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.util.settings.SecureSettings;
 
 import java.util.List;
@@ -31,9 +38,9 @@
  * The view model provides the menu information from the repository{@link MenuInfoRepository} for
  * the menu view{@link MenuView}.
  */
-class MenuViewModel implements MenuInfoRepository.OnSettingsContentsChanged {
+class MenuViewModel implements MenuInfoRepository.OnContentsChanged {
     private final MutableLiveData<List<AccessibilityTarget>> mTargetFeaturesData =
-            new MutableLiveData<>();
+            new MutableLiveData<>(emptyList());
     private final MutableLiveData<Integer> mSizeTypeData = new MutableLiveData<>();
     private final MutableLiveData<MenuFadeEffectInfo> mFadeEffectInfoData =
             new MutableLiveData<>();
@@ -41,12 +48,18 @@
     private final MutableLiveData<Boolean> mDockTooltipData = new MutableLiveData<>();
     private final MutableLiveData<Boolean> mMigrationTooltipData = new MutableLiveData<>();
     private final MutableLiveData<Position> mPercentagePositionData = new MutableLiveData<>();
+    private final MutableLiveData<Integer> mHearingDeviceStatusData = new MutableLiveData<>(
+            HearingAidDeviceManager.ConnectionStatus.NO_DEVICE_BONDED);
+    private final LiveData<Integer> mHearingDeviceTargetIndex = Transformations.map(
+            mTargetFeaturesData, this::getHearingDeviceTargetIndex);
+
     private final MenuInfoRepository mInfoRepository;
 
     MenuViewModel(Context context, AccessibilityManager accessibilityManager,
-            SecureSettings secureSettings) {
+            SecureSettings secureSettings, HearingAidDeviceManager hearingAidDeviceManager) {
         mInfoRepository = new MenuInfoRepository(context,
-                accessibilityManager, /* settingsContentsChanged= */ this, secureSettings);
+                accessibilityManager, /* settingsContentsChanged= */ this, secureSettings,
+                hearingAidDeviceManager);
     }
 
     @Override
@@ -64,6 +77,12 @@
         mFadeEffectInfoData.setValue(fadeEffectInfo);
     }
 
+    @Override
+    public void onDevicesConnectionStatusChanged(
+            @HearingAidDeviceManager.ConnectionStatus int status) {
+        mHearingDeviceStatusData.postValue(status);
+    }
+
     void updateMenuMoveToTucked(boolean isMoveToTucked) {
         mInfoRepository.updateMoveToTucked(isMoveToTucked);
     }
@@ -115,6 +134,19 @@
         return mTargetFeaturesData;
     }
 
+    LiveData<Integer> loadHearingDeviceStatus() {
+        mInfoRepository.loadHearingDeviceStatus(mHearingDeviceStatusData::setValue);
+        return mHearingDeviceStatusData;
+    }
+
+    LiveData<Integer> getHearingDeviceStatusData() {
+        return mHearingDeviceStatusData;
+    }
+
+    LiveData<Integer> getHearingDeviceTargetIndexData() {
+        return mHearingDeviceTargetIndex;
+    }
+
     void registerObserversAndCallbacks() {
         mInfoRepository.registerObserversAndCallbacks();
     }
@@ -122,4 +154,16 @@
     void unregisterObserversAndCallbacks() {
         mInfoRepository.unregisterObserversAndCallbacks();
     }
+
+    private int getHearingDeviceTargetIndex(List<AccessibilityTarget> targetList) {
+        final int listSize = targetList.size();
+        for (int index = 0; index < listSize; index++) {
+            AccessibilityTarget target = targetList.get(index);
+            if (ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.equals(
+                    ComponentName.unflattenFromString(target.getId()))) {
+                return index;
+            }
+        }
+        return -1;
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java
index 14626e1..e72dfad 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.UserHandle;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.dagger.qualifiers.Background;
 
@@ -41,4 +42,16 @@
             @Background Handler bgHandler) {
         return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
     }
+
+    @SuppressLint("MissingPermission")
+    @SysUISingleton
+    @Provides
+    @Nullable
+    static HearingAidDeviceManager provideHearingAidDeviceManager(
+            @Nullable LocalBluetoothManager localBluetoothManager) {
+        if (localBluetoothManager == null) {
+            return null;
+        }
+        return localBluetoothManager.getCachedDeviceManager().getHearingAidDeviceManager();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
index f310b30..3390640 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
@@ -18,6 +18,8 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
+import android.os.Bundle
+import android.util.Log
 import android.view.Display
 import android.view.LayoutInflater
 import android.view.WindowManager
@@ -39,14 +41,13 @@
 interface DisplayWindowPropertiesRepository {
 
     /**
-     * Returns a [DisplayWindowProperties] instance for a given display id and window type.
-     *
-     * @throws IllegalArgumentException if no display with the given display id exists.
+     * Returns a [DisplayWindowProperties] instance for a given display id and window type, or null
+     * if no display with the given display id exists.
      */
     fun get(
         displayId: Int,
         @WindowManager.LayoutParams.WindowType windowType: Int,
-    ): DisplayWindowProperties
+    ): DisplayWindowProperties?
 }
 
 @SysUISingleton
@@ -72,12 +73,10 @@
     override fun get(
         displayId: Int,
         @WindowManager.LayoutParams.WindowType windowType: Int,
-    ): DisplayWindowProperties {
-        val display =
-            displayRepository.getDisplay(displayId)
-                ?: throw IllegalArgumentException("Display with id $displayId doesn't exist")
+    ): DisplayWindowProperties? {
+        val display = displayRepository.getDisplay(displayId) ?: return null
         return properties.get(displayId, windowType)
-            ?: create(display, windowType).also { properties.put(displayId, windowType, it) }
+            ?: create(display, windowType)?.also { properties.put(displayId, windowType, it) }
     }
 
     override fun start() {
@@ -88,7 +87,7 @@
         }
     }
 
-    private fun create(display: Display, windowType: Int): DisplayWindowProperties {
+    private fun create(display: Display, windowType: Int): DisplayWindowProperties? {
         val displayId = display.displayId
         return if (displayId == Display.DEFAULT_DISPLAY) {
             // For the default display, we can just reuse the global/application properties.
@@ -102,6 +101,14 @@
             )
         } else {
             val context = createWindowContext(display, windowType)
+            if (context.displayId != display.displayId) {
+                Log.e(
+                    TAG,
+                    "Returning null because the new context doesn't have the desired display id " +
+                        "${display.displayId}. Display was already removed.",
+                )
+                return null
+            }
             @SuppressLint("NonInjectedService") // Need to manually get the service
             val windowManager = context.getSystemService(WindowManager::class.java) as WindowManager
             val layoutInflater = LayoutInflater.from(context)
@@ -110,11 +117,15 @@
     }
 
     private fun createWindowContext(display: Display, windowType: Int): Context =
-        globalContext.createWindowContext(display, windowType, /* options= */ null).also {
+        globalContext.createWindowContext(display, windowType, /* options= */ Bundle.EMPTY).also {
             it.setTheme(R.style.Theme_SystemUI)
         }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.write("perDisplayContexts: $properties")
     }
+
+    private companion object {
+        const val TAG = "DisplayWindowPropsRepo"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
index 711534f..564588c 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.display.data.repository
 
+import android.util.Log
 import android.view.Display
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
@@ -36,12 +37,10 @@
     val defaultDisplay: T
 
     /**
-     * Returns an instance for a specific display id.
-     *
-     * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
-     *   displays.
+     * Returns an instance for a specific display id, or null if [displayId] doesn't match the id of
+     * any existing displays.
      */
-    fun forDisplay(displayId: Int): T
+    fun forDisplay(displayId: Int): T?
 }
 
 abstract class PerDisplayStoreImpl<T>(
@@ -58,7 +57,7 @@
      * Note that the id of the default display is [Display.DEFAULT_DISPLAY].
      */
     override val defaultDisplay: T
-        get() = forDisplay(Display.DEFAULT_DISPLAY)
+        get() = forDisplay(Display.DEFAULT_DISPLAY)!!
 
     /**
      * Returns an instance for a specific display id.
@@ -66,16 +65,30 @@
      * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
      *   displays.
      */
-    override fun forDisplay(displayId: Int): T {
+    override fun forDisplay(displayId: Int): T? {
         if (displayRepository.getDisplay(displayId) == null) {
-            throw IllegalArgumentException("Display with id $displayId doesn't exist.")
+            Log.e(TAG, "<${instanceClass.simpleName}>: Display with id $displayId doesn't exist.")
+            return null
         }
-        return perDisplayInstances.computeIfAbsent(displayId) {
-            createInstanceForDisplay(displayId)
+        synchronized(perDisplayInstances) {
+            val existingInstance = perDisplayInstances[displayId]
+            if (existingInstance != null) {
+                return existingInstance
+            }
+            val newInstance = createInstanceForDisplay(displayId)
+            if (newInstance == null) {
+                Log.e(
+                    TAG,
+                    "<${instanceClass.simpleName}> returning null because createInstanceForDisplay($displayId) returned null.",
+                )
+            } else {
+                perDisplayInstances[displayId] = newInstance
+            }
+            return newInstance
         }
     }
 
-    protected abstract fun createInstanceForDisplay(displayId: Int): T
+    protected abstract fun createInstanceForDisplay(displayId: Int): T?
 
     override fun start() {
         val instanceType = instanceClass.simpleName
@@ -98,6 +111,10 @@
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println(perDisplayInstances)
     }
+
+    private companion object {
+        const val TAG = "PerDisplayStore"
+    }
 }
 
 class SingleDisplayStore<T>(defaultInstance: T) : PerDisplayStore<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
index 22e467b..99c9ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
@@ -33,7 +33,7 @@
      *
      * @throws IllegalArgumentException if no display with the given display id exists.
      */
-    fun getForStatusBar(displayId: Int): DisplayWindowProperties
+    fun getForStatusBar(displayId: Int): DisplayWindowProperties?
 }
 
 @SysUISingleton
@@ -42,7 +42,7 @@
 constructor(private val repo: DisplayWindowPropertiesRepository) :
     DisplayWindowPropertiesInteractor {
 
-    override fun getForStatusBar(displayId: Int): DisplayWindowProperties {
+    override fun getForStatusBar(displayId: Int): DisplayWindowProperties? {
         return repo.get(displayId, TYPE_STATUS_BAR)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index c895732..f9df676 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -720,9 +720,24 @@
 
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mView);
 
-        mViewCaptureAwareWindowManager.addView(mFrame,
-                getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
-                        .getRotation()));
+        try {
+            mViewCaptureAwareWindowManager.addView(
+                    mFrame,
+                    getBarLayoutParams(
+                            mContext.getResources()
+                                    .getConfiguration()
+                                    .windowConfiguration
+                                    .getRotation()));
+        } catch (WindowManager.InvalidDisplayException e) {
+            // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+            // after being added, and initialization hasn't finished yet.
+            Log.e(
+                    TAG,
+                    "Unable to add view to WindowManager. Display with id "
+                            + mDisplayId
+                            + " does not exist anymore",
+                    e);
+        }
         mDisplayId = mContext.getDisplayId();
         mIsOnDefaultDisplay = mDisplayId == mDisplayTracker.getDefaultDisplayId();
 
@@ -764,6 +779,15 @@
             Trace.beginSection("NavigationBar#removeViewImmediate");
             try {
                 mViewCaptureAwareWindowManager.removeViewImmediate(mView.getRootView());
+            } catch (IllegalArgumentException e) {
+                // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+                // after being added, and initialization hasn't finished yet.
+                // When that happens, adding the View to WindowManager fails, and therefore removing
+                // it here will fail too, since it wasn't added in the first place.
+                Log.e(
+                        TAG,
+                        "Failed to removed view from WindowManager. The View wasn't attached.",
+                        e);
             } finally {
                 Trace.endSection();
             }
@@ -859,7 +883,15 @@
         if (mOrientationHandle != null) {
             resetSecondaryHandle();
             getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
-            mViewCaptureAwareWindowManager.removeView(mOrientationHandle);
+            try {
+                mViewCaptureAwareWindowManager.removeView(mOrientationHandle);
+            } catch (IllegalArgumentException e) {
+                // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+                // after being added, and initialization hasn't finished yet.
+                // When that happens, adding the View to WindowManager fails, and therefore removing
+                // it here will fail too, since it wasn't added in the first place.
+                Log.e(TAG, "Trying to remove a View that is not attached", e);
+            }
             mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener(
                     mOrientationHandleGlobalLayoutListener);
         }
@@ -930,7 +962,18 @@
         mOrientationParams.setTitle("SecondaryHomeHandle" + mContext.getDisplayId());
         mOrientationParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION
                 | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
-        mViewCaptureAwareWindowManager.addView(mOrientationHandle, mOrientationParams);
+        try {
+            mViewCaptureAwareWindowManager.addView(mOrientationHandle, mOrientationParams);
+        } catch (WindowManager.InvalidDisplayException e) {
+            // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+            // after being added, and initialization hasn't finished yet.
+            Log.e(
+                    TAG,
+                    "Unable to add view to WindowManager. Display with id "
+                            + mDisplayId
+                            + " does not exist anymore",
+                    e);
+        }
         mOrientationHandle.setVisibility(View.GONE);
 
         logNavbarOrientation("initSecondaryHomeHandleForRotation");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt b/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
index ffeec4e..c302cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
@@ -79,6 +79,14 @@
     @JvmStatic
     inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
 
+    /**
+     * Called to ensure code is only run when the flag is enabled. This will throw an exception if
+     * the flag is not enabled to ensure that the refactor author catches issues in testing.
+     * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
+     */
+    @JvmStatic
+    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+
     /** Returns a developer-readable string that describes the current requirement list. */
     @JvmStatic
     fun requirementDescription(): String {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
index 9677d47..3b3fb9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
 import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractor
 import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import javax.inject.Inject
 
 @SysUISingleton
@@ -33,12 +34,14 @@
     private val accessibilityTilesInteractor: AccessibilityTilesInteractor,
     private val autoAddInteractor: AutoAddInteractor,
     private val featureFlags: QSPipelineFlagsRepository,
+    private val settingsPackageRepository: QSSettingsPackageRepository,
     private val restoreReconciliationInteractor: RestoreReconciliationInteractor,
 ) : CoreStartable {
 
     override fun start() {
         accessibilityTilesInteractor.init(currentTilesInteractor)
         autoAddInteractor.init(currentTilesInteractor)
+        settingsPackageRepository.init()
         restoreReconciliationInteractor.start()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/shared/QSSettingsPackageRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/shared/QSSettingsPackageRepository.kt
new file mode 100644
index 0000000..592e9da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/shared/QSSettingsPackageRepository.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.shared
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.user.data.repository.UserRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Provides the cached package name of the default Settings application.
+ *
+ * This repository retrieves and stores the package name to avoid repeated lookups. The package name
+ * is retrieved in a background thread when the `init()` method is called.
+ */
+@SysUISingleton
+@Suppress("ShadeDisplayAwareContextChecker")
+class QSSettingsPackageRepository
+@Inject
+constructor(
+    private val context: Context,
+    @Background private val backgroundScope: CoroutineScope,
+    private val userRepository: UserRepository,
+) {
+    private var settingsPackageName: String? = null
+
+    /**
+     * Initializes the repository by determining and caching the package name of the Settings app.
+     */
+    fun init() {
+        backgroundScope.launch {
+            val mainUserId = userRepository.mainUserId
+            val mainUserContext =
+                context.createContextAsUser(UserHandle.of(mainUserId), /* flags */ 0)
+            val pm = mainUserContext.packageManager
+            settingsPackageName =
+                pm.queryIntentActivities(
+                        Intent(Settings.ACTION_SETTINGS),
+                        PackageManager.MATCH_SYSTEM_ONLY or PackageManager.MATCH_DEFAULT_ONLY,
+                    )
+                    .firstOrNull()
+                    ?.activityInfo
+                    ?.packageName ?: DEFAULT_SETTINGS_PACKAGE_NAME
+        }
+    }
+
+    /**
+     * Returns the cached package name of the Settings app.
+     *
+     * If the package name has not been initialized yet, this method will return the default
+     * Settings package name.
+     *
+     * @return The package name of the Settings app.
+     */
+    fun getSettingsPackageName(): String {
+        return settingsPackageName ?: DEFAULT_SETTINGS_PACKAGE_NAME
+    }
+
+    companion object {
+        private const val DEFAULT_SETTINGS_PACKAGE_NAME = "com.android.settings"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
index c2e609d..1f93681 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
@@ -38,6 +38,7 @@
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.shared.QSSettingsPackageRepository;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
@@ -53,6 +54,7 @@
     @Nullable
     private Icon mIcon = null;
     private final UserSettingObserver mSetting;
+    private final QSSettingsPackageRepository mQSSettingsPackageRepository;
 
     @Inject
     public ColorCorrectionTile(
@@ -66,11 +68,13 @@
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             UserTracker userTracker,
-            SecureSettings secureSettings
+            SecureSettings secureSettings,
+            QSSettingsPackageRepository qsSettingsPackageRepository
     ) {
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
 
+        mQSSettingsPackageRepository = qsSettingsPackageRepository;
         mSetting = new UserSettingObserver(secureSettings, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, userTracker.getUserId()) {
             @Override
@@ -106,7 +110,8 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return new Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS);
+        return new Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+                .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index ce80133..38e9a20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -39,6 +39,7 @@
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.UserSettingObserver;
 import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.shared.QSSettingsPackageRepository;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
@@ -51,6 +52,7 @@
 
     public static final String TILE_SPEC = "inversion";
     private final UserSettingObserver mSetting;
+    private final QSSettingsPackageRepository mQSSettingsPackageRepository;
 
     @Inject
     public ColorInversionTile(
@@ -64,11 +66,13 @@
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             UserTracker userTracker,
-            SecureSettings secureSettings
+            SecureSettings secureSettings,
+            QSSettingsPackageRepository qsSettingsPackageRepository
     ) {
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
 
+        mQSSettingsPackageRepository = qsSettingsPackageRepository;
         mSetting = new UserSettingObserver(secureSettings, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) {
             @Override
@@ -104,7 +108,8 @@
 
     @Override
     public Intent getLongClickIntent() {
-        return new Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS);
+        return new Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS)
+                .setPackage(mQSSettingsPackageRepository.getSettingsPackageName());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 43e84a0..4050f2a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.QsEventLogger
 import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -56,6 +57,7 @@
     private val keyguardStateController: KeyguardStateController,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val fontScalingDialogDelegateProvider: Provider<FontScalingDialogDelegate>,
+    private val settingsPackageRepository: QSSettingsPackageRepository,
 ) :
     QSTileImpl<QSTile.State?>(
         host,
@@ -118,6 +120,7 @@
 
     override fun getLongClickIntent(): Intent? {
         return Intent(Settings.ACTION_TEXT_READING_SETTINGS)
+            .setPackage(settingsPackageRepository.getSettingsPackageName())
     }
 
     override fun getTileLabel(): CharSequence {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 7516ca0..b21c3e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -54,20 +54,21 @@
 
     private static final String TAG = "InternetAdapter";
 
-    private final InternetDialogController mInternetDialogController;
+    private final InternetDetailsContentController mInternetDetailsContentController;
     private final CoroutineScope mCoroutineScope;
     @Nullable
     private List<WifiEntry> mWifiEntries;
     @VisibleForTesting
     protected int mWifiEntriesCount;
     @VisibleForTesting
-    protected int mMaxEntriesCount = InternetDialogController.MAX_WIFI_ENTRY_COUNT;
+    protected int mMaxEntriesCount = InternetDetailsContentController.MAX_WIFI_ENTRY_COUNT;
 
     protected View mHolderView;
     protected Context mContext;
 
-    public InternetAdapter(InternetDialogController controller, CoroutineScope coroutineScope) {
-        mInternetDialogController = controller;
+    public InternetAdapter(InternetDetailsContentController controller,
+            CoroutineScope coroutineScope) {
+        mInternetDetailsContentController = controller;
         mCoroutineScope = coroutineScope;
     }
 
@@ -77,7 +78,8 @@
         mContext = viewGroup.getContext();
         mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item,
                 viewGroup, false);
-        return new InternetViewHolder(mHolderView, mInternetDialogController, mCoroutineScope);
+        return new InternetViewHolder(mHolderView, mInternetDetailsContentController,
+                mCoroutineScope);
     }
 
     @Override
@@ -137,16 +139,17 @@
         final TextView mWifiSummaryText;
         final ImageView mWifiEndIcon;
         final Context mContext;
-        final InternetDialogController mInternetDialogController;
+        final InternetDetailsContentController mInternetDetailsContentController;
         final CoroutineScope mCoroutineScope;
         @Nullable
         private Job mJob;
 
-        InternetViewHolder(View view, InternetDialogController internetDialogController,
+        InternetViewHolder(View view,
+                InternetDetailsContentController internetDetailsContentController,
                 CoroutineScope coroutineScope) {
             super(view);
             mContext = view.getContext();
-            mInternetDialogController = internetDialogController;
+            mInternetDetailsContentController = internetDetailsContentController;
             mCoroutineScope = coroutineScope;
             mContainerLayout = view.requireViewById(R.id.internet_container);
             mWifiListLayout = view.requireViewById(R.id.wifi_list);
@@ -169,7 +172,7 @@
             mWifiListLayout.setEnabled(shouldEnabled(wifiEntry));
             if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
                 mWifiListLayout.setOnClickListener(
-                        v -> mInternetDialogController.launchWifiDetailsSetting(
+                        v -> mInternetDetailsContentController.launchWifiDetailsSetting(
                                 wifiEntry.getKey(), v));
                 return;
             }
@@ -193,7 +196,7 @@
                 if (mJob == null) {
                     mJob = WifiUtils.checkWepAllowed(mContext, mCoroutineScope, wifiEntry.getSsid(),
                             WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, intent -> {
-                                mInternetDialogController.startActivityForDialog(intent);
+                                mInternetDetailsContentController.startActivityForDialog(intent);
                                 return null;
                             }, () -> {
                                 wifiConnect(wifiEntry, view);
@@ -211,19 +214,20 @@
                         true /* connectForCaller */);
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
-                mInternetDialogController.startActivityForDialog(intent);
+                mInternetDetailsContentController.startActivityForDialog(intent);
                 return;
             }
 
             if (wifiEntry.canConnect()) {
-                mInternetDialogController.connect(wifiEntry);
+                mInternetDetailsContentController.connect(wifiEntry);
                 return;
             }
 
             if (wifiEntry.isSaved()) {
                 Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:"
                         + wifiEntry.getSsid());
-                mInternetDialogController.launchWifiDetailsSetting(wifiEntry.getKey(), view);
+                mInternetDetailsContentController.launchWifiDetailsSetting(wifiEntry.getKey(),
+                        view);
             }
         }
 
@@ -239,7 +243,7 @@
 
         @Nullable
         Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) {
-            Drawable drawable = mInternetDialogController.getWifiDrawable(wifiEntry);
+            Drawable drawable = mInternetDetailsContentController.getWifiDrawable(wifiEntry);
             if (drawable == null) {
                 return null;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentController.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
rename to packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentController.java
index 7036ef91..23210ef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentController.java
@@ -117,9 +117,9 @@
 /**
  * Controller for Internet Dialog.
  */
-public class InternetDialogController implements AccessPointController.AccessPointCallback {
+public class InternetDetailsContentController implements AccessPointController.AccessPointCallback {
 
-    private static final String TAG = "InternetDialogController";
+    private static final String TAG = "InternetDetailsContentController";
     private static final String ACTION_WIFI_SCANNING_SETTINGS =
             "android.settings.WIFI_SCANNING_SETTINGS";
     /**
@@ -244,7 +244,8 @@
     }
 
     @Inject
-    public InternetDialogController(@ShadeDisplayAware Context context, UiEventLogger uiEventLogger,
+    public InternetDetailsContentController(@ShadeDisplayAware Context context,
+            UiEventLogger uiEventLogger,
             ActivityStarter starter, AccessPointController accessPointController,
             SubscriptionManager subscriptionManager, TelephonyManager telephonyManager,
             @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager,
@@ -260,7 +261,7 @@
             FeatureFlags featureFlags
     ) {
         if (DEBUG) {
-            Log.d(TAG, "Init InternetDialogController");
+            Log.d(TAG, "Init InternetDetailsContentController");
         }
         mHandler = handler;
         mWorkerHandler = workerHandler;
@@ -1108,13 +1109,13 @@
     static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback {
         final ActivityStarter mActivityStarter;
         final WifiEntry mWifiEntry;
-        final InternetDialogController mInternetDialogController;
+        final InternetDetailsContentController mInternetDetailsContentController;
 
         WifiEntryConnectCallback(ActivityStarter activityStarter, WifiEntry connectWifiEntry,
-                InternetDialogController internetDialogController) {
+                InternetDetailsContentController internetDetailsContentController) {
             mActivityStarter = activityStarter;
             mWifiEntry = connectWifiEntry;
-            mInternetDialogController = internetDialogController;
+            mInternetDetailsContentController = internetDetailsContentController;
         }
 
         @Override
@@ -1129,7 +1130,8 @@
                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 mActivityStarter.startActivity(intent, false /* dismissShade */);
             } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
-                mInternetDialogController.makeOverlayToast(R.string.wifi_failed_connect_message);
+                mInternetDetailsContentController.makeOverlayToast(
+                        R.string.wifi_failed_connect_message);
             } else {
                 if (DEBUG) {
                     Log.d(TAG, "connect failure reason=" + status);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
rename to packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java
index 5e9deec..82367eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacy.java
@@ -17,7 +17,7 @@
 
 import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_WIFI;
 import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
-import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
+import static com.android.systemui.qs.tiles.dialog.InternetDetailsContentController.MAX_WIFI_ENTRY_COUNT;
 
 import android.app.AlertDialog;
 import android.content.Context;
@@ -90,9 +90,9 @@
 /**
  * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
  */
-public class InternetDialogDelegate implements
+public class InternetDialogDelegateLegacy implements
         SystemUIDialog.Delegate,
-        InternetDialogController.InternetDialogCallback {
+        InternetDetailsContentController.InternetDialogCallback {
     private static final String TAG = "InternetDialog";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -120,7 +120,7 @@
     @Nullable
     private AlertDialog mAlertDialog;
     private final UiEventLogger mUiEventLogger;
-    private final InternetDialogController mInternetDialogController;
+    private final InternetDetailsContentController mInternetDetailsContentController;
     private TextView mInternetDialogTitle;
     private TextView mInternetDialogSubTitle;
     private View mDivider;
@@ -184,7 +184,7 @@
 
     @AssistedFactory
     public interface Factory {
-        InternetDialogDelegate create(
+        InternetDialogDelegateLegacy create(
                 @Assisted(ABOVE_STATUS_BAR) boolean aboveStatusBar,
                 @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
                 @Assisted(CAN_CONFIG_WIFI) boolean canConfigWifi,
@@ -192,10 +192,10 @@
     }
 
     @AssistedInject
-    public InternetDialogDelegate(
+    public InternetDialogDelegateLegacy(
             @ShadeDisplayAware Context context,
             InternetDialogManager internetDialogManager,
-            InternetDialogController internetDialogController,
+            InternetDetailsContentController internetDetailsContentController,
             @Assisted(CAN_CONFIG_MOBILE_DATA) boolean canConfigMobileData,
             @Assisted(CAN_CONFIG_WIFI) boolean canConfigWifi,
             @Assisted(ABOVE_STATUS_BAR) boolean aboveStatusBar,
@@ -207,6 +207,8 @@
             KeyguardStateController keyguardStateController,
             SystemUIDialog.Factory systemUIDialogFactory,
             ShadeDialogContextInteractor shadeDialogContextInteractor) {
+        // TODO: b/377388104 QsDetailedView.assertInLegacyMode();
+
         mAboveStatusBar = aboveStatusBar;
         mSystemUIDialogFactory = systemUIDialogFactory;
         mShadeDialogContextInteractor = shadeDialogContextInteractor;
@@ -218,8 +220,8 @@
         mHandler = handler;
         mBackgroundExecutor = executor;
         mInternetDialogManager = internetDialogManager;
-        mInternetDialogController = internetDialogController;
-        mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
+        mInternetDetailsContentController = internetDetailsContentController;
+        mDefaultDataSubId = mInternetDetailsContentController.getDefaultDataSubscriptionId();
         mCanConfigMobileData = canConfigMobileData;
         mCanConfigWifi = canConfigWifi;
         mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
@@ -227,7 +229,7 @@
         mCoroutineScope = coroutineScope;
         mUiEventLogger = uiEventLogger;
         mDialogTransitionAnimator = dialogTransitionAnimator;
-        mAdapter = new InternetAdapter(mInternetDialogController, coroutineScope);
+        mAdapter = new InternetAdapter(mInternetDetailsContentController, coroutineScope);
     }
 
     @Override
@@ -309,7 +311,8 @@
         setOnClickListener(dialog);
         mTurnWifiOnLayout.setBackground(null);
         mAirplaneModeButton.setVisibility(
-                mInternetDialogController.isAirplaneModeEnabled() ? View.VISIBLE : View.GONE);
+                mInternetDetailsContentController.isAirplaneModeEnabled() ? View.VISIBLE
+                        : View.GONE);
         mWifiRecyclerView.setLayoutManager(new LinearLayoutManager(context));
         mWifiRecyclerView.setAdapter(mAdapter);
 
@@ -324,7 +327,7 @@
 
         mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
 
-        mInternetDialogController.onStart(this, mCanConfigWifi);
+        mInternetDetailsContentController.onStart(this, mCanConfigWifi);
         if (!mCanConfigWifi) {
             hideWifiViews();
         }
@@ -356,7 +359,7 @@
         mDoneButton.setOnClickListener(null);
         mShareWifiButton.setOnClickListener(null);
         mAirplaneModeButton.setOnClickListener(null);
-        mInternetDialogController.onStop();
+        mInternetDetailsContentController.onStop();
         mInternetDialogManager.destroyDialog();
     }
 
@@ -413,18 +416,20 @@
         internetContent.mInternetDialogSubTitle = getSubtitleText();
         if (shouldUpdateMobileNetwork) {
             internetContent.mActiveNetworkIsCellular =
-                    mInternetDialogController.activeNetworkIsCellular();
+                    mInternetDetailsContentController.activeNetworkIsCellular();
             internetContent.mIsCarrierNetworkActive =
-                    mInternetDialogController.isCarrierNetworkActive();
+                    mInternetDetailsContentController.isCarrierNetworkActive();
         }
-        internetContent.mIsAirplaneModeEnabled = mInternetDialogController.isAirplaneModeEnabled();
-        internetContent.mHasEthernet = mInternetDialogController.hasEthernet();
-        internetContent.mIsWifiEnabled = mInternetDialogController.isWifiEnabled();
-        internetContent.mHasActiveSubIdOnDds = mInternetDialogController.hasActiveSubIdOnDds();
-        internetContent.mIsDeviceLocked = mInternetDialogController.isDeviceLocked();
-        internetContent.mIsWifiScanEnabled = mInternetDialogController.isWifiScanEnabled();
+        internetContent.mIsAirplaneModeEnabled =
+                mInternetDetailsContentController.isAirplaneModeEnabled();
+        internetContent.mHasEthernet = mInternetDetailsContentController.hasEthernet();
+        internetContent.mIsWifiEnabled = mInternetDetailsContentController.isWifiEnabled();
+        internetContent.mHasActiveSubIdOnDds =
+                mInternetDetailsContentController.hasActiveSubIdOnDds();
+        internetContent.mIsDeviceLocked = mInternetDetailsContentController.isDeviceLocked();
+        internetContent.mIsWifiScanEnabled = mInternetDetailsContentController.isWifiScanEnabled();
         internetContent.mActiveAutoSwitchNonDdsSubId =
-                mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+                mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
         return internetContent;
     }
 
@@ -432,8 +437,8 @@
         InternetContent internetContent = new InternetContent();
         internetContent.mInternetDialogTitleString = getDialogTitleText();
         internetContent.mInternetDialogSubTitle = getSubtitleText();
-        internetContent.mIsWifiEnabled = mInternetDialogController.isWifiEnabled();
-        internetContent.mIsDeviceLocked = mInternetDialogController.isDeviceLocked();
+        internetContent.mIsWifiEnabled = mInternetDetailsContentController.isWifiEnabled();
+        internetContent.mIsDeviceLocked = mInternetDetailsContentController.isDeviceLocked();
         return internetContent;
     }
 
@@ -447,15 +452,15 @@
             if (autoSwitchNonDdsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                 showTurnOffAutoDataSwitchDialog(dialog, autoSwitchNonDdsSubId);
             }
-            mInternetDialogController.connectCarrierNetwork();
+            mInternetDetailsContentController.connectCarrierNetwork();
         });
         mMobileDataToggle.setOnClickListener(v -> {
             boolean isChecked = mMobileDataToggle.isChecked();
             if (!isChecked && shouldShowMobileDialog()) {
                 mMobileDataToggle.setChecked(true);
                 showTurnOffMobileDialog(dialog);
-            } else if (mInternetDialogController.isMobileDataEnabled() != isChecked) {
-                mInternetDialogController.setMobileDataEnabled(
+            } else if (mInternetDetailsContentController.isMobileDataEnabled() != isChecked) {
+                mInternetDetailsContentController.setMobileDataEnabled(
                         dialog.getContext(), mDefaultDataSubId, isChecked, false);
             }
         });
@@ -466,12 +471,13 @@
         });
         mDoneButton.setOnClickListener(v -> dialog.dismiss());
         mShareWifiButton.setOnClickListener(v -> {
-            if (mInternetDialogController.mayLaunchShareWifiSettings(mConnectedWifiEntry, v)) {
+            if (mInternetDetailsContentController.mayLaunchShareWifiSettings(mConnectedWifiEntry,
+                    v)) {
                 mUiEventLogger.log(InternetDialogEvent.SHARE_WIFI_QS_BUTTON_CLICKED);
             }
         });
         mAirplaneModeButton.setOnClickListener(v -> {
-            mInternetDialogController.setAirplaneModeDisabled();
+            mInternetDetailsContentController.setAirplaneModeDisabled();
         });
     }
 
@@ -495,10 +501,10 @@
     }
 
     private void setWifiEnable(boolean isChecked) {
-        if (mInternetDialogController.isWifiEnabled() == isChecked) {
+        if (mInternetDetailsContentController.isWifiEnabled() == isChecked) {
             return;
         }
-        mInternetDialogController.setWifiEnabled(isChecked);
+        mInternetDetailsContentController.setWifiEnabled(isChecked);
     }
 
     @MainThread
@@ -534,7 +540,7 @@
             }
         } else {
             mMobileNetworkLayout.setVisibility(View.VISIBLE);
-            mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
+            mMobileDataToggle.setChecked(mInternetDetailsContentController.isMobileDataEnabled());
             mMobileTitleText.setText(getMobileNetworkTitle(mDefaultDataSubId));
             String summary = getMobileNetworkSummary(mDefaultDataSubId);
             if (!TextUtils.isEmpty(summary)) {
@@ -679,10 +685,10 @@
         mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
         mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
         mConnectedWifiIcon.setImageDrawable(
-                mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
+                mInternetDetailsContentController.getInternetWifiDrawable(mConnectedWifiEntry));
         mWifiSettingsIcon.setColorFilter(
                 mDialog.getContext().getColor(R.color.connected_network_primary_color));
-        if (mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+        if (mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(
                 mConnectedWifiEntry) != null) {
             mShareWifiButton.setVisibility(View.VISIBLE);
         } else {
@@ -748,7 +754,7 @@
         if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) {
             final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo(
                     AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION,
-                    mInternetDialogController::launchWifiScanningSetting);
+                    mInternetDetailsContentController::launchWifiScanningSetting);
             mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify(
                     mDialog.getContext().getText(R.string.wifi_scan_notify_message), linkInfo));
             mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance());
@@ -760,37 +766,38 @@
         if (mConnectedWifiEntry == null) {
             return;
         }
-        mInternetDialogController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(), view);
+        mInternetDetailsContentController.launchWifiDetailsSetting(mConnectedWifiEntry.getKey(),
+                view);
     }
 
     /** For DSDS auto data switch **/
     void onClickConnectedSecondarySub(View view) {
-        mInternetDialogController.launchMobileNetworkSettings(view);
+        mInternetDetailsContentController.launchMobileNetworkSettings(view);
     }
 
     void onClickSeeMoreButton(View view) {
-        mInternetDialogController.launchNetworkSetting(view);
+        mInternetDetailsContentController.launchNetworkSetting(view);
     }
 
     CharSequence getDialogTitleText() {
-        return mInternetDialogController.getDialogTitleText();
+        return mInternetDetailsContentController.getDialogTitleText();
     }
 
     @Nullable
     CharSequence getSubtitleText() {
-        return mInternetDialogController.getSubtitleText(mIsProgressBarVisible);
+        return mInternetDetailsContentController.getSubtitleText(mIsProgressBarVisible);
     }
 
     private Drawable getSignalStrengthDrawable(int subId) {
-        return mInternetDialogController.getSignalStrengthDrawable(subId);
+        return mInternetDetailsContentController.getSignalStrengthDrawable(subId);
     }
 
     CharSequence getMobileNetworkTitle(int subId) {
-        return mInternetDialogController.getMobileNetworkTitle(subId);
+        return mInternetDetailsContentController.getMobileNetworkTitle(subId);
     }
 
     String getMobileNetworkSummary(int subId) {
-        return mInternetDialogController.getMobileNetworkSummary(subId);
+        return mInternetDetailsContentController.getMobileNetworkSummary(subId);
     }
 
     private void setProgressBarVisible(boolean visible) {
@@ -810,7 +817,7 @@
         }
         boolean flag = Prefs.getBoolean(mDialog.getContext(), QS_HAS_TURNED_OFF_MOBILE_DATA,
                 false);
-        if (mInternetDialogController.isMobileDataEnabled() && !flag) {
+        if (mInternetDetailsContentController.isMobileDataEnabled() && !flag) {
             return true;
         }
         return false;
@@ -819,7 +826,8 @@
     private void showTurnOffMobileDialog(SystemUIDialog dialog) {
         Context context = dialog.getContext();
         CharSequence carrierName = getMobileNetworkTitle(mDefaultDataSubId);
-        boolean isInService = mInternetDialogController.isVoiceStateInService(mDefaultDataSubId);
+        boolean isInService = mInternetDetailsContentController.isVoiceStateInService(
+                mDefaultDataSubId);
         if (TextUtils.isEmpty(carrierName) || !isInService) {
             carrierName = context.getString(R.string.mobile_data_disable_message_default_carrier);
         }
@@ -831,7 +839,7 @@
                 .setPositiveButton(
                         com.android.internal.R.string.alert_windows_notification_turn_off_action,
                         (d, w) -> {
-                            mInternetDialogController.setMobileDataEnabled(context,
+                            mInternetDetailsContentController.setMobileDataEnabled(context,
                                     mDefaultDataSubId, false, false);
                             mMobileDataToggle.setChecked(false);
                             Prefs.putBoolean(context, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
@@ -858,7 +866,7 @@
                         })
                 .setPositiveButton(R.string.auto_data_switch_dialog_positive_button,
                         (d, w) -> {
-                            mInternetDialogController
+                            mInternetDetailsContentController
                                     .setAutoDataSwitchMobileDataPolicy(subId, false);
                             if (mSecondaryMobileNetworkLayout != null) {
                                 mSecondaryMobileNetworkLayout.setVisibility(View.GONE);
@@ -938,7 +946,7 @@
             @Nullable WifiEntry connectedEntry, boolean hasMoreWifiEntries) {
         // Should update the carrier network layout when it is connected under airplane mode ON.
         boolean shouldUpdateCarrierNetwork = mMobileNetworkLayout.getVisibility() == View.VISIBLE
-                && mInternetDialogController.isAirplaneModeEnabled();
+                && mInternetDetailsContentController.isAirplaneModeEnabled();
         mHandler.post(() -> {
             mConnectedWifiEntry = connectedEntry;
             mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
index f674971..8a54648 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
@@ -32,13 +32,13 @@
 private const val TAG = "InternetDialogFactory"
 private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
 
-/** Factory to create [InternetDialogDelegate] objects. */
+/** Factory to create [InternetDialogDelegateLegacy] objects. */
 @SysUISingleton
 class InternetDialogManager
 @Inject
 constructor(
     private val dialogTransitionAnimator: DialogTransitionAnimator,
-    private val dialogFactory: InternetDialogDelegate.Factory,
+    private val dialogFactory: InternetDialogDelegateLegacy.Factory,
     @Background private val bgDispatcher: CoroutineDispatcher,
 ) {
     private lateinit var coroutineScope: CoroutineScope
@@ -48,8 +48,8 @@
     }
 
     /**
-     * Creates a [InternetDialogDelegate]. The dialog will be animated from [expandable] if it is
-     * not null.
+     * Creates a [InternetDialogDelegateLegacy]. The dialog will be animated from [expandable] if
+     * it is not null.
      */
     fun create(
         aboveStatusBar: Boolean,
@@ -64,6 +64,7 @@
             return
         } else {
             coroutineScope = CoroutineScope(bgDispatcher + newTracingContext("InternetDialogScope"))
+            // TODO: b/377388104 check the QsDetailedView flag to use the correct dialogFactory
             dialog =
                 dialogFactory
                     .create(aboveStatusBar, canConfigMobileData, canConfigWifi, coroutineScope)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
index dfdec3b..b774643 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
@@ -19,6 +19,7 @@
 import android.content.Intent
 import android.provider.Settings
 import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.interactor.QSTileInput
 import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
@@ -32,21 +33,20 @@
 constructor(
     private val colorCorrectionRepository: ColorCorrectionRepository,
     private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+    private val settingsPackageRepository: QSSettingsPackageRepository,
 ) : QSTileUserActionInteractor<ColorCorrectionTileModel> {
 
     override suspend fun handleInput(input: QSTileInput<ColorCorrectionTileModel>): Unit =
         with(input) {
             when (action) {
                 is QSTileUserAction.Click -> {
-                    colorCorrectionRepository.setIsEnabled(
-                        !data.isEnabled,
-                        user,
-                    )
+                    colorCorrectionRepository.setIsEnabled(!data.isEnabled, user)
                 }
                 is QSTileUserAction.LongClick -> {
                     qsTileIntentUserActionHandler.handle(
                         action.expandable,
                         Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+                            .setPackage(settingsPackageRepository.getSettingsPackageName()),
                     )
                 }
                 is QSTileUserAction.ToggleClick -> {}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt
index 6ab5796..0ebb51e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.interactor.QSTileInput
 import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
@@ -46,6 +47,7 @@
     private val keyguardStateController: KeyguardStateController,
     private val dialogTransitionAnimator: DialogTransitionAnimator,
     private val activityStarter: ActivityStarter,
+    private val settingsPackageRepository: QSSettingsPackageRepository,
 ) : QSTileUserActionInteractor<FontScalingTileModel> {
 
     override suspend fun handleInput(input: QSTileInput<FontScalingTileModel>): Unit =
@@ -63,7 +65,7 @@
                                 ?.dialogTransitionController(
                                     DialogCuj(
                                         InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
-                                        INTERACTION_JANK_TAG
+                                        INTERACTION_JANK_TAG,
                                     )
                                 )
                                 ?.let { dialogTransitionAnimator.show(dialog, it) } ?: dialog.show()
@@ -78,7 +80,7 @@
                             /* cancelAction= */ null,
                             /* dismissShade= */ true,
                             /* afterKeyguardGone= */ true,
-                            /* deferred= */ false
+                            /* deferred= */ false,
                         )
                     }
                 }
@@ -86,6 +88,7 @@
                     qsTileIntentUserActionHandler.handle(
                         action.expandable,
                         Intent(Settings.ACTION_TEXT_READING_SETTINGS)
+                            .setPackage(settingsPackageRepository.getSettingsPackageName()),
                     )
                 }
                 is QSTileUserAction.ToggleClick -> {}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt
index aa83877..f783497 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt
@@ -19,6 +19,7 @@
 import android.content.Intent
 import android.provider.Settings
 import com.android.systemui.accessibility.data.repository.ColorInversionRepository
+import com.android.systemui.qs.shared.QSSettingsPackageRepository
 import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
 import com.android.systemui.qs.tiles.base.interactor.QSTileInput
 import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
@@ -32,21 +33,20 @@
 constructor(
     private val colorInversionRepository: ColorInversionRepository,
     private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+    private val settingsPackageRepository: QSSettingsPackageRepository,
 ) : QSTileUserActionInteractor<ColorInversionTileModel> {
 
     override suspend fun handleInput(input: QSTileInput<ColorInversionTileModel>): Unit =
         with(input) {
             when (action) {
                 is QSTileUserAction.Click -> {
-                    colorInversionRepository.setIsEnabled(
-                        !data.isEnabled,
-                        user,
-                    )
+                    colorInversionRepository.setIsEnabled(!data.isEnabled, user)
                 }
                 is QSTileUserAction.LongClick -> {
                     qsTileIntentUserActionHandler.handle(
                         action.expandable,
                         Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS)
+                            .setPackage(settingsPackageRepository.getSettingsPackageName()),
                     )
                 }
                 is QSTileUserAction.ToggleClick -> {}
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
index 10ac2cf..0650f86 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.scrim;
 
-import static com.android.systemui.Flags.notificationShadeBlur;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -216,7 +214,7 @@
     public void draw(@NonNull Canvas canvas) {
         mPaint.setColor(mMainColor);
         mPaint.setAlpha(mAlpha);
-        if (notificationShadeBlur() || WindowBlurFlag.isEnabled()) {
+        if (WindowBlurFlag.isEnabled()) {
             // TODO (b/381263600), wire this at ScrimController, move it to PrimaryBouncerTransition
             mPaint.setAlpha((int) (0.5f * mAlpha));
         }
diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
index 0f80e74..03a8d17 100644
--- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.scrim;
 
-import static com.android.systemui.Flags.notificationShadeBlur;
-
 import static java.lang.Float.isNaN;
 
 import android.annotation.NonNull;
@@ -44,6 +42,7 @@
 import com.android.systemui.res.R;
 import com.android.systemui.shade.TouchLogger;
 import com.android.systemui.util.LargeScreenUtils;
+import com.android.systemui.window.flag.WindowBlurFlag;
 
 import java.util.concurrent.Executor;
 
@@ -253,7 +252,7 @@
             if (mBlendWithMainColor) {
                 mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor, tintAmount);
             }
-            if (notificationShadeBlur()) {
+            if (WindowBlurFlag.isEnabled()) {
                 int layerAbove = ColorUtils.setAlphaComponent(
                         getResources().getColor(R.color.shade_panel, null),
                         (int) (0.4f * 255));
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
index 201dc03..4edba27 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
@@ -77,7 +77,17 @@
     private fun getContextOrDefault(displayId: Int): Context {
         return try {
             traceSection({ "Getting dialog context for displayId=$displayId" }) {
-                displayWindowPropertyRepository.get().get(displayId, DIALOG_WINDOW_TYPE).context
+                val displayWindowProperties =
+                    displayWindowPropertyRepository.get().get(displayId, DIALOG_WINDOW_TYPE)
+                if (displayWindowProperties == null) {
+                    Log.e(
+                        TAG,
+                        "DisplayWindowPropertiesRepository returned null for display $displayId. Returning default one",
+                    )
+                    defaultContext
+                } else {
+                    displayWindowProperties.context
+                }
             }
         } catch (e: Exception) {
             // This can happen if the display was disconnected in the meantime.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerText.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerText.kt
new file mode 100644
index 0000000..a747abb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChronometerText.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.chips.ui.compose
+
+import android.os.SystemClock
+import android.text.format.DateUtils.formatElapsedTime
+import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableLongStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.constrain
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.compose.LocalLifecycleOwner
+import androidx.lifecycle.repeatOnLifecycle
+import kotlinx.coroutines.delay
+
+/** Platform-optimized interface for getting current time */
+fun interface TimeSource {
+    fun getCurrentTime(): Long
+}
+
+/** Holds and manages the state for a Chronometer */
+class ChronometerState(private val timeSource: TimeSource, private val startTimeMillis: Long) {
+    private var currentTimeMillis by mutableLongStateOf(0L)
+    private val elapsedTimeMillis: Long
+        get() = maxOf(0L, currentTimeMillis - startTimeMillis)
+
+    val currentTimeText: String by derivedStateOf { formatElapsedTime(elapsedTimeMillis / 1000) }
+
+    suspend fun run() {
+        while (true) {
+            currentTimeMillis = timeSource.getCurrentTime()
+            val delaySkewMillis = (currentTimeMillis - startTimeMillis) % 1000L
+            delay(1000L - delaySkewMillis)
+        }
+    }
+}
+
+/** Remember and manage the ChronometerState */
+@Composable
+fun rememberChronometerState(timeSource: TimeSource, startTimeMillis: Long): ChronometerState {
+    val state =
+        remember(timeSource, startTimeMillis) { ChronometerState(timeSource, startTimeMillis) }
+    val lifecycleOwner = LocalLifecycleOwner.current
+    LaunchedEffect(lifecycleOwner, timeSource, startTimeMillis) {
+        lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { state.run() }
+    }
+
+    return state
+}
+
+/**
+ * A composable chronometer that displays elapsed time with constrained width. The width of the text
+ * is only allowed to increase. This ensures there is no visual jitter when individual digits in the
+ * text change due to the timer ticking.
+ */
+@Composable
+fun ChronometerText(
+    startTimeMillis: Long,
+    modifier: Modifier = Modifier,
+    color: Color = Color.Unspecified,
+    style: TextStyle = LocalTextStyle.current,
+    timeSource: TimeSource = remember { TimeSource { SystemClock.elapsedRealtime() } },
+) {
+    val state = rememberChronometerState(timeSource, startTimeMillis)
+    Text(
+        text = state.currentTimeText,
+        style = style,
+        color = color,
+        modifier = modifier.neverDecreaseWidth(),
+    )
+}
+
+/** A modifier that ensures the width of the content only increases and never decreases. */
+private fun Modifier.neverDecreaseWidth(): Modifier {
+    return this.then(neverDecreaseWidthElement)
+}
+
+private data object neverDecreaseWidthElement : ModifierNodeElement<NeverDecreaseWidthNode>() {
+    override fun create(): NeverDecreaseWidthNode {
+        return NeverDecreaseWidthNode()
+    }
+
+    override fun update(node: NeverDecreaseWidthNode) {
+        error("This should never be called")
+    }
+}
+
+private class NeverDecreaseWidthNode : Modifier.Node(), LayoutModifierNode {
+    private var minWidth = 0
+
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints,
+    ): MeasureResult {
+        val placeable = measurable.measure(Constraints(minWidth = minWidth).constrain(constraints))
+        val width = placeable.width
+        val height = placeable.height
+
+        minWidth = maxOf(minWidth, width)
+
+        return layout(width, height) { placeable.place(0, 0) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
index d24edda..d25ca28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
@@ -72,7 +72,7 @@
 
     private fun initializeStatusBarForDisplay(displayId: Int, result: RegisterStatusBarResult) {
         if ((result.mTransientBarTypes and WindowInsets.Type.statusBars()) != 0) {
-            statusBarModeRepository.forDisplay(displayId).showTransient()
+            statusBarModeRepository.forDisplay(displayId)?.showTransient()
         }
         val commandQueueCallbacks = commandQueueCallbacksLazy.get()
         commandQueueCallbacks.onSystemBarAttributesChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
index 9e9a38e..b057fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
@@ -89,21 +89,26 @@
     }
 
     private fun createAndStartOrchestratorForDisplay(displayId: Int) {
+        val statusBarModeRepository = statusBarModeRepositoryStore.forDisplay(displayId) ?: return
+        val statusBarInitializer = initializerStore.forDisplay(displayId) ?: return
+        val statusBarWindowController =
+            statusBarWindowControllerStore.forDisplay(displayId) ?: return
+        val autoHideController = autoHideControllerStore.forDisplay(displayId) ?: return
         statusBarOrchestratorFactory
             .create(
                 displayId,
                 displayScopeRepository.scopeForDisplay(displayId),
                 statusBarWindowStateRepositoryStore.forDisplay(displayId),
-                statusBarModeRepositoryStore.forDisplay(displayId),
-                initializerStore.forDisplay(displayId),
-                statusBarWindowControllerStore.forDisplay(displayId),
-                autoHideControllerStore.forDisplay(displayId),
+                statusBarModeRepository,
+                statusBarInitializer,
+                statusBarWindowController,
+                autoHideController,
             )
             .start()
     }
 
     private fun createAndStartInitializerForDisplay(displayId: Int) {
-        statusBarInitializerStore.forDisplay(displayId).start()
+        statusBarInitializerStore.forDisplay(displayId)?.start()
     }
 
     private fun startPrivacyDotForDisplay(displayId: Int) {
@@ -111,6 +116,6 @@
             // For the default display, privacy dot is started via ScreenDecorations
             return
         }
-        privacyDotWindowControllerStore.forDisplay(displayId).start()
+        privacyDotWindowControllerStore.forDisplay(displayId)?.start()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 4c54fc4..1e127ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -20,9 +20,11 @@
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.CoreStartable
 import com.android.systemui.fragments.FragmentHostManager
+import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewUpdatedListener
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController
 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
 import com.android.systemui.statusbar.phone.PhoneStatusBarView
@@ -34,7 +36,6 @@
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
-import java.lang.IllegalStateException
 import javax.inject.Provider
 
 /**
@@ -75,6 +76,8 @@
         fun create(
             statusBarWindowController: StatusBarWindowController,
             statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+            statusBarConfigurationController: StatusBarConfigurationController,
+            darkIconDispatcher: DarkIconDispatcher,
         ): StatusBarInitializer
     }
 }
@@ -84,6 +87,8 @@
 constructor(
     @Assisted private val statusBarWindowController: StatusBarWindowController,
     @Assisted private val statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+    @Assisted private val statusBarConfigurationController: StatusBarConfigurationController,
+    @Assisted private val darkIconDispatcher: DarkIconDispatcher,
     private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
     private val statusBarRootFactory: StatusBarRootFactory,
     private val componentFactory: HomeStatusBarComponent.Factory,
@@ -131,23 +136,32 @@
                 ->
                 val phoneStatusBarView = cv.findViewById<PhoneStatusBarView>(R.id.status_bar)
                 component =
-                    componentFactory.create(phoneStatusBarView).also { component ->
-                        // CollapsedStatusBarFragment used to be responsible initializing
-                        component.init()
-
-                        statusBarViewUpdatedListener?.onStatusBarViewUpdated(
-                            component.phoneStatusBarViewController,
-                            component.phoneStatusBarTransitions,
+                    componentFactory
+                        .create(
+                            phoneStatusBarView,
+                            statusBarConfigurationController,
+                            statusBarWindowController,
+                            darkIconDispatcher,
                         )
+                        .also { component ->
+                            // CollapsedStatusBarFragment used to be responsible initializing
+                            component.init()
 
-                        if (StatusBarConnectedDisplays.isEnabled) {
-                            statusBarModePerDisplayRepository.onStatusBarViewInitialized(component)
-                        } else {
-                            creationListeners.forEach { listener ->
-                                listener.onStatusBarViewInitialized(component)
+                            statusBarViewUpdatedListener?.onStatusBarViewUpdated(
+                                component.phoneStatusBarViewController,
+                                component.phoneStatusBarTransitions,
+                            )
+
+                            if (StatusBarConnectedDisplays.isEnabled) {
+                                statusBarModePerDisplayRepository.onStatusBarViewInitialized(
+                                    component
+                                )
+                            } else {
+                                creationListeners.forEach { listener ->
+                                    listener.onStatusBarViewInitialized(component)
+                                }
                             }
                         }
-                    }
             }
 
         // Add the new compose view to the hierarchy because we don't use fragment transactions
@@ -163,9 +177,11 @@
                 CollapsedStatusBarFragment.TAG,
                 object : FragmentHostManager.FragmentListener {
                     override fun onFragmentViewCreated(tag: String, fragment: Fragment) {
-                        component =
-                            (fragment as CollapsedStatusBarFragment).homeStatusBarComponent
-                                ?: throw IllegalStateException()
+                        val statusBarFragment = fragment as CollapsedStatusBarFragment
+                        if (statusBarFragment.homeStatusBarComponent == null) {
+                            return
+                        }
+                        component = fragment.homeStatusBarComponent
                         statusBarViewUpdatedListener?.onStatusBarViewUpdated(
                             component!!.phoneStatusBarViewController,
                             component!!.phoneStatusBarTransitions,
@@ -195,6 +211,8 @@
         override fun create(
             statusBarWindowController: StatusBarWindowController,
             statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+            statusBarConfigurationController: StatusBarConfigurationController,
+            darkIconDispatcher: DarkIconDispatcher,
         ): StatusBarInitializerImpl
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
index 4f815c1..de6cd07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
@@ -22,6 +22,8 @@
 import com.android.systemui.display.data.repository.PerDisplayStore
 import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import javax.inject.Inject
@@ -39,6 +41,8 @@
     private val factory: StatusBarInitializer.Factory,
     private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
     private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
+    private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
+    private val darkIconDispatcherStore: DarkIconDispatcherStore,
 ) :
     StatusBarInitializerStore,
     PerDisplayStoreImpl<StatusBarInitializer>(backgroundApplicationScope, displayRepository) {
@@ -47,10 +51,19 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer {
+    override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer? {
+        val statusBarWindowController =
+            statusBarWindowControllerStore.forDisplay(displayId) ?: return null
+        val statusBarModePerDisplayRepository =
+            statusBarModeRepositoryStore.forDisplay(displayId) ?: return null
+        val statusBarConfigurationController =
+            statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+        val darkIconDispatcher = darkIconDispatcherStore.forDisplay(displayId) ?: return null
         return factory.create(
-            statusBarWindowController = statusBarWindowControllerStore.forDisplay(displayId),
-            statusBarModePerDisplayRepository = statusBarModeRepositoryStore.forDisplay(displayId),
+            statusBarWindowController,
+            statusBarModePerDisplayRepository,
+            statusBarConfigurationController,
+            darkIconDispatcher,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
index 8183a48..041f3c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
@@ -65,8 +65,9 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): SysuiDarkIconDispatcher {
-        val properties = displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+    override fun createInstanceForDisplay(displayId: Int): SysuiDarkIconDispatcher? {
+        val properties =
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
         return factory.create(displayId, properties.context)
     }
 
@@ -103,7 +104,7 @@
     override val defaultDisplay: DarkIconDispatcher
         get() = store.defaultDisplay
 
-    override fun forDisplay(displayId: Int): DarkIconDispatcher = store.forDisplay(displayId)
+    override fun forDisplay(displayId: Int): DarkIconDispatcher? = store.forDisplay(displayId)
 }
 
 @Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
index e498755..c629d10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
@@ -49,13 +49,16 @@
     LightBarControllerStore,
     PerDisplayStoreImpl<LightBarController>(backgroundApplicationScope, displayRepository) {
 
-    override fun createInstanceForDisplay(displayId: Int): LightBarController {
+    override fun createInstanceForDisplay(displayId: Int): LightBarController? {
+        val darkIconDispatcher = darkIconDispatcherStore.forDisplay(displayId) ?: return null
+        val statusBarModePerDisplayRepository =
+            statusBarModeRepositoryStore.forDisplay(displayId) ?: return null
         return factory
             .create(
                 displayId,
                 displayScopeRepository.scopeForDisplay(displayId),
-                darkIconDispatcherStore.forDisplay(displayId),
-                statusBarModeRepositoryStore.forDisplay(displayId),
+                darkIconDispatcher,
+                statusBarModePerDisplayRepository,
             )
             .also { it.start() }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
index bd61c44..d48c94b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
@@ -52,11 +52,14 @@
     PrivacyDotViewControllerStore,
     PerDisplayStoreImpl<PrivacyDotViewController>(backgroundApplicationScope, displayRepository) {
 
-    override fun createInstanceForDisplay(displayId: Int): PrivacyDotViewController {
+    override fun createInstanceForDisplay(displayId: Int): PrivacyDotViewController? {
+        val configurationController =
+            statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+        val contentInsetsProvider = contentInsetsProviderStore.forDisplay(displayId) ?: return null
         return factory.create(
             displayScopeRepository.scopeForDisplay(displayId),
-            statusBarConfigurationControllerStore.forDisplay(displayId),
-            contentInsetsProviderStore.forDisplay(displayId),
+            configurationController,
+            contentInsetsProvider,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
index a1f5655..086cc99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
@@ -58,15 +58,18 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): PrivacyDotWindowController {
+    override fun createInstanceForDisplay(displayId: Int): PrivacyDotWindowController? {
         if (displayId == Display.DEFAULT_DISPLAY) {
             throw IllegalArgumentException("This class should only be used for connected displays")
         }
         val displayWindowProperties =
             displayWindowPropertiesRepository.get(displayId, TYPE_NAVIGATION_BAR_PANEL)
+                ?: return null
+        val privacyDotViewController =
+            privacyDotViewControllerStore.forDisplay(displayId) ?: return null
         return windowControllerFactory.create(
             displayId = displayId,
-            privacyDotViewController = privacyDotViewControllerStore.forDisplay(displayId),
+            privacyDotViewController = privacyDotViewController,
             viewCaptureAwareWindowManager =
                 viewCaptureAwareWindowManagerFactory.create(displayWindowProperties.windowManager),
             inflater = displayWindowProperties.layoutInflater,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
index 6cf2c73..38cea83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
@@ -62,9 +62,9 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): StatusBarConfigurationController {
+    override fun createInstanceForDisplay(displayId: Int): StatusBarConfigurationController? {
         val displayWindowProperties =
-            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
         return configurationControllerFactory.create(displayWindowProperties.context)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
index e471b12..554c46f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
@@ -59,13 +59,17 @@
         displayRepository,
     ) {
 
-    override fun createInstanceForDisplay(displayId: Int): StatusBarContentInsetsProvider {
-        val context = displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR).context
+    override fun createInstanceForDisplay(displayId: Int): StatusBarContentInsetsProvider? {
+        val displayWindowProperties =
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
+        val context = displayWindowProperties.context
+        val configurationController =
+            statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
         val cameraProtectionLoader = cameraProtectionLoaderFactory.create(context)
         return factory
             .create(
                 context,
-                statusBarConfigurationControllerStore.forDisplay(displayId),
+                configurationController,
                 sysUICutoutProviderFactory.create(context, cameraProtectionLoader),
             )
             .also { it.start() }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
index 7760f58..ffc1255 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
@@ -62,11 +62,17 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): SystemEventChipAnimationController {
+    override fun createInstanceForDisplay(displayId: Int): SystemEventChipAnimationController? {
+        val displayWindowProperties =
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
+        val statusBarWindowController =
+            statusBarWindowControllerStore.forDisplay(displayId) ?: return null
+        val contentInsetsProvider =
+            statusBarContentInsetsProviderStore.forDisplay(displayId) ?: return null
         return factory.create(
-            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR).context,
-            statusBarWindowControllerStore.forDisplay(displayId),
-            statusBarContentInsetsProviderStore.forDisplay(displayId),
+            displayWindowProperties.context,
+            statusBarWindowController,
+            contentInsetsProvider,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
index f2bb7b1..4b9721e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
@@ -72,5 +72,5 @@
     }
 
     private fun controllersForAllDisplays() =
-        displayRepository.displays.value.map { controllerStore.forDisplay(it.displayId) }
+        displayRepository.displays.value.mapNotNull { controllerStore.forDisplay(it.displayId) }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt
index 9928ac6..f7799bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.events
 
+import android.util.Log
 import android.view.Display
 import android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM
 import android.view.DisplayCutout.BOUNDS_POSITION_LEFT
@@ -23,6 +24,7 @@
 import android.view.DisplayCutout.BOUNDS_POSITION_TOP
 import android.view.LayoutInflater
 import android.view.View
+import android.view.WindowManager.InvalidDisplayException
 import android.view.WindowManager.LayoutParams.WRAP_CONTENT
 import android.widget.FrameLayout
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager
@@ -97,7 +99,17 @@
         // PrivacyDotViewController expects the dot view to have a FrameLayout parent.
         val rootView = FrameLayout(context)
         rootView.addView(this)
-        viewCaptureAwareWindowManager.addView(rootView, params)
+        try {
+            // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+            // after being added, and initialization hasn't finished yet.
+            viewCaptureAwareWindowManager.addView(rootView, params)
+        } catch (e: InvalidDisplayException) {
+            Log.e(
+                TAG,
+                "Unable to add view to WM. Display with id $displayId does not exist anymore",
+                e,
+            )
+        }
     }
 
     @AssistedFactory
@@ -109,4 +121,8 @@
             inflater: LayoutInflater,
         ): PrivacyDotWindowController
     }
+
+    private companion object {
+        const val TAG = "PrivacyDotWindowController"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt
index 227a1fe..eb55856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt
@@ -62,8 +62,10 @@
 
     override fun iconView(key: String): StatusBarIconView? {
         val entry = notifCollection.getEntry(key) ?: return null
+        val displayWindowProperties =
+            displayWindowPropertiesInteractor.getForStatusBar(displayId) ?: return null
         return cachedIcons.computeIfAbsent(key) {
-            val context = displayWindowPropertiesInteractor.getForStatusBar(displayId).context
+            val context = displayWindowProperties.context
             iconManager.createSbIconView(context, entry)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index 2ba28a6..e103282 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -68,13 +68,14 @@
             .distinctUntilChanged()
 
     /** The colors with which to display the notification icons. */
-    fun iconColors(displayId: Int): Flow<NotificationIconColors> =
-        darkIconInteractor
+    fun iconColors(displayId: Int): Flow<NotificationIconColors> {
+        return darkIconInteractor
             .darkState(displayId)
             .map { (areas: Collection<Rect>, tint: Int) -> IconColorsImpl(tint, areas) }
             .flowOn(bgContext)
             .conflate()
             .distinctUntilChanged()
+    }
 
     /** [NotificationIconsViewData] indicating which icons to display in the view. */
     val icons: Flow<NotificationIconsViewData> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt
index 64d1654..5106ccc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/NotificationShelfIconContainer.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.util.AttributeSet
 import android.view.View
+import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism
 import com.android.systemui.statusbar.phone.NotificationIconContainer
 import kotlin.math.max
@@ -35,7 +36,8 @@
     /**
      * @return The left boundary (not the RTL compatible start) of the area that icons can be added.
      */
-    override fun getLeftBound(): Float {
+    @VisibleForTesting
+    public override fun getLeftBound(): Float {
         if (!NotificationMinimalism.isEnabled) {
             return super.getLeftBound()
         }
@@ -49,7 +51,8 @@
     /**
      * @return The right boundary (not the RTL compatible end) of the area that icons can be added.
      */
-    override fun getRightBound(): Float {
+    @VisibleForTesting
+    public override fun getRightBound(): Float {
         if (!NotificationMinimalism.isEnabled) {
             return super.getRightBound()
         }
@@ -80,7 +83,8 @@
         return actualWidth - iconState.xTranslation - iconView.width
     }
 
-    private val isAlignedToRight: Boolean
+    @VisibleForTesting
+    val isAlignedToRight: Boolean
         get() {
             if (!NotificationMinimalism.isEnabled) {
                 return isLayoutRtl
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
index 744f969..2ae38dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
@@ -47,9 +47,9 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): AutoHideController {
+    override fun createInstanceForDisplay(displayId: Int): AutoHideController? {
         val displayWindowProperties =
-            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
         return autoHideControllerFactory.create(displayWindowProperties.context)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
index ea67f1c..ca0c1ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
@@ -499,9 +499,9 @@
         /** Creates a {@link LightBarControllerImpl}. */
         LightBarControllerImpl create(
                 int displayId,
-                CoroutineScope coroutineScope,
-                DarkIconDispatcher darkIconDispatcher,
-                StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
+                @NonNull CoroutineScope coroutineScope,
+                @NonNull DarkIconDispatcher darkIconDispatcher,
+                @NonNull StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
     }
 
     public static class LegacyFactory implements LightBarController.Factory {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
index 394502b..031754d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
 import com.android.systemui.statusbar.data.repository.SysuiDarkIconDispatcherStore
 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
@@ -54,7 +55,7 @@
 ) {
 
     /** Creates listener always using the same light color for overlay */
-    fun createListener(view: View) =
+    fun createListener(view: View): StatusOverlayHoverListener =
         StatusOverlayHoverListener(
             view,
             configurationController,
@@ -65,8 +66,10 @@
     /**
      * Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
      */
-    fun createDarkAwareListener(view: View) =
-        createDarkAwareListener(view, view.darkIconDispatcher.darkChangeFlow())
+    fun createDarkAwareListener(view: View): StatusOverlayHoverListener? {
+        val darkIconDispatcher = view.darkIconDispatcher ?: return null
+        return createDarkAwareListener(view, darkIconDispatcher.darkChangeFlow())
+    }
 
     /**
      * Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
@@ -78,27 +81,34 @@
         rightHoverMargin: Int = 0,
         topHoverMargin: Int = 0,
         bottomHoverMargin: Int = 0,
-    ) =
-        createDarkAwareListener(
+    ): StatusOverlayHoverListener? {
+        val darkIconDispatcher = view.darkIconDispatcher ?: return null
+        return createDarkAwareListener(
             view,
-            view.darkIconDispatcher.darkChangeFlow(),
+            darkIconDispatcher.darkChangeFlow(),
             leftHoverMargin,
             rightHoverMargin,
             topHoverMargin,
             bottomHoverMargin,
         )
+    }
 
     /**
      * Creates listener using provided [DarkChange] producer to determine light or dark color of the
      * overlay
      */
-    fun createDarkAwareListener(view: View, darkFlow: StateFlow<DarkChange>) =
-        StatusOverlayHoverListener(
+    fun createDarkAwareListener(
+        view: View,
+        darkFlow: StateFlow<DarkChange>,
+    ): StatusOverlayHoverListener? {
+        val configurationController = view.statusBarConfigurationController ?: return null
+        return StatusOverlayHoverListener(
             view,
-            view.statusBarConfigurationController,
+            configurationController,
             view.resources,
             darkFlow.map { toHoverTheme(view, it) },
         )
+    }
 
     private fun createDarkAwareListener(
         view: View,
@@ -107,10 +117,11 @@
         rightHoverMargin: Int = 0,
         topHoverMargin: Int = 0,
         bottomHoverMargin: Int = 0,
-    ) =
-        StatusOverlayHoverListener(
+    ): StatusOverlayHoverListener? {
+        val configurationController = view.statusBarConfigurationController ?: return null
+        return StatusOverlayHoverListener(
             view,
-            view.statusBarConfigurationController,
+            configurationController,
             view.resources,
             darkFlow.map { toHoverTheme(view, it) },
             leftHoverMargin,
@@ -118,11 +129,12 @@
             topHoverMargin,
             bottomHoverMargin,
         )
+    }
 
-    private val View.statusBarConfigurationController
+    private val View.statusBarConfigurationController: StatusBarConfigurationController?
         get() = statusBarConfigurationControllerStore.forDisplay(context.displayId)
 
-    private val View.darkIconDispatcher
+    private val View.darkIconDispatcher: SysuiDarkIconDispatcher?
         get() = darkIconDispatcherStore.forDisplay(context.displayId)
 
     private fun toHoverTheme(view: View, darkChange: DarkChange): HoverTheme {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 4f32aaa26..037dda9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -31,8 +31,10 @@
 import com.android.systemui.statusbar.core.StatusBarInitializerStore
 import com.android.systemui.statusbar.core.StatusBarOrchestrator
 import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
 import com.android.systemui.statusbar.data.repository.PrivacyDotViewControllerStoreModule
 import com.android.systemui.statusbar.data.repository.PrivacyDotWindowControllerStoreModule
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
 import com.android.systemui.statusbar.events.PrivacyDotViewControllerModule
 import com.android.systemui.statusbar.phone.AutoHideControllerStore
@@ -107,10 +109,14 @@
             implFactory: StatusBarInitializerImpl.Factory,
             statusBarWindowControllerStore: StatusBarWindowControllerStore,
             statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
+            statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
+            darkIconDispatcherStore: DarkIconDispatcherStore,
         ): StatusBarInitializerImpl {
             return implFactory.create(
                 statusBarWindowControllerStore.defaultDisplay,
                 statusBarModeRepositoryStore.defaultDisplay,
+                statusBarConfigurationControllerStore.defaultDisplay,
+                darkIconDispatcherStore.defaultDisplay,
             )
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
index 49356eb..0464654 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
@@ -15,12 +15,14 @@
  */
 package com.android.systemui.statusbar.phone.data.repository
 
+import android.util.Log
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.data.repository.SysuiDarkIconDispatcherStore
 import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
 import dagger.Binds
 import dagger.Module
 import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 
 /** Dark-mode state for tinting icons. */
@@ -33,8 +35,22 @@
 @Inject
 constructor(private val darkIconDispatcherStore: SysuiDarkIconDispatcherStore) :
     DarkIconRepository {
-    override fun darkState(displayId: Int): StateFlow<DarkChange> =
-        darkIconDispatcherStore.forDisplay(displayId).darkChangeFlow()
+    override fun darkState(displayId: Int): StateFlow<DarkChange> {
+        val perDisplayDakIconDispatcher = darkIconDispatcherStore.forDisplay(displayId)
+        if (perDisplayDakIconDispatcher == null) {
+            Log.e(
+                TAG,
+                "DarkIconDispatcher for display $displayId is null. Returning flow of " +
+                    "DarkChange.EMPTY",
+            )
+            return MutableStateFlow(DarkChange.EMPTY)
+        }
+        return perDisplayDakIconDispatcher.darkChangeFlow()
+    }
+
+    private companion object {
+        const val TAG = "DarkIconRepositoryImpl"
+    }
 }
 
 @Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
index ed8b3e8..b15fffb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
@@ -34,8 +34,8 @@
 @Inject
 constructor(private val repository: StatusBarModeRepositoryStore) {
 
-    fun isLowProfile(displayId: Int): Flow<Boolean> =
-        repository.forDisplay(displayId).statusBarMode.map {
+    fun isLowProfile(displayId: Int): Flow<Boolean>? =
+        repository.forDisplay(displayId)?.statusBarMode?.map {
             when (it) {
                 StatusBarMode.LIGHTS_OUT,
                 StatusBarMode.LIGHTS_OUT_TRANSPARENT -> true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index d257288..c31e34c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -47,6 +47,7 @@
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
@@ -59,6 +60,9 @@
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
 import com.android.systemui.statusbar.core.StatusBarRootModernization;
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -78,6 +82,8 @@
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener;
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
 import com.android.systemui.util.CarrierConfigTracker;
@@ -156,6 +162,9 @@
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final NotificationIconContainerStatusBarViewBinder mNicViewBinder;
     private final DemoModeController mDemoModeController;
+    private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
+    private final StatusBarConfigurationControllerStore mStatusBarConfigurationControllerStore;
+    private final DarkIconDispatcherStore mDarkIconDispatcherStore;
 
     private List<String> mBlockedIcons = new ArrayList<>();
     private Map<Startable, Startable.State> mStartableStates = new ArrayMap<>();
@@ -263,7 +272,10 @@
             DumpManager dumpManager,
             StatusBarWindowStateController statusBarWindowStateController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            DemoModeController demoModeController) {
+            DemoModeController demoModeController,
+            StatusBarWindowControllerStore statusBarWindowControllerStore,
+            StatusBarConfigurationControllerStore statusBarConfigurationControllerStore,
+            DarkIconDispatcherStore darkIconDispatcherStore) {
         mHomeStatusBarComponentFactory = homeStatusBarComponentFactory;
         mOngoingCallController = ongoingCallController;
         mAnimationScheduler = animationScheduler;
@@ -287,6 +299,9 @@
         mStatusBarWindowStateController = statusBarWindowStateController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mDemoModeController = demoModeController;
+        mStatusBarWindowControllerStore = statusBarWindowControllerStore;
+        mStatusBarConfigurationControllerStore = statusBarConfigurationControllerStore;
+        mDarkIconDispatcherStore = darkIconDispatcherStore;
     }
 
     private final DemoMode mDemoModeCallback = new DemoMode() {
@@ -337,8 +352,27 @@
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mDumpManager.registerDumpable(getDumpableName(), this);
-        mHomeStatusBarComponent = mHomeStatusBarComponentFactory.create(
-                (PhoneStatusBarView) getView());
+        int displayId = view.getContext().getDisplayId();
+        StatusBarConfigurationController configurationController =
+                mStatusBarConfigurationControllerStore.forDisplay(displayId);
+        if (configurationController == null) {
+            return;
+        }
+        StatusBarWindowController statusBarWindowController =
+                mStatusBarWindowControllerStore.forDisplay(displayId);
+        if (statusBarWindowController == null) {
+            return;
+        }
+        DarkIconDispatcher darkIconDispatcher = mDarkIconDispatcherStore.forDisplay(displayId);
+        if (darkIconDispatcher == null) {
+            return;
+        }
+        mHomeStatusBarComponent =
+                mHomeStatusBarComponentFactory.create(
+                        (PhoneStatusBarView) getView(),
+                        configurationController,
+                        statusBarWindowController,
+                        darkIconDispatcher);
         mHomeStatusBarComponent.init();
         mStartableStates.clear();
         for (Startable startable : mHomeStatusBarComponent.getStartables()) {
@@ -453,6 +487,9 @@
     @Override
     public void onResume() {
         super.onResume();
+        if (mHomeStatusBarComponent == null) {
+            return;
+        }
         mCommandQueue.addCallback(this);
         mStatusBarStateController.addCallback(this);
         initOngoingCallChip();
@@ -468,6 +505,9 @@
     @Override
     public void onPause() {
         super.onPause();
+        if (mHomeStatusBarComponent == null) {
+            return;
+        }
         mCommandQueue.removeCallback(this);
         mStatusBarStateController.removeCallback(this);
         if (!StatusBarRootModernization.isEnabled()) {
@@ -480,6 +520,9 @@
     @Override
     public void onDestroyView() {
         super.onDestroyView();
+        if (mHomeStatusBarComponent == null) {
+            return;
+        }
         mStatusBarIconController.removeIconGroup(mDarkIconManager);
         mCarrierConfigTracker.removeCallback(mCarrierConfigCallback);
         mCarrierConfigTracker.removeDataSubscriptionChangedListener(mDefaultDataListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java
index f8ad0f2..5837752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java
@@ -20,6 +20,7 @@
 import com.android.systemui.dagger.qualifiers.DisplaySpecific;
 import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.LegacyLightsOutNotifController;
@@ -29,6 +30,7 @@
 import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
 import com.android.systemui.statusbar.phone.StatusBarDemoMode;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
 
 import dagger.BindsInstance;
 import dagger.Subcomponent;
@@ -57,7 +59,10 @@
     interface Factory {
         /** */
         HomeStatusBarComponent create(
-                @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView);
+                @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView,
+                @BindsInstance StatusBarConfigurationController configurationController,
+                @BindsInstance StatusBarWindowController statusBarWindowController,
+                @BindsInstance @DisplaySpecific DarkIconDispatcher darkIconDispatcher);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
index 182f8d7..6a331b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
@@ -22,19 +22,14 @@
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.DisplaySpecific;
 import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
-import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
-import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
 import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
-import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 
 import dagger.Module;
 import dagger.Provides;
@@ -149,29 +144,4 @@
     static int displayId(@RootView PhoneStatusBarView view) {
         return view.getContext().getDisplayId();
     }
-
-    /** */
-    @Provides
-    @HomeStatusBarScope
-    static StatusBarConfigurationController configurationController(
-            @DisplaySpecific int displayId, StatusBarConfigurationControllerStore store) {
-        return store.forDisplay(displayId);
-    }
-
-    /** */
-    @Provides
-    @HomeStatusBarScope
-    static StatusBarWindowController provideWindowController(
-            @DisplaySpecific int displayId, StatusBarWindowControllerStore store) {
-        return store.forDisplay(displayId);
-    }
-
-    /** */
-    @Provides
-    @HomeStatusBarScope
-    @DisplaySpecific
-    static DarkIconDispatcher darkIconDispatcher(
-            @DisplaySpecific int displayId, DarkIconDispatcherStore store) {
-        return store.forDisplay(displayId);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index c3299bb..7243ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -70,6 +70,8 @@
 ) {
     fun create(root: ViewGroup, andThen: (ViewGroup) -> Unit): ComposeView {
         val composeView = ComposeView(root.context)
+        val darkIconDispatcher =
+            darkIconDispatcherStore.forDisplay(root.context.displayId) ?: return composeView
         composeView.apply {
             setContent {
                 StatusBarRoot(
@@ -80,7 +82,7 @@
                     darkIconManagerFactory = darkIconManagerFactory,
                     iconController = iconController,
                     ongoingCallController = ongoingCallController,
-                    darkIconDispatcher = darkIconDispatcherStore.forDisplay(root.context.displayId),
+                    darkIconDispatcher = darkIconDispatcher,
                     eventAnimationInteractor = eventAnimationInteractor,
                     onViewCreated = andThen,
                 )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index dcfbc5d..c9cc173 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -63,6 +63,7 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
@@ -216,7 +217,7 @@
         } else {
             combine(
                     notificationsInteractor.areAnyNotificationsPresent,
-                    lightsOutInteractor.isLowProfile(displayId),
+                    lightsOutInteractor.isLowProfile(displayId) ?: flowOf(false),
                 ) { hasNotifications, isLowProfile ->
                     hasNotifications && isLowProfile
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index 811a2ec..848e91d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -163,7 +163,18 @@
         mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
         Trace.endSection();
 
-        mWindowManager.addView(mStatusBarWindowView, mLp);
+        try {
+            mWindowManager.addView(mStatusBarWindowView, mLp);
+        } catch (WindowManager.InvalidDisplayException e) {
+            // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+            // after being added, and initialization hasn't finished yet.
+            Log.e(
+                    TAG,
+                    "Unable to add view to WindowManager. Display with id "
+                            + mContext.getDisplayId()
+                            + " doesn't exist anymore.",
+                    e);
+        }
         mLpChanged.copyFrom(mLp);
 
         mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations);
@@ -176,7 +187,15 @@
     public void stop() {
         StatusBarConnectedDisplays.assertInNewMode();
 
-        mWindowManager.removeView(mStatusBarWindowView);
+        try {
+            mWindowManager.removeView(mStatusBarWindowView);
+        } catch (IllegalArgumentException e) {
+            // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+            // after being added, and initialization hasn't finished yet.
+            // When that happens, adding the View to WindowManager fails, and therefore removing
+            // it here will fail too, since it wasn't added in the first place.
+            Log.e(TAG, "Failed to remove View from WindowManager. View was not attached", e);
+        }
 
         if (StatusBarRootModernization.isEnabled()) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index 7403161..f7688d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -54,19 +54,23 @@
         StatusBarConnectedDisplays.assertInNewMode()
     }
 
-    override fun createInstanceForDisplay(displayId: Int): StatusBarWindowController {
+    override fun createInstanceForDisplay(displayId: Int): StatusBarWindowController? {
         val statusBarDisplayContext =
             displayWindowPropertiesRepository.get(
                 displayId = displayId,
                 windowType = WindowManager.LayoutParams.TYPE_STATUS_BAR,
-            )
+            ) ?: return null
+        val statusBarConfigurationController =
+            statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+        val contentInsetsProvider =
+            statusBarContentInsetsProviderStore.forDisplay(displayId) ?: return null
         val viewCaptureAwareWindowManager =
             viewCaptureAwareWindowManagerFactory.create(statusBarDisplayContext.windowManager)
         return controllerFactory.create(
             statusBarDisplayContext.context,
             viewCaptureAwareWindowManager,
-            statusBarConfigurationControllerStore.forDisplay(displayId),
-            statusBarContentInsetsProviderStore.forDisplay(displayId),
+            statusBarConfigurationController,
+            contentInsetsProvider,
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
index 8bb0279..8733eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt
@@ -71,6 +71,8 @@
 
     fun CoroutineScope.bind(view: View) {
         val volumeDialogBackgroundView = view.requireViewById<View>(R.id.volume_dialog_background)
+        val ringerHBackgroundView =
+            view.requireViewById<View>(R.id.volume_ringer_horizontal_background)
         val drawerContainer = view.requireViewById<MotionLayout>(R.id.volume_ringer_drawer)
         val unselectedButtonUiModel = RingerButtonUiModel.getUnselectedButton(view.context)
         val selectedButtonUiModel = RingerButtonUiModel.getSelectedButton(view.context)
@@ -84,6 +86,11 @@
             )
         var backgroundAnimationProgress: Float by
             Delegates.observable(0F) { _, _, progress ->
+                ringerHBackgroundView.applyCorners(
+                    fullRadius = volumeDialogBgFullRadius,
+                    diff = volumeDialogBgFullRadius - volumeDialogBgSmallRadius,
+                    progress,
+                )
                 volumeDialogBackgroundView.applyCorners(
                     fullRadius = volumeDialogBgFullRadius,
                     diff = volumeDialogBgFullRadius - volumeDialogBgSmallRadius,
@@ -95,6 +102,7 @@
         }
         drawerContainer.setTransitionListener(ringerDrawerTransitionListener)
         volumeDialogBackgroundView.background = volumeDialogBackgroundView.background.mutate()
+        ringerHBackgroundView.background = ringerHBackgroundView.background.mutate()
 
         viewModel.ringerViewModel
             .mapLatest { ringerState ->
@@ -184,6 +192,8 @@
                                 )
                                 volumeDialogBackgroundView.background =
                                     volumeDialogBackgroundView.background.mutate()
+                                ringerHBackgroundView.background =
+                                    ringerHBackgroundView.background.mutate()
                             }
                         }
                     }
@@ -193,6 +203,9 @@
                         volumeDialogBackgroundView.setBackgroundResource(
                             R.drawable.volume_dialog_background
                         )
+                        ringerHBackgroundView.setBackgroundResource(
+                            R.drawable.volume_dialog_background
+                        )
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt
index 25ba1bd..69ffa38 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/RingerDrawerConstraintsUtils.kt
@@ -119,6 +119,15 @@
         )
         when (lastOrientation) {
             ORIENTATION_LANDSCAPE -> {
+                if (index == 0) {
+                    setMargin(
+                        button.id,
+                        ConstraintSet.LEFT,
+                        motionLayout.context.resources.getDimensionPixelSize(
+                            R.dimen.volume_dialog_ringer_drawer_left_margin
+                        ),
+                    )
+                }
                 setButtonPositionLandscapeConstraints(motionLayout, index, button)
                 if (index != motionLayout.childCount - 1) {
                     setMargin(
@@ -134,6 +143,9 @@
                 setMargin(button.id, ConstraintSet.BOTTOM, 0)
             }
             ORIENTATION_PORTRAIT -> {
+                if (index == 0) {
+                    setMargin(button.id, ConstraintSet.LEFT, 0)
+                }
                 setButtonPositionPortraitConstraints(motionLayout, index, button)
                 if (index != motionLayout.childCount - 1) {
                     setMargin(
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 51a7b5f..bc9d4c7 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
@@ -42,6 +42,7 @@
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
@@ -95,6 +96,8 @@
     private Lazy<ViewCapture> mLazyViewCapture;
     @Mock
     private NavigationModeController mNavigationModeController;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
 
     @Before
     public void setUp() throws Exception {
@@ -170,7 +173,7 @@
         mController = setUpController();
         mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager,
                 mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
-                mNavigationModeController);
+                mNavigationModeController, mHearingAidDeviceManager);
         captureKeyguardUpdateMonitorCallback();
         mKeyguardCallback.onUserUnlocked();
 
@@ -198,7 +201,7 @@
         mController = setUpController();
         mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager,
                 mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
-                mNavigationModeController);
+                mNavigationModeController, mHearingAidDeviceManager);
         captureKeyguardUpdateMonitorCallback();
 
         mKeyguardCallback.onUserSwitching(fakeUserId);
@@ -213,7 +216,7 @@
         mController = setUpController();
         mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager,
                 mViewCaptureAwareWindowManager, mAccessibilityManager, mSecureSettings,
-                mNavigationModeController);
+                mNavigationModeController, mHearingAidDeviceManager);
         captureKeyguardUpdateMonitorCallback();
         mKeyguardCallback.onUserUnlocked();
         mKeyguardCallback.onKeyguardVisibilityChanged(true);
@@ -368,9 +371,9 @@
         final AccessibilityFloatingMenuController controller =
                 new AccessibilityFloatingMenuController(mContextWrapper, windowManager,
                         viewCaptureAwareWindowManager, displayManager, mAccessibilityManager,
-                        mTargetsObserver, mModeObserver, mKeyguardUpdateMonitor, mSecureSettings,
-                        displayTracker, mNavigationModeController, new Handler(
-                                mTestableLooper.getLooper()));
+                        mTargetsObserver, mModeObserver, mHearingAidDeviceManager,
+                        mKeyguardUpdateMonitor, mSecureSettings, displayTracker,
+                        mNavigationModeController, new Handler(mTestableLooper.getLooper()));
         controller.init();
 
         return controller;
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 dddaabb..856c379 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
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.graphics.PointF;
-
 import android.testing.TestableLooper;
 import android.view.View;
 import android.view.ViewPropertyAnimator;
@@ -40,6 +39,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.utils.TestUtils;
@@ -74,6 +74,8 @@
 
     @Mock
     private AccessibilityManager mAccessibilityManager;
+    @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
 
     @Before
     public void setUp() throws Exception {
@@ -82,7 +84,7 @@
                 stubWindowManager);
         final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
-                secureSettings);
+                secureSettings, mHearingAidDeviceManager);
 
         mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
                 secureSettings));
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 400b3b3..33cfb38 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
@@ -77,6 +77,7 @@
 import com.android.internal.accessibility.common.ShortcutConstants;
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
 import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.settingslib.bluetooth.HearingAidDeviceManager;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.SysuiTestableContext;
@@ -140,6 +141,8 @@
     @Mock
     private AccessibilityManager mStubAccessibilityManager;
     @Mock
+    private HearingAidDeviceManager mHearingAidDeviceManager;
+    @Mock
     private PackageManager mMockPackageManager;
     private final SecureSettings mSecureSettings = TestUtils.mockSecureSettings();
 
@@ -160,7 +163,7 @@
         doReturn(mWindowMetrics).when(mStubWindowManager).getCurrentWindowMetrics();
 
         mMenuViewModel = new MenuViewModel(
-                mSpyContext, mStubAccessibilityManager, mSecureSettings);
+                mSpyContext, mStubAccessibilityManager, mSecureSettings, mHearingAidDeviceManager);
         MenuViewAppearance menuViewAppearance = new MenuViewAppearance(
                 mSpyContext, mStubWindowManager);
         mMenuView = spy(
@@ -419,9 +422,10 @@
     @Test
     @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
     public void onDismissAction_incrementsTexMetricDismiss() {
-        mMenuViewModel.onTargetFeaturesChanged(
-                List.of(new TestAccessibilityTarget(mSpyContext, 1234),
-                        new TestAccessibilityTarget(mSpyContext, 5678)));
+        List<AccessibilityTarget> testTargets = new ArrayList<>();
+        testTargets.add(new TestAccessibilityTarget(mSpyContext, 1234));
+        testTargets.add(new TestAccessibilityTarget(mSpyContext, 5678));
+        mMenuViewModel.onTargetFeaturesChanged(testTargets);
 
         mMenuViewLayer.dispatchAccessibilityAction(R.id.action_remove_menu);
 
@@ -431,9 +435,10 @@
     @Test
     @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
     public void onEditAction_incrementsTexMetricEdit() {
-        mMenuViewModel.onTargetFeaturesChanged(
-                List.of(new TestAccessibilityTarget(mSpyContext, 1234),
-                        new TestAccessibilityTarget(mSpyContext, 5678)));
+        List<AccessibilityTarget> testTargets = new ArrayList<>();
+        testTargets.add(new TestAccessibilityTarget(mSpyContext, 1234));
+        testTargets.add(new TestAccessibilityTarget(mSpyContext, 5678));
+        mMenuViewModel.onTargetFeaturesChanged(testTargets);
 
         mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentControllerTest.java
similarity index 79%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentControllerTest.java
index 782b248..e4a49530 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDetailsContentControllerTest.java
@@ -9,8 +9,8 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.settingslib.wifi.WifiUtils.getHotspotIconResource;
-import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
-import static com.android.systemui.qs.tiles.dialog.InternetDialogController.TOAST_PARAMS_VERTICAL_WEIGHT;
+import static com.android.systemui.qs.tiles.dialog.InternetDetailsContentController.TOAST_PARAMS_HORIZONTAL_WEIGHT;
+import static com.android.systemui.qs.tiles.dialog.InternetDetailsContentController.TOAST_PARAMS_VERTICAL_WEIGHT;
 import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MAX;
 import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN;
 import static com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE;
@@ -105,7 +105,7 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class InternetDialogDelegateControllerTest extends SysuiTestCase {
+public class InternetDetailsContentControllerTest extends SysuiTestCase {
 
     private static final int SUB_ID = 1;
     private static final int SUB_ID2 = 2;
@@ -160,7 +160,7 @@
     @Mock
     private WifiUtils.InternetIconInjector mWifiIconInjector;
     @Mock
-    InternetDialogController.InternetDialogCallback mInternetDialogCallback;
+    InternetDetailsContentController.InternetDialogCallback mInternetDialogCallback;
     @Mock
     private ViewCaptureAwareWindowManager mWindowManager;
     @Mock
@@ -189,7 +189,7 @@
     private FakeFeatureFlags mFlags = new FakeFeatureFlags();
 
     private TestableResources mTestableResources;
-    private InternetDialogController mInternetDialogController;
+    private InternetDetailsContentController mInternetDetailsContentController;
     private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private List<WifiEntry> mAccessPoints = new ArrayList<>();
     private List<WifiEntry> mWifiEntries = new ArrayList<>();
@@ -229,7 +229,7 @@
         when(mSystemUIToast.getInAnimation()).thenReturn(mAnimator);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
 
-        mInternetDialogController = new InternetDialogController(mContext,
+        mInternetDetailsContentController = new InternetDetailsContentController(mContext,
                 mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
                 mSubscriptionManager, mTelephonyManager, mWifiManager,
                 mConnectivityManager, mHandler, mExecutor, mBroadcastDispatcher,
@@ -238,11 +238,11 @@
                 mCarrierConfigTracker, mLocationController, mDialogTransitionAnimator,
                 mWifiStateWorker, mFlags);
         mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
-                mInternetDialogController.mOnSubscriptionsChangedListener);
-        mInternetDialogController.onStart(mInternetDialogCallback, true);
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
-        mInternetDialogController.mActivityStarter = mActivityStarter;
-        mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
+                mInternetDetailsContentController.mOnSubscriptionsChangedListener);
+        mInternetDetailsContentController.onStart(mInternetDialogCallback, true);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.mActivityStarter = mActivityStarter;
+        mInternetDetailsContentController.mWifiIconInjector = mWifiIconInjector;
         mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, false);
         mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, false);
 
@@ -260,7 +260,7 @@
 
     @Test
     public void connectCarrierNetwork_mergedCarrierEntryCanConnect_connectAndCreateSysUiToast() {
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         when(spyController.isMobileDataEnabled()).thenReturn(true);
         when(mKeyguardStateController.isUnlocked()).thenReturn(true);
         when(mConnectivityManager.getActiveNetwork()).thenReturn(mNetwork);
@@ -282,7 +282,7 @@
 
     @Test
     public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenSettingsOff() {
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         when(spyController.isMobileDataEnabled()).thenReturn(false);
         mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
             TOAST_MESSAGE_STRING);
@@ -296,7 +296,7 @@
 
     @Test
     public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenKeyguardLocked() {
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         when(spyController.isMobileDataEnabled()).thenReturn(true);
         when(mKeyguardStateController.isUnlocked()).thenReturn(false);
 
@@ -311,8 +311,6 @@
 
     @Test
     public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenMobileIsPrimary() {
-        InternetDialogController spyController = spy(mInternetDialogController);
-        when(spyController.isMobileDataEnabled()).thenReturn(true);
         when(mKeyguardStateController.isUnlocked()).thenReturn(true);
         when(mConnectivityManager.getActiveNetwork()).thenReturn(mNetwork);
         when(mConnectivityManager.getNetworkCapabilities(mNetwork))
@@ -322,7 +320,7 @@
 
         mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now,
             TOAST_MESSAGE_STRING);
-        mInternetDialogController.connectCarrierNetwork();
+        mInternetDetailsContentController.connectCarrierNetwork();
 
         verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */);
         verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(),
@@ -333,7 +331,7 @@
     public void makeOverlayToast_withGravityFlags_addViewWithLayoutParams() {
         mTestableResources.addOverride(TOAST_MESSAGE_STRING_ID, TOAST_MESSAGE_STRING);
 
-        mInternetDialogController.makeOverlayToast(TOAST_MESSAGE_STRING_ID);
+        mInternetDetailsContentController.makeOverlayToast(TOAST_MESSAGE_STRING_ID);
 
         ArgumentCaptor<WindowManager.LayoutParams> paramsCaptor = ArgumentCaptor.forClass(
             WindowManager.LayoutParams.class);
@@ -349,7 +347,7 @@
     public void makeOverlayToast_withAnimation_verifyAnimatorStart() {
         mTestableResources.addOverride(TOAST_MESSAGE_STRING_ID, TOAST_MESSAGE_STRING);
 
-        mInternetDialogController.makeOverlayToast(TOAST_MESSAGE_STRING_ID);
+        mInternetDetailsContentController.makeOverlayToast(TOAST_MESSAGE_STRING_ID);
 
         verify(mAnimator).start();
     }
@@ -358,7 +356,7 @@
     public void getDialogTitleText_withAirplaneModeOn_returnAirplaneMode() {
         fakeAirplaneModeEnabled(true);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(),
+        assertTrue(TextUtils.equals(mInternetDetailsContentController.getDialogTitleText(),
                 getResourcesString("airplane_mode")));
     }
 
@@ -366,7 +364,7 @@
     public void getDialogTitleText_withAirplaneModeOff_returnInternet() {
         fakeAirplaneModeEnabled(false);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(),
+        assertTrue(TextUtils.equals(mInternetDetailsContentController.getDialogTitleText(),
                 getResourcesString("quick_settings_internet_label")));
     }
 
@@ -375,13 +373,13 @@
         fakeAirplaneModeEnabled(true);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isEqualTo(getResourcesString("wifi_is_off"));
 
         // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
-        mInternetDialogController.mCanConfigWifi = false;
+        mInternetDetailsContentController.mCanConfigWifi = false;
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isNotEqualTo(getResourcesString("wifi_is_off"));
     }
 
@@ -390,13 +388,13 @@
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isEqualTo(getResourcesString("wifi_is_off"));
 
         // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
-        mInternetDialogController.mCanConfigWifi = false;
+        mInternetDetailsContentController.mCanConfigWifi = false;
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isNotEqualTo(getResourcesString("wifi_is_off"));
     }
 
@@ -404,15 +402,15 @@
     public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
-        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+        mInternetDetailsContentController.onAccessPointsChanged(null /* accessPoints */);
 
-        assertThat(mInternetDialogController.getSubtitleText(true))
+        assertThat(mInternetDetailsContentController.getSubtitleText(true))
                 .isEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
 
         // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
-        mInternetDialogController.mCanConfigWifi = false;
+        mInternetDetailsContentController.mCanConfigWifi = false;
 
-        assertThat(mInternetDialogController.getSubtitleText(true))
+        assertThat(mInternetDetailsContentController.getSubtitleText(true))
                 .isNotEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
     }
 
@@ -422,13 +420,13 @@
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isEqualTo(getResourcesString("tap_a_network_to_connect"));
 
         // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
-        mInternetDialogController.mCanConfigWifi = false;
+        mInternetDetailsContentController.mCanConfigWifi = false;
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isNotEqualTo(getResourcesString("tap_a_network_to_connect"));
     }
 
@@ -438,14 +436,14 @@
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
         when(mKeyguardStateController.isUnlocked()).thenReturn(false);
 
-        assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
+        assertTrue(TextUtils.equals(mInternetDetailsContentController.getSubtitleText(false),
                 getResourcesString("unlock_to_view_networks")));
     }
 
     @Test
     public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
         mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, true);
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
         spyController.onAccessPointsChanged(null /* accessPoints */);
@@ -466,7 +464,7 @@
 
     @Test
     public void getSubtitleText_withNoService_returnNoNetworksAvailable_flagOff() {
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
         spyController.onAccessPointsChanged(null /* accessPoints */);
@@ -488,22 +486,22 @@
     public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() {
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
-        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
-        InternetDialogController spyController = spy(mInternetDialogController);
+        mInternetDetailsContentController.onAccessPointsChanged(null /* accessPoints */);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
 
         doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
         spyController.mSubIdServiceState.put(SUB_ID, mServiceState);
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isEqualTo(getResourcesString("non_carrier_network_unavailable"));
 
         // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
-        mInternetDialogController.mCanConfigWifi = false;
+        mInternetDetailsContentController.mCanConfigWifi = false;
 
         when(spyController.isMobileDataEnabled()).thenReturn(false);
 
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isNotEqualTo(getResourcesString("non_carrier_network_unavailable"));
     }
 
@@ -511,21 +509,22 @@
     public void getSubtitleText_withCarrierNetworkActiveOnly_returnNoOtherAvailable() {
         fakeAirplaneModeEnabled(false);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
-        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+        mInternetDetailsContentController.onAccessPointsChanged(null /* accessPoints */);
         when(mMergedCarrierEntry.isDefaultNetwork()).thenReturn(true);
 
-        assertThat(mInternetDialogController.getSubtitleText(false))
+        assertThat(mInternetDetailsContentController.getSubtitleText(false))
                 .isEqualTo(getResourcesString("non_carrier_network_unavailable"));
     }
 
     @Test
     public void getWifiDetailsSettingsIntent_withNoKey_returnNull() {
-        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent(null)).isNull();
+        assertThat(mInternetDetailsContentController.getWifiDetailsSettingsIntent(null)).isNull();
     }
 
     @Test
     public void getWifiDetailsSettingsIntent_withKey_returnIntent() {
-        assertThat(mInternetDialogController.getWifiDetailsSettingsIntent("test_key")).isNotNull();
+        assertThat(mInternetDetailsContentController.getWifiDetailsSettingsIntent(
+                "test_key")).isNotNull();
     }
 
     @Test
@@ -533,7 +532,7 @@
         final Drawable drawable = mock(Drawable.class);
         when(mWifiIconInjector.getIcon(anyBoolean(), anyInt())).thenReturn(drawable);
 
-        mInternetDialogController.getInternetWifiDrawable(mConnectedEntry);
+        mInternetDetailsContentController.getInternetWifiDrawable(mConnectedEntry);
 
         verify(mWifiIconInjector).getIcon(eq(false), anyInt());
         verify(drawable).setTint(mContext.getColor(R.color.connected_network_primary_color));
@@ -543,7 +542,7 @@
     public void getWifiDrawable_withWifiLevelUnreachable_returnNull() {
         when(mConnectedEntry.getLevel()).thenReturn(WIFI_LEVEL_UNREACHABLE);
 
-        assertThat(mInternetDialogController.getWifiDrawable(mConnectedEntry)).isNull();
+        assertThat(mInternetDetailsContentController.getWifiDrawable(mConnectedEntry)).isNull();
     }
 
     @Test
@@ -553,19 +552,21 @@
         Drawable hotspotDrawable = mock(Drawable.class);
         mTestableResources.addOverride(getHotspotIconResource(DEVICE_TYPE_PHONE), hotspotDrawable);
 
-        assertThat(mInternetDialogController.getWifiDrawable(entry)).isEqualTo(hotspotDrawable);
+        assertThat(mInternetDetailsContentController.getWifiDrawable(entry)).isEqualTo(
+                hotspotDrawable);
     }
 
     @Test
     public void startActivityForDialog_always_startActivityWithoutDismissShade() {
-        mInternetDialogController.startActivityForDialog(mock(Intent.class));
+        mInternetDetailsContentController.startActivityForDialog(mock(Intent.class));
 
         verify(mActivityStarter).startActivity(any(Intent.class), eq(false) /* dismissShade */);
     }
 
     @Test
     public void launchWifiDetailsSetting_withNoWifiEntryKey_doNothing() {
-        mInternetDialogController.launchWifiDetailsSetting(null /* key */, mDialogLaunchView);
+        mInternetDetailsContentController.launchWifiDetailsSetting(null /* key */,
+                mDialogLaunchView);
 
         verify(mActivityStarter, never())
                 .postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
@@ -573,7 +574,8 @@
 
     @Test
     public void launchWifiDetailsSetting_withWifiEntryKey_startActivity() {
-        mInternetDialogController.launchWifiDetailsSetting("wifi_entry_key", mDialogLaunchView);
+        mInternetDetailsContentController.launchWifiDetailsSetting("wifi_entry_key",
+                mDialogLaunchView);
 
         verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt(),
                 any());
@@ -583,22 +585,22 @@
     public void isDeviceLocked_keyguardIsUnlocked_returnFalse() {
         when(mKeyguardStateController.isUnlocked()).thenReturn(true);
 
-        assertThat(mInternetDialogController.isDeviceLocked()).isFalse();
+        assertThat(mInternetDetailsContentController.isDeviceLocked()).isFalse();
     }
 
     @Test
     public void isDeviceLocked_keyguardIsLocked_returnTrue() {
         when(mKeyguardStateController.isUnlocked()).thenReturn(false);
 
-        assertThat(mInternetDialogController.isDeviceLocked()).isTrue();
+        assertThat(mInternetDetailsContentController.isDeviceLocked()).isTrue();
     }
 
     @Test
     public void onAccessPointsChanged_canNotConfigWifi_doNothing() {
         reset(mInternetDialogCallback);
-        mInternetDialogController.mCanConfigWifi = false;
+        mInternetDetailsContentController.mCanConfigWifi = false;
 
-        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+        mInternetDetailsContentController.onAccessPointsChanged(null /* accessPoints */);
 
         verify(mInternetDialogCallback, never()).onAccessPointsChanged(any(), any(), anyBoolean());
     }
@@ -607,7 +609,7 @@
     public void onAccessPointsChanged_nullAccessPoints_callbackBothNull() {
         reset(mInternetDialogCallback);
 
-        mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+        mInternetDetailsContentController.onAccessPointsChanged(null /* accessPoints */);
 
         verify(mInternetDialogCallback).onAccessPointsChanged(null /* wifiEntries */,
                 null /* connectedEntry */, false /* hasMoreEntry */);
@@ -619,7 +621,7 @@
         mAccessPoints.clear();
         mAccessPoints.add(mConnectedEntry);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry,
@@ -632,7 +634,7 @@
         mAccessPoints.clear();
         mAccessPoints.add(mWifiEntry1);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         mWifiEntries.add(mWifiEntry1);
@@ -647,7 +649,7 @@
         mAccessPoints.add(mConnectedEntry);
         mAccessPoints.add(mWifiEntry1);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         mWifiEntries.add(mWifiEntry1);
@@ -663,7 +665,7 @@
         mAccessPoints.add(mWifiEntry1);
         mAccessPoints.add(mWifiEntry2);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         mWifiEntries.add(mWifiEntry1);
@@ -681,7 +683,7 @@
         mAccessPoints.add(mWifiEntry2);
         mAccessPoints.add(mWifiEntry3);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         mWifiEntries.add(mWifiEntry1);
@@ -699,7 +701,7 @@
         mAccessPoints.add(mWifiEntry3);
         mAccessPoints.add(mWifiEntry4);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         mWifiEntries.add(mWifiEntry1);
@@ -718,7 +720,7 @@
         when(mWifiEntry1.hasInternetAccess()).thenReturn(false);
         mAccessPoints.add(mWifiEntry1);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
         mWifiEntries.clear();
         mWifiEntries.add(mWifiEntry1);
@@ -735,9 +737,10 @@
         when(mWifiEntry1.hasInternetAccess()).thenReturn(false);
         mAccessPoints.add(mWifiEntry1);
 
-        mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+        mInternetDetailsContentController.onAccessPointsChanged(mAccessPoints);
 
-        verify(mWifiEntry1).setListener(mInternetDialogController.mConnectedWifiInternetMonitor);
+        verify(mWifiEntry1).setListener(
+                mInternetDetailsContentController.mConnectedWifiInternetMonitor);
     }
 
     @Test
@@ -746,8 +749,9 @@
         when(mWifiEntry1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
         when(mWifiEntry1.isDefaultNetwork()).thenReturn(true);
         when(mWifiEntry1.hasInternetAccess()).thenReturn(false);
-        InternetDialogController.ConnectedWifiInternetMonitor mConnectedWifiInternetMonitor =
-                mInternetDialogController.mConnectedWifiInternetMonitor;
+        InternetDetailsContentController.ConnectedWifiInternetMonitor
+                mConnectedWifiInternetMonitor =
+                mInternetDetailsContentController.mConnectedWifiInternetMonitor;
         mConnectedWifiInternetMonitor.registerCallbackIfNeed(mWifiEntry1);
 
         // When the hasInternetAccess() changed to true, and call back the onUpdated() function.
@@ -762,7 +766,7 @@
         reset(mInternetDialogCallback);
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
 
-        mInternetDialogController.onWifiScan(true);
+        mInternetDetailsContentController.onWifiScan(true);
 
         verify(mInternetDialogCallback).onWifiScan(false);
     }
@@ -772,7 +776,7 @@
         reset(mInternetDialogCallback);
         when(mKeyguardStateController.isUnlocked()).thenReturn(false);
 
-        mInternetDialogController.onWifiScan(true);
+        mInternetDetailsContentController.onWifiScan(true);
 
         verify(mInternetDialogCallback).onWifiScan(false);
     }
@@ -781,7 +785,7 @@
     public void onWifiScan_onWifiScanFalse_callbackOnWifiScanFalse() {
         reset(mInternetDialogCallback);
 
-        mInternetDialogController.onWifiScan(false);
+        mInternetDetailsContentController.onWifiScan(false);
 
         verify(mInternetDialogCallback).onWifiScan(false);
     }
@@ -790,7 +794,7 @@
     public void onWifiScan_onWifiScanTrue_callbackOnWifiScanTrue() {
         reset(mInternetDialogCallback);
 
-        mInternetDialogController.onWifiScan(true);
+        mInternetDetailsContentController.onWifiScan(true);
 
         verify(mInternetDialogCallback).onWifiScan(true);
     }
@@ -800,7 +804,7 @@
         when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
                 .thenReturn(true);
 
-        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
+        mInternetDetailsContentController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
 
         verify(mMergedCarrierEntry, never()).setEnabled(anyBoolean());
     }
@@ -811,7 +815,7 @@
                 .thenReturn(false);
         when(mAccessPointController.getMergedCarrierEntry()).thenReturn(null);
 
-        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
+        mInternetDetailsContentController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
     }
 
     @Test
@@ -819,11 +823,11 @@
         when(mCarrierConfigTracker.getCarrierProvisionsWifiMergedNetworksBool(SUB_ID))
                 .thenReturn(false);
 
-        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
+        mInternetDetailsContentController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, true);
 
         verify(mMergedCarrierEntry).setEnabled(true);
 
-        mInternetDialogController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, false);
+        mInternetDetailsContentController.setMergedCarrierWifiEnabledIfNeed(SUB_ID, false);
 
         verify(mMergedCarrierEntry).setEnabled(false);
     }
@@ -833,11 +837,11 @@
         when(mLocationController.isLocationEnabled()).thenReturn(false);
         when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
 
-        assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse();
+        assertThat(mInternetDetailsContentController.isWifiScanEnabled()).isFalse();
 
         when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
 
-        assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse();
+        assertThat(mInternetDetailsContentController.isWifiScanEnabled()).isFalse();
     }
 
     @Test
@@ -845,17 +849,17 @@
         when(mLocationController.isLocationEnabled()).thenReturn(true);
         when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false);
 
-        assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse();
+        assertThat(mInternetDetailsContentController.isWifiScanEnabled()).isFalse();
 
         when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true);
 
-        assertThat(mInternetDialogController.isWifiScanEnabled()).isTrue();
+        assertThat(mInternetDetailsContentController.isWifiScanEnabled()).isTrue();
     }
 
     @Test
     public void getSignalStrengthIcon_differentSubId() {
         mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, true);
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         Drawable icons = spyController.getSignalStrengthIcon(SUB_ID, mContext, 1, 1, 0, false);
         Drawable icons2 = spyController.getSignalStrengthIcon(SUB_ID2, mContext, 1, 1, 0, false);
 
@@ -870,12 +874,12 @@
         doReturn(SUB_ID2).when(info).getSubscriptionId();
         when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
 
-        int subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+        int subId = mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
         assertThat(subId).isEqualTo(SUB_ID2);
 
         // active on CBRS
         doReturn(true).when(info).isOpportunistic();
-        subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+        subId = mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
         assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
 
         // active on DDS
@@ -883,7 +887,7 @@
         doReturn(SUB_ID).when(info).getSubscriptionId();
         when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
 
-        subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+        subId = mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
         assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
 
@@ -894,7 +898,7 @@
         doReturn(SUB_ID2).when(info).getSubscriptionId();
         when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
 
-        int subId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+        int subId = mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
         assertThat(subId).isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
     }
 
@@ -908,22 +912,24 @@
         doReturn(false).when(info).isOpportunistic();
         when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
 
-        mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+        mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
 
         // 1st time is onStart(), 2nd time is getActiveAutoSwitchNonDdsSubId()
         verify(mTelephonyManager, times(2)).registerTelephonyCallback(any(), any());
-        assertThat(mInternetDialogController.mSubIdTelephonyCallbackMap.size()).isEqualTo(2);
+        assertThat(mInternetDetailsContentController.mSubIdTelephonyCallbackMap.size()).isEqualTo(
+                2);
 
         // Adds non DDS subId again
         doReturn(SUB_ID2).when(info).getSubscriptionId();
         doReturn(false).when(info).isOpportunistic();
         when(mSubscriptionManager.getActiveSubscriptionInfo(anyInt())).thenReturn(info);
 
-        mInternetDialogController.getActiveAutoSwitchNonDdsSubId();
+        mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId();
 
         // Does not add due to cached subInfo in mSubIdTelephonyCallbackMap.
         verify(mTelephonyManager, times(2)).registerTelephonyCallback(any(), any());
-        assertThat(mInternetDialogController.mSubIdTelephonyCallbackMap.size()).isEqualTo(2);
+        assertThat(mInternetDetailsContentController.mSubIdTelephonyCallbackMap.size()).isEqualTo(
+                2);
     }
 
     @Test
@@ -936,7 +942,7 @@
         when(SubscriptionManager.getResourcesForSubId(any(), eq(SUB_ID))).thenReturn(res1);
         when(SubscriptionManager.getResourcesForSubId(any(), eq(SUB_ID2))).thenReturn(res2);
 
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         Map<Integer, TelephonyDisplayInfo> mSubIdTelephonyDisplayInfoMap =
                 spyController.mSubIdTelephonyDisplayInfoMap;
         TelephonyDisplayInfo info1 = new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_EDGE,
@@ -961,7 +967,7 @@
 
     @Test
     public void getMobileNetworkSummary_flagOff() {
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         doReturn(true).when(spyController).isMobileDataEnabled();
         doReturn(true).when(spyController).activeNetworkIsCellular();
         String dds = spyController.getMobileNetworkSummary(SUB_ID);
@@ -972,7 +978,7 @@
     @Test
     public void launchMobileNetworkSettings_validSubId() {
         mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, true);
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         doReturn(SUB_ID2).when(spyController).getActiveAutoSwitchNonDdsSubId();
         spyController.launchMobileNetworkSettings(mDialogLaunchView);
 
@@ -983,7 +989,7 @@
     @Test
     public void launchMobileNetworkSettings_invalidSubId() {
         mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, true);
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
                 .when(spyController).getActiveAutoSwitchNonDdsSubId();
         spyController.launchMobileNetworkSettings(mDialogLaunchView);
@@ -995,7 +1001,7 @@
     @Test
     public void setAutoDataSwitchMobileDataPolicy() {
         mFlags.set(Flags.QS_SECONDARY_DATA_SUB_INFO, true);
-        mInternetDialogController.setAutoDataSwitchMobileDataPolicy(SUB_ID, true);
+        mInternetDetailsContentController.setAutoDataSwitchMobileDataPolicy(SUB_ID, true);
 
         verify(mTelephonyManager).setMobileDataPolicyEnabled(eq(
                 TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH), eq(true));
@@ -1006,9 +1012,9 @@
         // Fake mobile data level as SIGNAL_STRENGTH_POOR(1)
         when(mSignalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_POOR);
         // Fake carrier network level as WIFI_LEVEL_MAX(4)
-        when(mInternetDialogController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
+        when(mInternetDetailsContentController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
 
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         spyController.getSignalStrengthDrawableWithLevel(false /* isCarrierNetworkActive */, 0);
 
         verify(spyController).getSignalStrengthIcon(eq(0), any(), eq(SIGNAL_STRENGTH_POOR),
@@ -1020,9 +1026,9 @@
         // Fake mobile data level as SIGNAL_STRENGTH_POOR(1)
         when(mSignalStrength.getLevel()).thenReturn(SIGNAL_STRENGTH_POOR);
         // Fake carrier network level as WIFI_LEVEL_MAX(4)
-        when(mInternetDialogController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
+        when(mInternetDetailsContentController.getCarrierNetworkLevel()).thenReturn(WIFI_LEVEL_MAX);
 
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         spyController.getSignalStrengthDrawableWithLevel(true /* isCarrierNetworkActive */, 0);
 
         verify(spyController).getSignalStrengthIcon(eq(0), any(), eq(WIFI_LEVEL_MAX),
@@ -1033,14 +1039,16 @@
     public void getCarrierNetworkLevel_mergedCarrierEntryIsNull_returnMinLevel() {
         when(mAccessPointController.getMergedCarrierEntry()).thenReturn(null);
 
-        assertThat(mInternetDialogController.getCarrierNetworkLevel()).isEqualTo(WIFI_LEVEL_MIN);
+        assertThat(mInternetDetailsContentController.getCarrierNetworkLevel()).isEqualTo(
+                WIFI_LEVEL_MIN);
     }
 
     @Test
     public void getCarrierNetworkLevel_getUnreachableLevel_returnMinLevel() {
         when(mMergedCarrierEntry.getLevel()).thenReturn(WIFI_LEVEL_UNREACHABLE);
 
-        assertThat(mInternetDialogController.getCarrierNetworkLevel()).isEqualTo(WIFI_LEVEL_MIN);
+        assertThat(mInternetDetailsContentController.getCarrierNetworkLevel()).isEqualTo(
+                WIFI_LEVEL_MIN);
     }
 
     @Test
@@ -1048,7 +1056,7 @@
         for (int level = WIFI_LEVEL_MIN; level <= WIFI_LEVEL_MAX; level++) {
             when(mMergedCarrierEntry.getLevel()).thenReturn(level);
 
-            assertThat(mInternetDialogController.getCarrierNetworkLevel()).isEqualTo(level);
+            assertThat(mInternetDetailsContentController.getCarrierNetworkLevel()).isEqualTo(level);
         }
     }
 
@@ -1057,7 +1065,7 @@
         Resources res = mock(Resources.class);
         doReturn("Carrier network changing").when(res).getString(anyInt());
         when(SubscriptionManager.getResourcesForSubId(any(), eq(SUB_ID))).thenReturn(res);
-        InternetDialogController spyController = spy(mInternetDialogController);
+        InternetDetailsContentController spyController = spy(mInternetDetailsContentController);
         Map<Integer, TelephonyDisplayInfo> mSubIdTelephonyDisplayInfoMap =
                 spyController.mSubIdTelephonyDisplayInfoMap;
         TelephonyDisplayInfo info = new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
@@ -1076,14 +1084,14 @@
     public void getConfiguratorQrCodeGeneratorIntentOrNull_wifiNotShareable_returnNull() {
         mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, true);
         when(mConnectedEntry.canShare()).thenReturn(false);
-        assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+        assertThat(mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(
                 mConnectedEntry)).isNull();
     }
     @Test
     public void getConfiguratorQrCodeGeneratorIntentOrNull_flagOff_returnNull() {
         mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, false);
         when(mConnectedEntry.canShare()).thenReturn(true);
-        assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+        assertThat(mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(
                 mConnectedEntry)).isNull();
     }
 
@@ -1092,7 +1100,7 @@
         mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, true);
         when(mConnectedEntry.canShare()).thenReturn(true);
         when(mConnectedEntry.getWifiConfiguration()).thenReturn(null);
-        assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+        assertThat(mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(
                 mConnectedEntry)).isNull();
     }
 
@@ -1101,30 +1109,34 @@
         mFlags.set(Flags.SHARE_WIFI_QS_BUTTON, true);
         when(mConnectedEntry.canShare()).thenReturn(true);
         when(mConnectedEntry.getWifiConfiguration()).thenReturn(mWifiConfiguration);
-        assertThat(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(
+        assertThat(mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(
                 mConnectedEntry)).isNotNull();
     }
 
     @Test
     public void onStop_cleanUp() {
         doReturn(SUB_ID).when(mTelephonyManager).getSubscriptionId();
-        assertThat(mInternetDialogController.mSubIdTelephonyManagerMap.get(SUB_ID)).isEqualTo(
+        assertThat(
+                mInternetDetailsContentController.mSubIdTelephonyManagerMap.get(SUB_ID)).isEqualTo(
                 mTelephonyManager);
-        assertThat(mInternetDialogController.mSubIdTelephonyCallbackMap.get(SUB_ID)).isNotNull();
-        assertThat(mInternetDialogController.mCallback).isNotNull();
+        assertThat(mInternetDetailsContentController.mSubIdTelephonyCallbackMap.get(
+                SUB_ID)).isNotNull();
+        assertThat(mInternetDetailsContentController.mCallback).isNotNull();
 
-        mInternetDialogController.onStop();
+        mInternetDetailsContentController.onStop();
 
         verify(mTelephonyManager).unregisterTelephonyCallback(any(TelephonyCallback.class));
-        assertThat(mInternetDialogController.mSubIdTelephonyDisplayInfoMap.isEmpty()).isTrue();
-        assertThat(mInternetDialogController.mSubIdTelephonyManagerMap.isEmpty()).isTrue();
-        assertThat(mInternetDialogController.mSubIdTelephonyCallbackMap.isEmpty()).isTrue();
-        verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(mInternetDialogController
-                .mOnSubscriptionsChangedListener);
-        verify(mAccessPointController).removeAccessPointCallback(mInternetDialogController);
+        assertThat(
+                mInternetDetailsContentController.mSubIdTelephonyDisplayInfoMap.isEmpty()).isTrue();
+        assertThat(mInternetDetailsContentController.mSubIdTelephonyManagerMap.isEmpty()).isTrue();
+        assertThat(mInternetDetailsContentController.mSubIdTelephonyCallbackMap.isEmpty()).isTrue();
+        verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(
+                mInternetDetailsContentController
+                        .mOnSubscriptionsChangedListener);
+        verify(mAccessPointController).removeAccessPointCallback(mInternetDetailsContentController);
         verify(mConnectivityManager).unregisterNetworkCallback(
                 any(ConnectivityManager.NetworkCallback.class));
-        assertThat(mInternetDialogController.mCallback).isNull();
+        assertThat(mInternetDetailsContentController.mCallback).isNull();
     }
 
     @Test
@@ -1132,16 +1144,16 @@
         when(SubscriptionManager.getDefaultDataSubscriptionId())
                 .thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
 
-        mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        mInternetDetailsContentController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
 
-        assertThat(mInternetDialogController.hasActiveSubIdOnDds()).isFalse();
+        assertThat(mInternetDetailsContentController.hasActiveSubIdOnDds()).isFalse();
     }
 
     @Test
     public void hasActiveSubIdOnDds_activeDds_returnTrue() {
-        mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        mInternetDetailsContentController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
 
-        assertThat(mInternetDialogController.hasActiveSubIdOnDds()).isTrue();
+        assertThat(mInternetDetailsContentController.hasActiveSubIdOnDds()).isTrue();
     }
 
     @Test
@@ -1153,9 +1165,9 @@
         when(info.getProfileClass()).thenReturn(PROFILE_CLASS_PROVISIONING);
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info);
 
-        mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        mInternetDetailsContentController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
 
-        assertThat(mInternetDialogController.hasActiveSubIdOnDds()).isFalse();
+        assertThat(mInternetDetailsContentController.hasActiveSubIdOnDds()).isFalse();
     }
 
     @Test
@@ -1167,9 +1179,9 @@
         when(info.isOnlyNonTerrestrialNetwork()).thenReturn(true);
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info);
 
-        mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        mInternetDetailsContentController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
 
-        assertFalse(mInternetDialogController.hasActiveSubIdOnDds());
+        assertFalse(mInternetDetailsContentController.hasActiveSubIdOnDds());
     }
 
     @Test
@@ -1181,9 +1193,9 @@
         when(info.isOnlyNonTerrestrialNetwork()).thenReturn(false);
         when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info);
 
-        mInternetDialogController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
+        mInternetDetailsContentController.mOnSubscriptionsChangedListener.onSubscriptionsChanged();
 
-        assertTrue(mInternetDialogController.hasActiveSubIdOnDds());
+        assertTrue(mInternetDetailsContentController.hasActiveSubIdOnDds());
     }
 
     private String getResourcesString(String name) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacyTest.java
new file mode 100644
index 0000000..2385515
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateLegacyTest.java
@@ -0,0 +1,841 @@
+package com.android.systemui.qs.tiles.dialog;
+
+import static com.android.systemui.qs.tiles.dialog.InternetDetailsContentController.MAX_WIFI_ENTRY_COUNT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.view.Window;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogTransitionAnimator;
+import com.android.systemui.res.R;
+import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.wifitrackerlib.WifiEntry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+
+import java.util.List;
+
+import kotlinx.coroutines.CoroutineScope;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@UiThreadTest
+public class InternetDialogDelegateLegacyTest extends SysuiTestCase {
+
+    private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
+    private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary";
+    private static final String WIFI_TITLE = "Connected Wi-Fi Title";
+    private static final String WIFI_SUMMARY = "Connected Wi-Fi Summary";
+
+    @Mock
+    private Handler mHandler;
+    @Mock
+    CoroutineScope mScope;
+    @Mock
+    private TelephonyManager mTelephonyManager;
+    @Mock
+    private WifiEntry mInternetWifiEntry;
+    @Mock
+    private List<WifiEntry> mWifiEntries;
+    @Mock
+    private InternetAdapter mInternetAdapter;
+    @Mock
+    private InternetDetailsContentController mInternetDetailsContentController;
+    @Mock
+    private KeyguardStateController mKeyguard;
+    @Mock
+    private DialogTransitionAnimator mDialogTransitionAnimator;
+    @Mock
+    private SystemUIDialog.Factory mSystemUIDialogFactory;
+    @Mock
+    private SystemUIDialog mSystemUIDialog;
+    @Mock
+    private Window mWindow;
+
+    private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
+    private InternetDialogDelegateLegacy mInternetDialogDelegateLegacy;
+    private View mDialogView;
+    private View mSubTitle;
+    private LinearLayout mEthernet;
+    private LinearLayout mMobileDataLayout;
+    private Switch mMobileToggleSwitch;
+    private LinearLayout mWifiToggle;
+    private Switch mWifiToggleSwitch;
+    private TextView mWifiToggleSummary;
+    private LinearLayout mConnectedWifi;
+    private RecyclerView mWifiList;
+    private LinearLayout mSeeAll;
+    private LinearLayout mWifiScanNotify;
+    private TextView mAirplaneModeSummaryText;
+
+    private MockitoSession mMockitoSession;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
+        when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
+        when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+        when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
+        when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
+        when(mWifiEntries.size()).thenReturn(1);
+
+        when(mInternetDetailsContentController.getMobileNetworkTitle(anyInt()))
+                .thenReturn(MOBILE_NETWORK_TITLE);
+        when(mInternetDetailsContentController.getMobileNetworkSummary(anyInt()))
+                .thenReturn(MOBILE_NETWORK_SUMMARY);
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId()).thenReturn(
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+        mMockitoSession = ExtendedMockito.mockitoSession()
+                .spyStatic(WifiEnterpriseRestrictionUtils.class)
+                .startMocking();
+        when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
+        when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class), eq(mContext)))
+                .thenReturn(mSystemUIDialog);
+        when(mSystemUIDialog.getContext()).thenReturn(mContext);
+        when(mSystemUIDialog.getWindow()).thenReturn(mWindow);
+        createInternetDialog();
+    }
+
+    private void createInternetDialog() {
+        mInternetDialogDelegateLegacy = new InternetDialogDelegateLegacy(
+                mContext,
+                mock(InternetDialogManager.class),
+                mInternetDetailsContentController,
+                true,
+                true,
+                true,
+                mScope,
+                mock(UiEventLogger.class),
+                mDialogTransitionAnimator,
+                mHandler,
+                mBgExecutor,
+                mKeyguard,
+                mSystemUIDialogFactory,
+                new FakeShadeDialogContextInteractor(mContext));
+        mInternetDialogDelegateLegacy.createDialog();
+        mInternetDialogDelegateLegacy.onCreate(mSystemUIDialog, null);
+        mInternetDialogDelegateLegacy.mAdapter = mInternetAdapter;
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = mInternetWifiEntry;
+        mInternetDialogDelegateLegacy.mWifiEntriesCount = mWifiEntries.size();
+
+        mDialogView = mInternetDialogDelegateLegacy.mDialogView;
+        mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+        mEthernet = mDialogView.requireViewById(R.id.ethernet_layout);
+        mMobileDataLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
+        mMobileToggleSwitch = mDialogView.requireViewById(R.id.mobile_toggle);
+        mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+        mWifiToggleSwitch = mDialogView.requireViewById(R.id.wifi_toggle);
+        mWifiToggleSummary = mDialogView.requireViewById(R.id.wifi_toggle_summary);
+        mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
+        mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
+        mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
+        mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
+        mAirplaneModeSummaryText = mDialogView.requireViewById(R.id.airplane_mode_summary);
+        mInternetDialogDelegateLegacy.onStart(mSystemUIDialog);
+    }
+
+    @After
+    public void tearDown() {
+        mInternetDialogDelegateLegacy.onStop(mSystemUIDialog);
+        mInternetDialogDelegateLegacy.dismissDialog();
+        mMockitoSession.finishMocking();
+    }
+
+    @Test
+    public void createInternetDialog_setAccessibilityPaneTitleToQuickSettings() {
+        assertThat(mDialogView.getAccessibilityPaneTitle())
+                .isEqualTo(mContext.getText(R.string.accessibility_desc_quick_settings));
+    }
+
+    @Test
+    public void hideWifiViews_WifiViewsGone() {
+        mInternetDialogDelegateLegacy.hideWifiViews();
+
+        assertThat(mInternetDialogDelegateLegacy.mIsProgressBarVisible).isFalse();
+        assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_withApmOn_internetDialogSubTitleGone() {
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOffAndHasEthernet_showEthernet() {
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(false);
+        when(mInternetDetailsContentController.hasEthernet()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOffAndNoEthernet_hideEthernet() {
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(false);
+        when(mInternetDetailsContentController.hasEthernet()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnAndHasEthernet_showEthernet() {
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.hasEthernet()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnAndNoEthernet_hideEthernet() {
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.hasEthernet()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOffAndNotCarrierNetwork_mobileDataLayoutGone() {
+        // Mobile network should be gone if the list of active subscriptionId is null.
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(false);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(false);
+        when(mInternetDetailsContentController.hasActiveSubIdOnDds()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayoutVisible() {
+        // Carrier network should be visible if airplane mode ON and Wi-Fi is ON.
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayoutGone() {
+        // Carrier network should be gone if airplane mode ON and Wi-Fi is off.
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnAndNoCarrierNetwork_mobileDataLayoutGone() {
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(false);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnAndWifiOnHasCarrierNetwork_showAirplaneSummary() {
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        doReturn(false).when(mInternetDetailsContentController).activeNetworkIsCellular();
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
+                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOffAndWifiOnHasCarrierNetwork_notShowApmSummary() {
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(false);
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        doReturn(false).when(mInternetDetailsContentController).activeNetworkIsCellular();
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOffAndHasCarrierNetwork_notShowApmSummary() {
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_apmOnAndNoCarrierNetwork_notShowApmSummary() {
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(false);
+        when(mInternetDetailsContentController.isAirplaneModeEnabled()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_mobileDataIsEnabled_checkMobileDataSwitch() {
+        doReturn(true).when(mInternetDetailsContentController).hasActiveSubIdOnDds();
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isMobileDataEnabled()).thenReturn(true);
+        mMobileToggleSwitch.setChecked(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileToggleSwitch.isChecked()).isTrue();
+                });
+    }
+
+    @Test
+    public void updateDialog_mobileDataIsNotChanged_checkMobileDataSwitch() {
+        doReturn(true).when(mInternetDetailsContentController).hasActiveSubIdOnDds();
+        when(mInternetDetailsContentController.isCarrierNetworkActive()).thenReturn(true);
+        when(mInternetDetailsContentController.isMobileDataEnabled()).thenReturn(false);
+        mMobileToggleSwitch.setChecked(false);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mMobileToggleSwitch.isChecked()).isFalse();
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
+        when(mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId()).thenReturn(1);
+        doReturn(true).when(mInternetDetailsContentController).hasActiveSubIdOnDds();
+        // The preconditions WiFi ON and Internet WiFi are already in setUp()
+        doReturn(false).when(mInternetDetailsContentController).activeNetworkIsCellular();
+
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+                    LinearLayout secondaryLayout = mDialogView.requireViewById(
+                            R.id.secondary_mobile_network_layout);
+                    assertThat(secondaryLayout.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        doReturn(false).when(mInternetDetailsContentController).activeNetworkIsCellular();
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndNoWifiEntry_showWifiListAndSeeAllArea() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        mInternetDialogDelegateLegacy.mWifiEntriesCount = 0;
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+                    // Show a blank block to fix the dialog height even if there is no WiFi list
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+                    verify(mInternetAdapter).setMaxEntriesCount(3);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndOneWifiEntry_showWifiListAndSeeAllArea() {
+        // The precondition WiFi ON is already in setUp()
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        mInternetDialogDelegateLegacy.mWifiEntriesCount = 1;
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+                    // Show a blank block to fix the dialog height even if there is no WiFi list
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+                    verify(mInternetAdapter).setMaxEntriesCount(3);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndHasConnectedWifi_showAllWifiAndSeeAllArea() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+        mInternetDialogDelegateLegacy.mWifiEntriesCount = 0;
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+                    // Show a blank block to fix the dialog height even if there is no WiFi list
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+                    verify(mInternetAdapter).setMaxEntriesCount(2);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndHasMaxWifiList_showWifiListAndSeeAll() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        mInternetDialogDelegateLegacy.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT;
+        mInternetDialogDelegateLegacy.mHasMoreWifiEntries = true;
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+                    verify(mInternetAdapter).setMaxEntriesCount(3);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOnAndHasBothWifiEntry_showBothWifiEntryAndSeeAll() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+        mInternetDialogDelegateLegacy.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT - 1;
+        mInternetDialogDelegateLegacy.mHasMoreWifiEntries = true;
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
+                    verify(mInternetAdapter).setMaxEntriesCount(2);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
+                });
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndNoConnectedWifi_showWifiToggle() {
+        // The preconditions WiFi entries are already in setUp()
+        when(mInternetDetailsContentController.isDeviceLocked()).thenReturn(true);
+        mInternetDialogDelegateLegacy.mConnectedWifiEntry = null;
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    // Show WiFi Toggle without background
+                    assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
+                    assertThat(mWifiToggle.getBackground()).isNull();
+                    // Hide Wi-Fi networks and See all
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_deviceLockedAndHasConnectedWifi_showWifiToggleWithBackground() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+        when(mInternetDetailsContentController.isDeviceLocked()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    // Show WiFi Toggle with highlight background
+                    assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
+                    assertThat(mWifiToggle.getBackground()).isNotNull();
+                    // Hide Wi-Fi networks and See all
+                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+                    assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_disallowChangeWifiState_disableWifiSwitch() {
+        mInternetDialogDelegateLegacy.dismissDialog();
+        when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(false);
+        createInternetDialog();
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    // Disable Wi-Fi switch and show restriction message in summary.
+                    assertThat(mWifiToggleSwitch.isEnabled()).isFalse();
+                    assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.VISIBLE);
+                    assertThat(mWifiToggleSummary.getText().length()).isNotEqualTo(0);
+                });
+    }
+
+    @Test
+    public void updateDialog_allowChangeWifiState_enableWifiSwitch() {
+        mInternetDialogDelegateLegacy.dismissDialog();
+        when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
+        createInternetDialog();
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    // Enable Wi-Fi switch and hide restriction message in summary.
+                    assertThat(mWifiToggleSwitch.isEnabled()).isTrue();
+                    assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_showSecondaryDataSub() {
+        when(mInternetDetailsContentController.getActiveAutoSwitchNonDdsSubId()).thenReturn(1);
+        doReturn(1).when(mInternetDetailsContentController).getActiveAutoSwitchNonDdsSubId();
+        doReturn(true).when(mInternetDetailsContentController).hasActiveSubIdOnDds();
+        doReturn(false).when(mInternetDetailsContentController).isAirplaneModeEnabled();
+        clearInvocations(mInternetDetailsContentController);
+        mInternetDialogDelegateLegacy.updateDialog(true);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    LinearLayout primaryLayout = mDialogView.requireViewById(
+                            R.id.mobile_network_layout);
+                    LinearLayout secondaryLayout = mDialogView.requireViewById(
+                            R.id.secondary_mobile_network_layout);
+
+                    verify(mInternetDetailsContentController).getMobileNetworkSummary(1);
+                    assertThat(primaryLayout.getBackground()).isNotEqualTo(
+                            secondaryLayout.getBackground());
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiOn_hideWifiScanNotify() {
+        // The preconditions WiFi ON and WiFi entries are already in setUp()
+
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+                });
+
+        assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() {
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(false);
+        when(mInternetDetailsContentController.isWifiScanEnabled()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+                });
+
+        assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() {
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(false);
+        when(mInternetDetailsContentController.isWifiScanEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.isDeviceLocked()).thenReturn(true);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+                });
+
+        assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
+    }
+
+    @Test
+    public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() {
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(false);
+        when(mInternetDetailsContentController.isWifiScanEnabled()).thenReturn(true);
+        when(mInternetDetailsContentController.isDeviceLocked()).thenReturn(false);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE);
+                    TextView wifiScanNotifyText = mDialogView.requireViewById(
+                            R.id.wifi_scan_notify_text);
+                    assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0);
+                    assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull();
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiIsDisabled_uncheckWifiSwitch() {
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(false);
+        mWifiToggleSwitch.setChecked(true);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mWifiToggleSwitch.isChecked()).isFalse();
+                });
+    }
+
+    @Test
+    public void updateDialog_wifiIsEnabled_checkWifiSwitch() throws Exception {
+        when(mInternetDetailsContentController.isWifiEnabled()).thenReturn(true);
+        mWifiToggleSwitch.setChecked(false);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mWifiToggleSwitch.isChecked()).isTrue();
+                });
+    }
+
+    @Test
+    public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() {
+        mSeeAll.performClick();
+
+        verify(mInternetDetailsContentController).launchNetworkSetting(
+                mDialogView.requireViewById(R.id.see_all_layout));
+    }
+
+    @Test
+    public void onWifiScan_isScanTrue_setProgressBarVisibleTrue() {
+        mInternetDialogDelegateLegacy.mIsProgressBarVisible = false;
+
+        mInternetDialogDelegateLegacy.onWifiScan(true);
+
+        assertThat(mInternetDialogDelegateLegacy.mIsProgressBarVisible).isTrue();
+    }
+
+    @Test
+    public void onWifiScan_isScanFalse_setProgressBarVisibleFalse() {
+        mInternetDialogDelegateLegacy.mIsProgressBarVisible = true;
+
+        mInternetDialogDelegateLegacy.onWifiScan(false);
+
+        assertThat(mInternetDialogDelegateLegacy.mIsProgressBarVisible).isFalse();
+    }
+
+    @Test
+    public void getWifiListMaxCount_returnCountCorrectly() {
+        // Both of the Ethernet, MobileData is hidden.
+        // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT.
+        setNetworkVisible(false, false, false);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount()).isEqualTo(
+                MAX_WIFI_ENTRY_COUNT);
+
+        // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
+        setNetworkVisible(false, false, true);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+
+        // Only one of Ethernet, MobileData is displayed.
+        // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT.
+        setNetworkVisible(true, false, false);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount()).isEqualTo(
+                MAX_WIFI_ENTRY_COUNT);
+
+        setNetworkVisible(false, true, false);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount()).isEqualTo(
+                MAX_WIFI_ENTRY_COUNT);
+
+        // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
+        setNetworkVisible(true, false, true);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+
+        setNetworkVisible(false, true, true);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+
+        // Both of Ethernet, MobileData, ConnectedWiFi is displayed.
+        // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT - 1.
+        setNetworkVisible(true, true, false);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
+
+        // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
+        setNetworkVisible(true, true, true);
+
+        assertThat(mInternetDialogDelegateLegacy.getWifiListMaxCount())
+                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 2);
+    }
+
+    @Test
+    public void updateDialog_shareWifiIntentNull_hideButton() {
+        when(mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
+                .thenReturn(null);
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(
+                            mInternetDialogDelegateLegacy.mShareWifiButton.getVisibility())
+                            .isEqualTo(View.GONE);
+                });
+    }
+
+    @Test
+    public void updateDialog_shareWifiShareable_showButton() {
+        when(mInternetDetailsContentController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
+                .thenReturn(new Intent());
+        mInternetDialogDelegateLegacy.updateDialog(false);
+        mBgExecutor.runAllReady();
+
+        mInternetDialogDelegateLegacy.mDataInternetContent.observe(
+                mInternetDialogDelegateLegacy.mLifecycleOwner, i -> {
+                    assertThat(mInternetDialogDelegateLegacy.mShareWifiButton.getVisibility())
+                            .isEqualTo(View.VISIBLE);
+                });
+    }
+
+    private void setNetworkVisible(boolean ethernetVisible, boolean mobileDataVisible,
+            boolean connectedWifiVisible) {
+        mEthernet.setVisibility(ethernetVisible ? View.VISIBLE : View.GONE);
+        mMobileDataLayout.setVisibility(mobileDataVisible ? View.VISIBLE : View.GONE);
+        mConnectedWifi.setVisibility(connectedWifiVisible ? View.VISIBLE : View.GONE);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
deleted file mode 100644
index 8560b67..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateTest.java
+++ /dev/null
@@ -1,837 +0,0 @@
-package com.android.systemui.qs.tiles.dialog;
-
-import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Intent;
-import android.os.Handler;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.testing.TestableLooper;
-import android.view.View;
-import android.view.Window;
-import android.widget.LinearLayout;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
-import com.android.internal.logging.UiEventLogger;
-import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.animation.DialogTransitionAnimator;
-import com.android.systemui.res.R;
-import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-import com.android.wifitrackerlib.WifiEntry;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-
-import java.util.List;
-
-import kotlinx.coroutines.CoroutineScope;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@UiThreadTest
-public class InternetDialogDelegateTest extends SysuiTestCase {
-
-    private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
-    private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary";
-    private static final String WIFI_TITLE = "Connected Wi-Fi Title";
-    private static final String WIFI_SUMMARY = "Connected Wi-Fi Summary";
-
-    @Mock
-    private Handler mHandler;
-    @Mock
-    CoroutineScope mScope;
-    @Mock
-    private TelephonyManager mTelephonyManager;
-    @Mock
-    private WifiEntry mInternetWifiEntry;
-    @Mock
-    private List<WifiEntry> mWifiEntries;
-    @Mock
-    private InternetAdapter mInternetAdapter;
-    @Mock
-    private InternetDialogController mInternetDialogController;
-    @Mock
-    private KeyguardStateController mKeyguard;
-    @Mock
-    private DialogTransitionAnimator mDialogTransitionAnimator;
-    @Mock
-    private SystemUIDialog.Factory mSystemUIDialogFactory;
-    @Mock
-    private SystemUIDialog mSystemUIDialog;
-    @Mock
-    private Window mWindow;
-
-    private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock());
-    private InternetDialogDelegate mInternetDialogDelegate;
-    private View mDialogView;
-    private View mSubTitle;
-    private LinearLayout mEthernet;
-    private LinearLayout mMobileDataLayout;
-    private Switch mMobileToggleSwitch;
-    private LinearLayout mWifiToggle;
-    private Switch mWifiToggleSwitch;
-    private TextView mWifiToggleSummary;
-    private LinearLayout mConnectedWifi;
-    private RecyclerView mWifiList;
-    private LinearLayout mSeeAll;
-    private LinearLayout mWifiScanNotify;
-    private TextView mAirplaneModeSummaryText;
-
-    private MockitoSession mMockitoSession;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
-        when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
-        when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
-        when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
-        when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
-        when(mWifiEntries.size()).thenReturn(1);
-
-        when(mInternetDialogController.getMobileNetworkTitle(anyInt()))
-                .thenReturn(MOBILE_NETWORK_TITLE);
-        when(mInternetDialogController.getMobileNetworkSummary(anyInt()))
-                .thenReturn(MOBILE_NETWORK_SUMMARY);
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
-        when(mInternetDialogController.getActiveAutoSwitchNonDdsSubId()).thenReturn(
-                SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-        mMockitoSession = ExtendedMockito.mockitoSession()
-                .spyStatic(WifiEnterpriseRestrictionUtils.class)
-                .startMocking();
-        when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
-        when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class), eq(mContext)))
-                .thenReturn(mSystemUIDialog);
-        when(mSystemUIDialog.getContext()).thenReturn(mContext);
-        when(mSystemUIDialog.getWindow()).thenReturn(mWindow);
-        createInternetDialog();
-    }
-
-    private void createInternetDialog() {
-        mInternetDialogDelegate = new InternetDialogDelegate(
-                mContext,
-                mock(InternetDialogManager.class),
-                mInternetDialogController,
-                true,
-                true,
-                true,
-                mScope,
-                mock(UiEventLogger.class),
-                mDialogTransitionAnimator,
-                mHandler,
-                mBgExecutor,
-                mKeyguard,
-                mSystemUIDialogFactory,
-                new FakeShadeDialogContextInteractor(mContext));
-        mInternetDialogDelegate.createDialog();
-        mInternetDialogDelegate.onCreate(mSystemUIDialog, null);
-        mInternetDialogDelegate.mAdapter = mInternetAdapter;
-        mInternetDialogDelegate.mConnectedWifiEntry = mInternetWifiEntry;
-        mInternetDialogDelegate.mWifiEntriesCount = mWifiEntries.size();
-
-        mDialogView = mInternetDialogDelegate.mDialogView;
-        mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
-        mEthernet = mDialogView.requireViewById(R.id.ethernet_layout);
-        mMobileDataLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
-        mMobileToggleSwitch = mDialogView.requireViewById(R.id.mobile_toggle);
-        mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
-        mWifiToggleSwitch = mDialogView.requireViewById(R.id.wifi_toggle);
-        mWifiToggleSummary = mDialogView.requireViewById(R.id.wifi_toggle_summary);
-        mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
-        mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
-        mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
-        mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout);
-        mAirplaneModeSummaryText = mDialogView.requireViewById(R.id.airplane_mode_summary);
-        mInternetDialogDelegate.onStart(mSystemUIDialog);
-    }
-
-    @After
-    public void tearDown() {
-        mInternetDialogDelegate.onStop(mSystemUIDialog);
-        mInternetDialogDelegate.dismissDialog();
-        mMockitoSession.finishMocking();
-    }
-
-    @Test
-    public void createInternetDialog_setAccessibilityPaneTitleToQuickSettings() {
-        assertThat(mDialogView.getAccessibilityPaneTitle())
-                .isEqualTo(mContext.getText(R.string.accessibility_desc_quick_settings));
-    }
-
-    @Test
-    public void hideWifiViews_WifiViewsGone() {
-        mInternetDialogDelegate.hideWifiViews();
-
-        assertThat(mInternetDialogDelegate.mIsProgressBarVisible).isFalse();
-        assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
-        assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void updateDialog_withApmOn_internetDialogSubTitleGone() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOffAndHasEthernet_showEthernet() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        when(mInternetDialogController.hasEthernet()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOffAndNoEthernet_hideEthernet() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        when(mInternetDialogController.hasEthernet()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnAndHasEthernet_showEthernet() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        when(mInternetDialogController.hasEthernet()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnAndNoEthernet_hideEthernet() {
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        when(mInternetDialogController.hasEthernet()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOffAndNotCarrierNetwork_mobileDataLayoutGone() {
-        // Mobile network should be gone if the list of active subscriptionId is null.
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        when(mInternetDialogController.hasActiveSubIdOnDds()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayoutVisible() {
-        // Carrier network should be visible if airplane mode ON and Wi-Fi is ON.
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnWithCarrierNetworkAndWifiStatus_mobileDataLayoutGone() {
-        // Carrier network should be gone if airplane mode ON and Wi-Fi is off.
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnAndNoCarrierNetwork_mobileDataLayoutGone() {
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnAndWifiOnHasCarrierNetwork_showAirplaneSummary() {
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileDataLayout.getVisibility()).isEqualTo(View.VISIBLE);
-                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOffAndWifiOnHasCarrierNetwork_notShowApmSummary() {
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOffAndHasCarrierNetwork_notShowApmSummary() {
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_apmOnAndNoCarrierNetwork_notShowApmSummary() {
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(false);
-        when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mAirplaneModeSummaryText.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_mobileDataIsEnabled_checkMobileDataSwitch() {
-        doReturn(true).when(mInternetDialogController).hasActiveSubIdOnDds();
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isMobileDataEnabled()).thenReturn(true);
-        mMobileToggleSwitch.setChecked(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileToggleSwitch.isChecked()).isTrue();
-                });
-    }
-
-    @Test
-    public void updateDialog_mobileDataIsNotChanged_checkMobileDataSwitch() {
-        doReturn(true).when(mInternetDialogController).hasActiveSubIdOnDds();
-        when(mInternetDialogController.isCarrierNetworkActive()).thenReturn(true);
-        when(mInternetDialogController.isMobileDataEnabled()).thenReturn(false);
-        mMobileToggleSwitch.setChecked(false);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mMobileToggleSwitch.isChecked()).isFalse();
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndHasInternetWifi_showConnectedWifi() {
-        when(mInternetDialogController.getActiveAutoSwitchNonDdsSubId()).thenReturn(1);
-        doReturn(true).when(mInternetDialogController).hasActiveSubIdOnDds();
-        // The preconditions WiFi ON and Internet WiFi are already in setUp()
-        doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
-                    LinearLayout secondaryLayout = mDialogView.requireViewById(
-                            R.id.secondary_mobile_network_layout);
-                    assertThat(secondaryLayout.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
-        // The precondition WiFi ON is already in setUp()
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndNoWifiEntry_showWifiListAndSeeAllArea() {
-        // The precondition WiFi ON is already in setUp()
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        mInternetDialogDelegate.mWifiEntriesCount = 0;
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-                    // Show a blank block to fix the dialog height even if there is no WiFi list
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
-                    verify(mInternetAdapter).setMaxEntriesCount(3);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndOneWifiEntry_showWifiListAndSeeAllArea() {
-        // The precondition WiFi ON is already in setUp()
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        mInternetDialogDelegate.mWifiEntriesCount = 1;
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-                    // Show a blank block to fix the dialog height even if there is no WiFi list
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
-                    verify(mInternetAdapter).setMaxEntriesCount(3);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndHasConnectedWifi_showAllWifiAndSeeAllArea() {
-        // The preconditions WiFi ON and WiFi entries are already in setUp()
-        mInternetDialogDelegate.mWifiEntriesCount = 0;
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
-                    // Show a blank block to fix the dialog height even if there is no WiFi list
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
-                    verify(mInternetAdapter).setMaxEntriesCount(2);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.INVISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndHasMaxWifiList_showWifiListAndSeeAll() {
-        // The preconditions WiFi ON and WiFi entries are already in setUp()
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        mInternetDialogDelegate.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT;
-        mInternetDialogDelegate.mHasMoreWifiEntries = true;
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
-                    verify(mInternetAdapter).setMaxEntriesCount(3);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOnAndHasBothWifiEntry_showBothWifiEntryAndSeeAll() {
-        // The preconditions WiFi ON and WiFi entries are already in setUp()
-        mInternetDialogDelegate.mWifiEntriesCount = MAX_WIFI_ENTRY_COUNT - 1;
-        mInternetDialogDelegate.mHasMoreWifiEntries = true;
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE);
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE);
-                    verify(mInternetAdapter).setMaxEntriesCount(2);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE);
-                });
-    }
-
-    @Test
-    public void updateDialog_deviceLockedAndNoConnectedWifi_showWifiToggle() {
-        // The preconditions WiFi entries are already in setUp()
-        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-        mInternetDialogDelegate.mConnectedWifiEntry = null;
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    // Show WiFi Toggle without background
-                    assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
-                    assertThat(mWifiToggle.getBackground()).isNull();
-                    // Hide Wi-Fi networks and See all
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_deviceLockedAndHasConnectedWifi_showWifiToggleWithBackground() {
-        // The preconditions WiFi ON and WiFi entries are already in setUp()
-        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    // Show WiFi Toggle with highlight background
-                    assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE);
-                    assertThat(mWifiToggle.getBackground()).isNotNull();
-                    // Hide Wi-Fi networks and See all
-                    assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
-                    assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
-                    assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_disallowChangeWifiState_disableWifiSwitch() {
-        mInternetDialogDelegate.dismissDialog();
-        when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(false);
-        createInternetDialog();
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    // Disable Wi-Fi switch and show restriction message in summary.
-                    assertThat(mWifiToggleSwitch.isEnabled()).isFalse();
-                    assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.VISIBLE);
-                    assertThat(mWifiToggleSummary.getText().length()).isNotEqualTo(0);
-                });
-    }
-
-    @Test
-    public void updateDialog_allowChangeWifiState_enableWifiSwitch() {
-        mInternetDialogDelegate.dismissDialog();
-        when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
-        createInternetDialog();
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    // Enable Wi-Fi switch and hide restriction message in summary.
-                    assertThat(mWifiToggleSwitch.isEnabled()).isTrue();
-                    assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_showSecondaryDataSub() {
-        when(mInternetDialogController.getActiveAutoSwitchNonDdsSubId()).thenReturn(1);
-        doReturn(1).when(mInternetDialogController).getActiveAutoSwitchNonDdsSubId();
-        doReturn(true).when(mInternetDialogController).hasActiveSubIdOnDds();
-        doReturn(false).when(mInternetDialogController).isAirplaneModeEnabled();
-        clearInvocations(mInternetDialogController);
-        mInternetDialogDelegate.updateDialog(true);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    LinearLayout primaryLayout = mDialogView.requireViewById(
-                            R.id.mobile_network_layout);
-                    LinearLayout secondaryLayout = mDialogView.requireViewById(
-                            R.id.secondary_mobile_network_layout);
-
-                    verify(mInternetDialogController).getMobileNetworkSummary(1);
-                    assertThat(primaryLayout.getBackground()).isNotEqualTo(
-                            secondaryLayout.getBackground());
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiOn_hideWifiScanNotify() {
-        // The preconditions WiFi ON and WiFi entries are already in setUp()
-
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
-                });
-
-        assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() {
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-        when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
-                });
-
-        assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() {
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-        when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
-        when(mInternetDialogController.isDeviceLocked()).thenReturn(true);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
-                });
-
-        assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() {
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-        when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true);
-        when(mInternetDialogController.isDeviceLocked()).thenReturn(false);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE);
-                    TextView wifiScanNotifyText = mDialogView.requireViewById(
-                            R.id.wifi_scan_notify_text);
-                    assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0);
-                    assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull();
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiIsDisabled_uncheckWifiSwitch() {
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(false);
-        mWifiToggleSwitch.setChecked(true);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mWifiToggleSwitch.isChecked()).isFalse();
-                });
-    }
-
-    @Test
-    public void updateDialog_wifiIsEnabled_checkWifiSwitch() throws Exception {
-        when(mInternetDialogController.isWifiEnabled()).thenReturn(true);
-        mWifiToggleSwitch.setChecked(false);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mWifiToggleSwitch.isChecked()).isTrue();
-                });
-    }
-
-    @Test
-    public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() {
-        mSeeAll.performClick();
-
-        verify(mInternetDialogController).launchNetworkSetting(
-                mDialogView.requireViewById(R.id.see_all_layout));
-    }
-
-    @Test
-    public void onWifiScan_isScanTrue_setProgressBarVisibleTrue() {
-        mInternetDialogDelegate.mIsProgressBarVisible = false;
-
-        mInternetDialogDelegate.onWifiScan(true);
-
-        assertThat(mInternetDialogDelegate.mIsProgressBarVisible).isTrue();
-    }
-
-    @Test
-    public void onWifiScan_isScanFalse_setProgressBarVisibleFalse() {
-        mInternetDialogDelegate.mIsProgressBarVisible = true;
-
-        mInternetDialogDelegate.onWifiScan(false);
-
-        assertThat(mInternetDialogDelegate.mIsProgressBarVisible).isFalse();
-    }
-
-    @Test
-    public void getWifiListMaxCount_returnCountCorrectly() {
-        // Both of the Ethernet, MobileData is hidden.
-        // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT.
-        setNetworkVisible(false, false, false);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
-
-        // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
-        setNetworkVisible(false, false, true);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
-                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
-
-        // Only one of Ethernet, MobileData is displayed.
-        // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT.
-        setNetworkVisible(true, false, false);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
-
-        setNetworkVisible(false, true, false);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount()).isEqualTo(MAX_WIFI_ENTRY_COUNT);
-
-        // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
-        setNetworkVisible(true, false, true);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
-                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
-
-        setNetworkVisible(false, true, true);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
-                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
-
-        // Both of Ethernet, MobileData, ConnectedWiFi is displayed.
-        // Then the maximum count is equal to MAX_WIFI_ENTRY_COUNT - 1.
-        setNetworkVisible(true, true, false);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
-                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 1);
-
-        // If the Connected Wi-Fi is displayed then reduce one of the Wi-Fi list max count.
-        setNetworkVisible(true, true, true);
-
-        assertThat(mInternetDialogDelegate.getWifiListMaxCount())
-                .isEqualTo(MAX_WIFI_ENTRY_COUNT - 2);
-    }
-
-    @Test
-    public void updateDialog_shareWifiIntentNull_hideButton() {
-        when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
-                .thenReturn(null);
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility()).isEqualTo(
-                            View.GONE);
-                });
-    }
-
-    @Test
-    public void updateDialog_shareWifiShareable_showButton() {
-        when(mInternetDialogController.getConfiguratorQrCodeGeneratorIntentOrNull(any()))
-                .thenReturn(new Intent());
-        mInternetDialogDelegate.updateDialog(false);
-        mBgExecutor.runAllReady();
-
-        mInternetDialogDelegate.mDataInternetContent.observe(
-                mInternetDialogDelegate.mLifecycleOwner, i -> {
-                    assertThat(mInternetDialogDelegate.mShareWifiButton.getVisibility())
-                            .isEqualTo(View.VISIBLE);
-                });
-    }
-
-    private void setNetworkVisible(boolean ethernetVisible, boolean mobileDataVisible,
-            boolean connectedWifiVisible) {
-        mEthernet.setVisibility(ethernetVisible ? View.VISIBLE : View.GONE);
-        mMobileDataLayout.setVisibility(mobileDataVisible ? View.VISIBLE : View.GONE);
-        mConnectedWifi.setVisibility(connectedWifiVisible ? View.VISIBLE : View.GONE);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
index 2d35ea5..61943f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt
@@ -65,7 +65,7 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.notificationLockscreenUserManager
@@ -128,7 +128,7 @@
     private val shadeController = kosmos.shadeControllerSceneImpl
     private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager
     private val statusBarStateController = kosmos.statusBarStateController
-    private val headsUpManager = kosmos.headsUpManager
+    private val headsUpManager = kosmos.mockHeadsUpManager
     private val activityStarter = kosmos.activityStarter
     private val userManager = kosmos.userManager
     private val activeNotificationsInteractor = kosmos.activeNotificationsInteractor
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 411c81d13..1fcf02d 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
@@ -36,6 +36,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -54,8 +56,6 @@
 
 import static java.util.Collections.emptySet;
 
-import static kotlinx.coroutines.flow.FlowKt.flowOf;
-
 import android.app.ActivityManager;
 import android.app.IWallpaperManager;
 import android.app.NotificationManager;
@@ -132,6 +132,7 @@
 import com.android.systemui.notetask.NoteTaskController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -175,6 +176,7 @@
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
 import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -216,6 +218,10 @@
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.startingsurface.StartingSurface;
 
+import dagger.Lazy;
+
+import kotlinx.coroutines.test.TestScope;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -232,9 +238,6 @@
 
 import javax.inject.Provider;
 
-import dagger.Lazy;
-import kotlinx.coroutines.test.TestScope;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -536,6 +539,8 @@
                 new StatusBarInitializerImpl(
                         mStatusBarWindowController,
                         mStatusBarModePerDisplayRepository,
+                        mock(StatusBarConfigurationController.class),
+                        mock(DarkIconDispatcher.class),
                         mCollapsedStatusBarFragmentProvider,
                         mock(StatusBarRootFactory.class),
                         mock(HomeStatusBarComponent.Factory.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 0b443675..3a99328 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -61,6 +62,9 @@
 import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.core.StatusBarRootModernization;
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -75,6 +79,8 @@
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeHomeStatusBarViewModel;
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.StatusBarOperatorNameViewModel;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
 import com.android.systemui.util.CarrierConfigTracker;
@@ -134,6 +140,12 @@
     private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private StatusBarWindowControllerStore mStatusBarWindowControllerStore;
+    @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private StatusBarConfigurationControllerStore mStatusBarConfigurationControllerStore;
+    @Mock private StatusBarConfigurationController mStatusBarConfigurationController;
+    @Mock private DarkIconDispatcherStore mDarkIconDispatcherStore;
+    @Mock private DarkIconDispatcher mDarkIconDispatcher;
     @Rule
     public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(this);
 
@@ -145,6 +157,12 @@
 
     @Before
     public void setup() {
+        when(mStatusBarWindowControllerStore.forDisplay(anyInt()))
+                .thenReturn(mStatusBarWindowController);
+        when(mStatusBarConfigurationControllerStore.forDisplay(anyInt()))
+                .thenReturn(mStatusBarConfigurationController);
+        when(mDarkIconDispatcherStore.forDisplay(anyInt())).thenReturn(mDarkIconDispatcher);
+
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         mDependency.injectMockDependency(DarkIconDispatcher.class);
 
@@ -1276,11 +1294,14 @@
                 mDumpManager,
                 mStatusBarWindowStateController,
                 mKeyguardUpdateMonitor,
-                mock(DemoModeController.class));
+                mock(DemoModeController.class),
+                mStatusBarWindowControllerStore,
+                mStatusBarConfigurationControllerStore,
+                mDarkIconDispatcherStore);
     }
 
     private void setUpDaggerComponent() {
-        when(mStatusBarFragmentComponentFactory.create(any()))
+        when(mStatusBarFragmentComponentFactory.create(any(), any(), any(), any()))
                 .thenReturn(mHomeStatusBarComponent);
         when(mHomeStatusBarComponent.getHeadsUpAppearanceController())
                 .thenReturn(mHeadsUpAppearanceController);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
index b8be6aa..64d89c5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
@@ -81,6 +81,14 @@
         return super.getDisplay();
     }
 
+    @Override
+    public int getDisplayId() {
+        if (mCustomDisplay != null) {
+            return mCustomDisplay.getDisplayId();
+        }
+        return super.getDisplayId();
+    }
+
     public SysuiTestableContext createDefaultDisplayContext() {
         Display display = getBaseContext().getSystemService(DisplayManager.class).getDisplays()[0];
         return (SysuiTestableContext) createDisplayContext(display);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
index 50a19a9..fb2e2a3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.core
 
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController
 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.window.StatusBarWindowController
 
@@ -24,5 +26,7 @@
     override fun create(
         statusBarWindowController: StatusBarWindowController,
         statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+        statusBarConfigurationController: StatusBarConfigurationController,
+        darkIconDispatcher: DarkIconDispatcher,
     ): StatusBarInitializer = FakeStatusBarInitializer()
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
index 6e99027..b8dafb2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
@@ -19,7 +19,9 @@
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.data.repository.darkIconDispatcherStore
 import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.statusBarConfigurationControllerStore
 import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
 
 val Kosmos.fakeStatusBarInitializer by Kosmos.Fixture { FakeStatusBarInitializer() }
@@ -39,6 +41,8 @@
             fakeStatusBarInitializerFactory,
             fakeStatusBarWindowControllerStore,
             fakeStatusBarModeRepository,
+            statusBarConfigurationControllerStore,
+            darkIconDispatcherStore,
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerKosmos.kt
new file mode 100644
index 0000000..2a2f5f9
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.headsup
+
+import com.android.internal.logging.uiEventLoggerFake
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.mockAvalancheController by Fixture { mock<AvalancheController>() }
+
+val Kosmos.avalancheController by Fixture {
+    AvalancheController(dumpManager, uiEventLoggerFake, headsUpManagerLogger, bgHandler = mock())
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt
index de9485d..dfc8a68 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerKosmos.kt
@@ -16,8 +16,44 @@
 
 package com.android.systemui.statusbar.notification.headsup
 
+import android.content.applicationContext
+import android.view.accessibility.accessibilityManagerWrapper
+import com.android.internal.logging.uiEventLoggerFake
+import com.android.systemui.concurrency.fakeExecutor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.statusbar.statusBarStateController
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
+import com.android.systemui.statusbar.phone.keyguardBypassController
+import com.android.systemui.statusbar.policy.configurationController
+import com.android.systemui.util.concurrency.mockExecutorHandler
+import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.settings.fakeGlobalSettings
+import com.android.systemui.util.time.fakeSystemClock
 
-var Kosmos.headsUpManager by Fixture { mock<HeadsUpManager>() }
+var Kosmos.mockHeadsUpManager by Fixture { mock<HeadsUpManager>() }
+
+var Kosmos.headsUpManager: HeadsUpManager by Fixture {
+    HeadsUpManagerImpl(
+        applicationContext,
+        headsUpManagerLogger,
+        statusBarStateController,
+        keyguardBypassController,
+        mock<GroupMembershipManager>(),
+        visualStabilityProvider,
+        configurationController,
+        mockExecutorHandler(fakeExecutor),
+        fakeGlobalSettings,
+        fakeSystemClock,
+        fakeExecutor,
+        accessibilityManagerWrapper,
+        uiEventLoggerFake,
+        JavaAdapter(testScope.backgroundScope),
+        shadeInteractor,
+        avalancheController,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLoggerKosmos.kt
new file mode 100644
index 0000000..d595fa6
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLoggerKosmos.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.headsup
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.log.logcatLogBuffer
+import org.mockito.kotlin.mock
+
+val Kosmos.mockHeadsUpManagerLogger by Fixture { mock<HeadsUpManagerLogger>() }
+
+val Kosmos.headsUpManagerLogger by Fixture {
+    HeadsUpManagerLogger(logcatLogBuffer("HeadsUpManagerLogger"))
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt
index ec54c33..cc3f21b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/OnUserInteractionCallbackKosmos.kt
@@ -22,14 +22,14 @@
 import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl
 import com.android.systemui.statusbar.notification.collection.notifCollection
 import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 
 var Kosmos.onUserInteractionCallback: OnUserInteractionCallback by
     Kosmos.Fixture {
         OnUserInteractionCallbackImpl(
             notificationVisibilityProvider,
             notifCollection,
-            headsUpManager,
+            mockHeadsUpManager,
             statusBarStateController,
             visualStabilityCoordinator,
         )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
index 383e31d..65f4ec1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.shade.transition.largeScreenShadeInterpolator
+import com.android.systemui.statusbar.notification.headsup.mockAvalancheController
 import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
@@ -33,6 +34,6 @@
         /*bypassController=*/ stackScrollAlgorithmBypassController,
         /*statusBarKeyguardViewManager=*/ statusBarKeyguardViewManager,
         /*largeScreenShadeInterpolator=*/ largeScreenShadeInterpolator,
-        /*avalancheController=*/ avalancheController,
+        /*avalancheController=*/ mockAvalancheController,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
index a5c4bfd..67343c95 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmKosmos.kt
@@ -18,7 +18,6 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.statusbar.notification.headsup.AvalancheController
 import com.android.systemui.util.mockito.mock
 
 var Kosmos.stackScrollAlgorithmSectionProvider by Fixture {
@@ -28,5 +27,3 @@
 var Kosmos.stackScrollAlgorithmBypassController by Fixture {
     mock<StackScrollAlgorithm.BypassController>()
 }
-
-var Kosmos.avalancheController by Fixture { mock<AvalancheController>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
index e972c2c..64f16da 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/WindowRootViewVisibilityInteractorKosmos.kt
@@ -25,14 +25,14 @@
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 
 val Kosmos.windowRootViewVisibilityInteractor by Fixture {
     WindowRootViewVisibilityInteractor(
         scope = applicationCoroutineScope,
         windowRootViewVisibilityRepository = windowRootViewVisibilityRepository,
         keyguardRepository = keyguardRepository,
-        headsUpManager = headsUpManager,
+        headsUpManager = mockHeadsUpManager,
         powerInteractor = powerInteractor,
         activeNotificationsInteractor = activeNotificationsInteractor,
     ) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt
index f86824a..d0bf584 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt
@@ -26,7 +26,7 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.shade.domain.interactor.shadeLockscreenInteractor
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 import com.android.systemui.statusbar.notificationShadeWindowController
 import com.android.systemui.statusbar.policy.batteryController
 import com.android.systemui.statusbar.policy.deviceProvisionedController
@@ -42,7 +42,7 @@
             wakefulnessLifecycle,
             statusBarStateController,
             deviceProvisionedController,
-            headsUpManager,
+            mockHeadsUpManager,
             batteryController,
             scrimController,
             { biometricUnlockController },
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt
index 5b7f23b..9adaeff9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ShadeTouchableRegionManagerKosmos.kt
@@ -24,7 +24,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 import com.android.systemui.statusbar.notificationShadeWindowController
 import com.android.systemui.statusbar.policy.configurationController
 import com.android.systemui.util.kotlin.JavaAdapter
@@ -36,7 +36,7 @@
             applicationContext,
             notificationShadeWindowController,
             configurationController,
-            headsUpManager,
+            mockHeadsUpManager,
             shadeInteractor,
             { sceneInteractor },
             JavaAdapter(testScope.backgroundScope),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
index 6083414..7743a1c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
@@ -36,7 +36,7 @@
 import com.android.systemui.statusbar.commandQueue
 import com.android.systemui.statusbar.notification.collection.provider.launchFullScreenIntentProvider
 import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider
-import com.android.systemui.statusbar.notification.headsup.headsUpManager
+import com.android.systemui.statusbar.notification.headsup.mockHeadsUpManager
 import com.android.systemui.statusbar.notification.notificationTransitionAnimatorControllerProvider
 import com.android.systemui.statusbar.notification.row.onUserInteractionCallback
 import com.android.systemui.statusbar.notificationClickNotifier
@@ -58,7 +58,7 @@
             fakeExecutorHandler,
             fakeExecutor,
             notificationVisibilityProvider,
-            headsUpManager,
+            mockHeadsUpManager,
             activityStarter,
             commandQueue,
             notificationClickNotifier,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 50b6990..c9f06ac 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10837,8 +10837,12 @@
                     opti++;
                 }
                 synchronized (this) {
+                    // TODO: b/361161826 - Always pass in the dumpAll and let
+                    // BroadcastController decide how to treat it.
+                    final boolean requestDumpAll = "filter".equals(dumpPackage)
+                            ? dumpAll : true;
                     mBroadcastController.dumpBroadcastsLocked(fd, pw, args, opti,
-                            /* dumpAll= */ true, dumpPackage);
+                            requestDumpAll, dumpPackage);
                 }
             } else if ("broadcast-stats".equals(cmd)) {
                 if (opti < args.length) {
diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java
index aa06b7e..bfacfbb 100644
--- a/services/core/java/com/android/server/am/BroadcastController.java
+++ b/services/core/java/com/android/server/am/BroadcastController.java
@@ -47,6 +47,8 @@
 import static com.android.server.am.ActivityManagerService.UPDATE_TIME_PREFERENCE_MSG;
 import static com.android.server.am.ActivityManagerService.UPDATE_TIME_ZONE;
 import static com.android.server.am.ActivityManagerService.checkComponentPermission;
+import static com.android.server.am.BroadcastRecord.debugLog;
+import static com.android.server.am.BroadcastRecord.intentToString;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1017,6 +1019,13 @@
                         android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS,
                         callingPid, callingUid, "recordResponseEventWhileInBackground");
             }
+
+            if (brOptions.isDebugLogEnabled()) {
+                if (!isShellOrRoot(callingUid)
+                        && (callerApp == null || !callerApp.hasActiveInstrumentation())) {
+                    brOptions.setDebugLogEnabled(false);
+                }
+            }
         }
 
         // Verify that protected broadcasts are only being sent by system code,
@@ -1622,6 +1631,10 @@
             }
         }
         while (ir < NR) {
+            // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
+            if (callerInstantApp) {
+                intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
+            }
             if (receivers == null) {
                 receivers = new ArrayList();
             }
@@ -1647,7 +1660,9 @@
                     callerAppProcessState, mService.mPlatformCompat);
             broadcastSentEventRecord.setBroadcastRecord(r);
 
-            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
+            if (DEBUG_BROADCAST || r.debugLog()) {
+                Slog.v(TAG_BROADCAST, "Enqueueing broadcast " + r);
+            }
             queue.enqueueBroadcastLocked(r);
         } else {
             // There was nobody interested in the broadcast, but we still want to record
@@ -1657,11 +1672,19 @@
                 // This was an implicit broadcast... let's record it for posterity.
                 addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
             }
+            if (DEBUG_BROADCAST || debugLog(brOptions)) {
+                Slog.v(TAG_BROADCAST, "Skipping broadcast " + intentToString(intent)
+                        + " due to no receivers");
+            }
         }
 
         return ActivityManager.BROADCAST_SUCCESS;
     }
 
+    private boolean isShellOrRoot(int uid) {
+        return uid == SHELL_UID || uid == ROOT_UID;
+    }
+
     @GuardedBy("mService")
     private void scheduleCanceledResultTo(ProcessRecord resultToApp, IIntentReceiver resultTo,
             Intent intent, int userId, BroadcastOptions options, int callingUid,
@@ -2178,6 +2201,8 @@
         boolean printedAnything = false;
         boolean onlyReceivers = false;
         int filteredUid = Process.INVALID_UID;
+        boolean onlyFilter = false;
+        String dumpIntentAction = null;
 
         if ("history".equals(dumpPackage)) {
             if (opti < args.length && "-s".equals(args[opti])) {
@@ -2185,8 +2210,7 @@
             }
             onlyHistory = true;
             dumpPackage = null;
-        }
-        if ("receivers".equals(dumpPackage)) {
+        } else if ("receivers".equals(dumpPackage)) {
             onlyReceivers = true;
             dumpPackage = null;
             if (opti + 2 <= args.length) {
@@ -2205,7 +2229,23 @@
                     }
                 }
             }
+        } else if ("filter".equals(dumpPackage)) {
+            onlyFilter = true;
+            dumpPackage = null;
+            if (opti + 2 <= args.length) {
+                if ("--action".equals(args[opti++])) {
+                    dumpIntentAction = args[opti++];
+                    if (dumpIntentAction == null) {
+                        pw.printf("Missing argument for --action option\n");
+                        return;
+                    }
+                } else {
+                    pw.printf("Unknown argument: %s\n", args[opti]);
+                    return;
+                }
+            }
         }
+
         if (DEBUG_BROADCAST) {
             Slogf.d(TAG_BROADCAST, "dumpBroadcastsLocked(): dumpPackage=%s, onlyHistory=%b, "
                             + "onlyReceivers=%b, filteredUid=%d", dumpPackage, onlyHistory,
@@ -2213,7 +2253,7 @@
         }
 
         pw.println("ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)");
-        if (!onlyHistory && dumpAll) {
+        if (!onlyHistory && !onlyFilter && dumpAll) {
             if (mRegisteredReceivers.size() > 0) {
                 boolean printed = false;
                 Iterator it = mRegisteredReceivers.values().iterator();
@@ -2257,14 +2297,14 @@
 
         if (!onlyReceivers) {
             needSep = mBroadcastQueue.dumpLocked(fd, pw, args, opti,
-                    dumpConstants, dumpHistory, dumpAll, dumpPackage, needSep);
+                    dumpConstants, dumpHistory, dumpAll, dumpPackage, dumpIntentAction, needSep);
             printedAnything |= needSep;
         }
 
         needSep = true;
 
         synchronized (mStickyBroadcasts) {
-            if (!onlyHistory && !onlyReceivers && mStickyBroadcasts != null
+            if (!onlyHistory && !onlyReceivers && !onlyFilter && mStickyBroadcasts != null
                     && dumpPackage == null) {
                 for (int user = 0; user < mStickyBroadcasts.size(); user++) {
                     if (needSep) {
@@ -2312,13 +2352,12 @@
             }
         }
 
-        if (!onlyHistory && !onlyReceivers && dumpAll) {
+        if (!onlyHistory && !onlyReceivers && !onlyFilter && dumpAll) {
             pw.println();
-            pw.println("  Queue " + mBroadcastQueue.toString() + ": "
+            pw.println("  Queue " + mBroadcastQueue + ": "
                     + mBroadcastQueue.describeStateLocked());
             pw.println("  mHandler:");
             mService.mHandler.dump(new PrintWriterPrinter(pw), "    ");
-            needSep = true;
             printedAnything = true;
         }
 
diff --git a/services/core/java/com/android/server/am/BroadcastHistory.java b/services/core/java/com/android/server/am/BroadcastHistory.java
index d6e3d43..6ddf60b 100644
--- a/services/core/java/com/android/server/am/BroadcastHistory.java
+++ b/services/core/java/com/android/server/am/BroadcastHistory.java
@@ -29,6 +29,7 @@
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.Objects;
 
 /**
  * Collection of recent historical broadcasts that are available to be dumped
@@ -163,10 +164,11 @@
 
     @NeverCompile
     public boolean dumpLocked(@NonNull PrintWriter pw, @Nullable String dumpPackage,
-            @NonNull String queueName, @NonNull SimpleDateFormat sdf,
-            boolean dumpAll, boolean needSep) {
-        dumpBroadcastList(pw, sdf, mFrozenBroadcasts, "Frozen");
-        dumpBroadcastList(pw, sdf, mPendingBroadcasts, "Pending");
+            @Nullable String dumpIntentAction, @NonNull String queueName,
+            @NonNull SimpleDateFormat sdf, boolean dumpAll) {
+        boolean needSep = true;
+        dumpBroadcastList(pw, sdf, mFrozenBroadcasts, dumpIntentAction, dumpAll, "Frozen");
+        dumpBroadcastList(pw, sdf, mPendingBroadcasts, dumpIntentAction, dumpAll, "Pending");
 
         int i;
         boolean printed = false;
@@ -187,6 +189,10 @@
             if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
                 continue;
             }
+            if (dumpIntentAction != null && !Objects.equals(dumpIntentAction,
+                    r.intent.getAction())) {
+                continue;
+            }
             if (!printed) {
                 if (needSep) {
                     pw.println();
@@ -195,9 +201,16 @@
                 pw.println("  Historical broadcasts [" + queueName + "]:");
                 printed = true;
             }
-            if (dumpAll) {
+            if (dumpIntentAction != null) {
                 pw.print("  Historical Broadcast " + queueName + " #");
-                        pw.print(i); pw.println(":");
+                pw.print(i); pw.println(":");
+                r.dump(pw, "    ", sdf);
+                if (!dumpAll) {
+                    break;
+                }
+            } else if (dumpAll) {
+                pw.print("  Historical Broadcast " + queueName + " #");
+                pw.print(i); pw.println(":");
                 r.dump(pw, "    ", sdf);
             } else {
                 pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
@@ -213,7 +226,7 @@
             }
         } while (ringIndex != lastIndex);
 
-        if (dumpPackage == null) {
+        if (dumpPackage == null && dumpIntentAction == null) {
             lastIndex = ringIndex = mSummaryHistoryNext;
             if (dumpAll) {
                 printed = false;
@@ -276,15 +289,28 @@
     }
 
     private void dumpBroadcastList(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
-            @NonNull ArrayList<BroadcastRecord> broadcasts, @NonNull String flavor) {
+            @NonNull ArrayList<BroadcastRecord> broadcasts, @Nullable String dumpIntentAction,
+            boolean dumpAll, @NonNull String flavor) {
         pw.print("  "); pw.print(flavor); pw.println(" broadcasts:");
         if (broadcasts.isEmpty()) {
             pw.println("    <empty>");
         } else {
+            boolean printedAnything = false;
             for (int idx = broadcasts.size() - 1; idx >= 0; --idx) {
                 final BroadcastRecord r = broadcasts.get(idx);
+                if (dumpIntentAction != null && !Objects.equals(dumpIntentAction,
+                        r.intent.getAction())) {
+                    continue;
+                }
                 pw.print(flavor); pw.print("  broadcast #"); pw.print(idx); pw.println(":");
                 r.dump(pw, "    ", sdf);
+                printedAnything = true;
+                if (dumpIntentAction != null && !dumpAll) {
+                    break;
+                }
+            }
+            if (!printedAnything) {
+                pw.println("    <no-matches>");
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 6386af6..a7d74a9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -264,7 +264,8 @@
     @GuardedBy("mService")
     public abstract boolean dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
             @NonNull String[] args, int opti, boolean dumpConstants, boolean dumpHistory,
-            boolean dumpAll, @Nullable String dumpPackage, boolean needSep);
+            boolean dumpAll, @Nullable String dumpPackage, @Nullable String dumpIntentAction,
+            boolean needSep);
 
     /**
      * Execute {@link #dumpLocked} and store the output into
@@ -276,7 +277,7 @@
                     PrintWriter pw = new PrintWriter(out)) {
                 pw.print("Message: ");
                 pw.println(msg);
-                dumpLocked(fd, pw, null, 0, false, false, false, null, false);
+                dumpLocked(fd, pw, null, 0, false, false, false, null, null, false);
                 pw.flush();
             }
         }, DropBoxManager.IS_TEXT);
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 9e4666c..b270513 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -798,7 +798,9 @@
             mService.mOomAdjuster.mCachedAppOptimizer.freezeAppAsyncImmediateLSP(r.callerApp);
             return;
         }
-        if (DEBUG_BROADCAST) logv("Enqueuing " + r + " for " + r.receivers.size() + " receivers");
+        if (DEBUG_BROADCAST || r.debugLog()) {
+            logv("Enqueuing " + r + " for " + r.receivers.size() + " receivers");
+        }
 
         final int cookie = traceBegin("enqueueBroadcast");
         r.applySingletonPolicy(mService);
@@ -1019,7 +1021,9 @@
                 & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0;
 
         long startTimeNs = SystemClock.uptimeNanos();
-        if (DEBUG_BROADCAST) logv("Scheduling " + r + " to cold " + queue);
+        if (DEBUG_BROADCAST || r.debugLog()) {
+            logv("Scheduling " + r + " to cold " + queue);
+        }
         queue.app = mService.startProcessLocked(queue.processName, info, true, intentFlags,
                 hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
         if (queue.app == null) {
@@ -1176,7 +1180,9 @@
             }
         }
 
-        if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
+        if (DEBUG_BROADCAST || r.debugLog()) {
+            logv("Scheduling " + r + " to warm " + app);
+        }
         setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
                 "scheduleReceiverWarmLocked");
 
@@ -1562,12 +1568,17 @@
         // bookkeeping to update for ordered broadcasts
         if (!isDeliveryStateTerminal(oldDeliveryState)
                 && isDeliveryStateTerminal(newDeliveryState)) {
-            if (DEBUG_BROADCAST
-                    && newDeliveryState != BroadcastRecord.DELIVERY_DELIVERED) {
-                logw("Delivery state of " + r + " to " + receiver
+            if ((DEBUG_BROADCAST && newDeliveryState != BroadcastRecord.DELIVERY_DELIVERED)
+                    || r.debugLog()) {
+                final String msg = "Delivery state of " + r + " to " + receiver
                         + " via " + app + " changed from "
                         + deliveryStateToString(oldDeliveryState) + " to "
-                        + deliveryStateToString(newDeliveryState) + " because " + reason);
+                        + deliveryStateToString(newDeliveryState) + " because " + reason;
+                if (newDeliveryState == BroadcastRecord.DELIVERY_DELIVERED) {
+                    logv(msg);
+                } else {
+                    logw(msg);
+                }
             }
 
             notifyFinishReceiver(queue, app, r, index, receiver);
@@ -2417,12 +2428,33 @@
     @GuardedBy("mService")
     public boolean dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
             @NonNull String[] args, int opti, boolean dumpConstants, boolean dumpHistory,
-            boolean dumpAll, @Nullable String dumpPackage, boolean needSep) {
+            boolean dumpAll, @Nullable String dumpPackage, @Nullable String dumpIntentAction,
+            boolean needSep) {
         final long now = SystemClock.uptimeMillis();
         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
         ipw.increaseIndent();
         ipw.println();
 
+        if (dumpIntentAction == null) {
+            dumpProcessQueues(ipw, now);
+            dumpBroadcastsWithIgnoredPolicies(ipw);
+            dumpForegroundUids(ipw);
+
+            if (dumpConstants) {
+                mFgConstants.dump(ipw);
+                mBgConstants.dump(ipw);
+            }
+        }
+
+        if (dumpHistory) {
+            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+            needSep = mHistory.dumpLocked(ipw, dumpPackage, dumpIntentAction, mQueueName,
+                    sdf, dumpAll);
+        }
+        return needSep;
+    }
+
+    private void dumpProcessQueues(@NonNull IndentingPrintWriter ipw, @UptimeMillisLong long now) {
         ipw.println("📋 Per-process queues:");
         ipw.increaseIndent();
         for (int i = 0; i < mProcessQueues.size(); i++) {
@@ -2470,28 +2502,21 @@
         }
         ipw.decreaseIndent();
         ipw.println();
+    }
 
+    private void dumpBroadcastsWithIgnoredPolicies(@NonNull IndentingPrintWriter ipw) {
         ipw.println("Broadcasts with ignored delivery group policies:");
         ipw.increaseIndent();
         mService.dumpDeliveryGroupPolicyIgnoredActions(ipw);
         ipw.decreaseIndent();
         ipw.println();
+    }
 
+    private void dumpForegroundUids(@NonNull IndentingPrintWriter ipw) {
         ipw.println("Foreground UIDs:");
         ipw.increaseIndent();
         ipw.println(mUidForeground);
         ipw.decreaseIndent();
         ipw.println();
-
-        if (dumpConstants) {
-            mFgConstants.dump(ipw);
-            mBgConstants.dump(ipw);
-        }
-
-        if (dumpHistory) {
-            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-            needSep = mHistory.dumpLocked(ipw, dumpPackage, mQueueName, sdf, dumpAll, needSep);
-        }
-        return needSep;
     }
 }
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8d0805d..c1b0a76 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -1285,31 +1285,43 @@
     }
 
     @Override
+    @NonNull
     public String toString() {
         if (mCachedToString == null) {
-            String label = intent.getAction();
-            if (label == null) {
-                label = intent.toString();
-            }
             mCachedToString = "BroadcastRecord{" + toShortString() + "}";
         }
         return mCachedToString;
     }
 
+    @NonNull
     public String toShortString() {
         if (mCachedToShortString == null) {
-            String label = intent.getAction();
-            if (label == null) {
-                label = intent.toString();
-            }
+            final String label = intentToString(intent);
             mCachedToShortString = Integer.toHexString(System.identityHashCode(this))
                     + " " + label + "/u" + userId;
         }
         return mCachedToShortString;
     }
 
+    @NonNull
+    public static String intentToString(@NonNull Intent intent) {
+        String label = intent.getAction();
+        if (label == null) {
+            label = intent.toString();
+        }
+        return label;
+    }
+
+    public boolean debugLog() {
+        return debugLog(options);
+    }
+
+    public static boolean debugLog(@Nullable BroadcastOptions options) {
+        return options != null && options.isDebugLogEnabled();
+    }
+
     @NeverCompile
-    public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+    public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
         long token = proto.start(fieldId);
         proto.write(BroadcastRecordProto.USER_ID, userId);
         proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction());
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 49149e1..1503d88 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1005,6 +1005,11 @@
     }
 
     @GuardedBy(anyOf = {"mService", "mProcLock"})
+    boolean hasActiveInstrumentation() {
+        return mInstr != null;
+    }
+
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
     boolean isKilledByAm() {
         return mKilledByAm;
     }
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 56cb6f49..febf24e 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -71,6 +71,9 @@
                         (reason) -> updateMouseSwapPrimaryButton()),
                 Map.entry(Settings.System.getUriFor(Settings.System.MOUSE_SCROLLING_ACCELERATION),
                         (reason) -> updateMouseScrollingAcceleration()),
+                Map.entry(Settings.System.getUriFor(
+                                Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED),
+                        (reason) -> updateMouseAccelerationEnabled()),
                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_POINTER_SPEED),
                         (reason) -> updateTouchpadPointerSpeed()),
                 Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_NATURAL_SCROLLING),
@@ -191,6 +194,11 @@
                 InputSettings.isMouseScrollingAccelerationEnabled(mContext));
     }
 
+    private void updateMouseAccelerationEnabled() {
+        mNative.setMouseAccelerationEnabled(
+                InputSettings.isMousePointerAccelerationEnabled(mContext));
+    }
+
     private void updateTouchpadPointerSpeed() {
         mNative.setTouchpadPointerSpeed(
                 constrainPointerSpeedValue(InputSettings.getTouchpadPointerSpeed(mContext)));
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index ab5a680..7dbde64 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -138,6 +138,8 @@
 
     void setMouseSwapPrimaryButtonEnabled(boolean enabled);
 
+    void setMouseAccelerationEnabled(boolean enabled);
+
     void setTouchpadPointerSpeed(int speed);
 
     void setTouchpadNaturalScrollingEnabled(boolean enabled);
@@ -429,6 +431,9 @@
         public native void setMouseSwapPrimaryButtonEnabled(boolean enabled);
 
         @Override
+        public native void setMouseAccelerationEnabled(boolean enabled);
+
+        @Override
         public native void setTouchpadPointerSpeed(int speed);
 
         @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7375a68..f50e8aa 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3082,16 +3082,42 @@
 
     private void sendRegisteredOnlyBroadcast(Intent baseIntent) {
         int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true);
-        Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        for (int userId : userIds) {
-            getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
-        }
-        // explicitly send the broadcast to all DND packages, even if they aren't currently running
-        for (int userId : userIds) {
-            for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
-                Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags(
-                        Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
+        if (Flags.nmBinderPerfReduceZenBroadcasts()) {
+            for (int userId : userIds) {
+                Context userContext = getContext().createContextAsUser(UserHandle.of(userId), 0);
+                String[] dndPackages = mConditionProviders.getAllowedPackages(userId)
+                        .toArray(new String[0]);
+
+                // We send the broadcast to all DND packages in the second step, so leave them out
+                // of this first broadcast for *running* receivers. That ensures each package only
+                // receives it once.
+                Intent registeredOnlyIntent = new Intent(baseIntent)
+                        .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                userContext.sendBroadcastMultiplePermissions(registeredOnlyIntent,
+                        /* receiverPermissions= */ new String[0],
+                        /* excludedPermissions= */ new String[0],
+                        /* excludedPackages= */ dndPackages);
+
+                for (String pkg : dndPackages) {
+                    Intent pkgIntent = new Intent(baseIntent).setPackage(pkg)
+                            .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                    userContext.sendBroadcast(pkgIntent);
+                }
+            }
+        } else {
+            Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            for (int userId : userIds) {
+                getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
+            }
+
+            // explicitly send the broadcast to all DND packages, even if they aren't currently
+            // running
+            for (int userId : userIds) {
+                for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
+                    Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags(
+                            Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                    getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
+                }
             }
         }
     }
@@ -4276,16 +4302,16 @@
 
         @Override
         @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-        public @NonNull String[] getTypeAdjustmentDeniedPackages() {
+        public @NonNull int[] getAllowedAdjustmentKeyTypesForPackage(String pkg) {
             checkCallerIsSystemOrSystemUiOrShell();
-            return mAssistants.getTypeAdjustmentDeniedPackages();
+            return mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg);
         }
 
-        @Override
         @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+        public void setAssistantAdjustmentKeyTypeStateForPackage(String pkg, int type,
+                                                                 boolean enabled) {
             checkCallerIsSystemOrSystemUiOrShell();
-            mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
+            mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, type, enabled);
 
             handleSavePolicyFile();
         }
@@ -7083,7 +7109,7 @@
                         toRemove.add(potentialKey);
                     } else if (notificationClassificationUi()
                             && !mAssistants.isTypeAdjustmentAllowedForPackage(
-                            r.getSbn().getPackageName())) {
+                            r.getSbn().getPackageName(), adjustments.getInt(KEY_TYPE))) {
                         toRemove.add(potentialKey);
                     }
                 }
@@ -11740,7 +11766,11 @@
         private static final String ATT_DENIED = "denied_adjustments";
         private static final String ATT_ENABLED_TYPES = "enabled_key_types";
         private static final String ATT_NAS_UNSUPPORTED = "unsupported_adjustments";
-        private static final String ATT_TYPES_DENIED_APPS = "types_denied_apps";
+        // Encapsulates a list of packages and the bundle types enabled for each package.
+        private static final String TAG_TYPES_ENABLED_FOR_APPS = "types_enabled_for_apps";
+        // Encapsulates the bundle types enabled for a package.
+        private static final String ATT_APP_ENABLED_TYPES = "app_enabled_types";
+        private static final String ATT_PACKAGE = "package";
 
         private final Object mLock = new Object();
 
@@ -11756,8 +11786,14 @@
         @GuardedBy("mLock")
         private Map<Integer, HashSet<String>> mNasUnsupported = new ArrayMap<>();
 
+        // Types of classifications (aka bundles) enabled/allowed for this package.
+        // If the set is NULL (or package is not in the list), default classification allow list
+        // (the global one) should be used.
+        // If the set is empty, that indicates the package explicitly has all classifications
+        // disallowed.
         @GuardedBy("mLock")
-        private Set<String> mClassificationTypeDeniedPackages = new ArraySet<>();
+        private Map<String, Set<Integer>> mClassificationTypePackagesEnabledTypes =
+                new ArrayMap<>();
 
         protected ComponentName mDefaultFromConfig = null;
 
@@ -11958,41 +11994,88 @@
             }
         }
 
+        /**
+         * Returns whether the type adjustment is allowed for this particular package.
+         * If no package-specific restrictions have been set, defaults to the same value as
+         * isAdjustmentKeyTypeAllowed(type).
+         */
         @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-        protected @NonNull boolean isTypeAdjustmentAllowedForPackage(String pkg) {
+        protected boolean isTypeAdjustmentAllowedForPackage(String pkg,
+                                                                     @Adjustment.Types int type) {
             synchronized (mLock) {
                 if (notificationClassificationUi()) {
-                    return !mClassificationTypeDeniedPackages.contains(pkg);
+                    if (mClassificationTypePackagesEnabledTypes.containsKey(pkg)) {
+                        Set<Integer> enabled = mClassificationTypePackagesEnabledTypes.get(pkg);
+                        if (enabled != null) {
+                            return enabled.contains(type);
+                        }
+                    }
+                    // If mClassificationTypePackagesEnabledTypes does not contain the pkg, or
+                    // the stored set is null, return the default.
+                    return isAdjustmentKeyTypeAllowed(type);
                 }
             }
-            return true;
+            return false;
         }
 
         @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-        protected @NonNull String[] getTypeAdjustmentDeniedPackages() {
+        protected @NonNull int[] getAllowedAdjustmentKeyTypesForPackage(String pkg) {
             synchronized (mLock) {
                 if (notificationClassificationUi()) {
-                    return mClassificationTypeDeniedPackages.toArray(new String[0]);
+                    if (mClassificationTypePackagesEnabledTypes.containsKey(pkg)) {
+                        Set<Integer> enabled = mClassificationTypePackagesEnabledTypes.get(pkg);
+                        if (enabled != null) {
+                            // Convert Set to int[] for return.
+                            int[] returnEnabled = new int[enabled.size()];
+                            int i = 0;
+                            for (int val: enabled) {
+                                returnEnabled[i] = val;
+                                i++;
+                            }
+                            return returnEnabled;
+                        }
+                    }
+                    // If package is not in the map, or the value is null, return the default.
+                    return getAllowedAdjustmentKeyTypes();
                 }
             }
-            return new String[]{};
+            return new int[]{};
         }
 
         /**
          * Set whether a particular package can have its notification channels adjusted to have a
          * different type by NotificationAssistants.
+         * Note: once this method is called to enable or disable a specific type for a package,
+         * the global default is set as the starting point, and the type is enabled/disabled from
+         * there. Future changes to the global default will not apply automatically to this package.
          */
         @FlaggedApi(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
+        public void setAssistantAdjustmentKeyTypeStateForPackage(String pkg,
+                                                       @Adjustment.Types int type,
+                                                       boolean enabled) {
             if (!notificationClassificationUi()) {
                 return;
             }
             synchronized (mLock) {
-                if (enabled) {
-                    mClassificationTypeDeniedPackages.remove(pkg);
-                } else {
-                    mClassificationTypeDeniedPackages.add(pkg);
+                Set<Integer> enabledTypes = null;
+                if (mClassificationTypePackagesEnabledTypes.containsKey(pkg)) {
+                    enabledTypes = mClassificationTypePackagesEnabledTypes.get(pkg);
                 }
+                if (enabledTypes == null) {
+                    // Use global default to start.
+                    enabledTypes = new ArraySet<Integer>();
+                    // Convert from int[] to Set<Integer>
+                    for (int value : getAllowedAdjustmentKeyTypes()) {
+                        enabledTypes.add(value);
+                    }
+                }
+
+                if (enabled) {
+                    enabledTypes.add(type);
+                } else {
+                    enabledTypes.remove(type);
+                }
+                mClassificationTypePackagesEnabledTypes.put(pkg, enabledTypes);
             }
         }
 
@@ -12459,16 +12542,25 @@
                         TextUtils.join(",", mAllowedAdjustmentKeyTypes));
                 out.endTag(null, ATT_ENABLED_TYPES);
                 if (notificationClassificationUi()) {
-                    out.startTag(null, ATT_TYPES_DENIED_APPS);
-                    out.attribute(null, ATT_TYPES,
-                            TextUtils.join(",", mClassificationTypeDeniedPackages));
-                    out.endTag(null, ATT_TYPES_DENIED_APPS);
+                    out.startTag(null, TAG_TYPES_ENABLED_FOR_APPS);
+                    for (String pkg: mClassificationTypePackagesEnabledTypes.keySet()) {
+                        Set<Integer> allowedTypes =
+                                mClassificationTypePackagesEnabledTypes.get(pkg);
+                        if (allowedTypes != null) {
+                            out.startTag(null, ATT_APP_ENABLED_TYPES);
+                            out.attribute(null, ATT_PACKAGE, pkg);
+                            out.attribute(null, ATT_TYPES, TextUtils.join(",", allowedTypes));
+                            out.endTag(null, ATT_APP_ENABLED_TYPES);
+                        }
+                    }
+                    out.endTag(null, TAG_TYPES_ENABLED_FOR_APPS);
                 }
             }
         }
 
         @Override
-        protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {
+        protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException,
+                XmlPullParserException {
             if (!notificationClassification()) {
                 return;
             }
@@ -12495,12 +12587,25 @@
                         }
                     }
                 }
-            } else if (notificationClassificationUi() && ATT_TYPES_DENIED_APPS.equals(tag)) {
-                final String apps = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+            } else if (TAG_TYPES_ENABLED_FOR_APPS.equals(tag)) {
+                final int appsOuterDepth = parser.getDepth();
                 synchronized (mLock) {
-                    mClassificationTypeDeniedPackages.clear();
-                    if (!TextUtils.isEmpty(apps)) {
-                        mClassificationTypeDeniedPackages.addAll(Arrays.asList(apps.split(",")));
+                    mClassificationTypePackagesEnabledTypes.clear();
+                    while (XmlUtils.nextElementWithin(parser, appsOuterDepth)) {
+                        if (!ATT_APP_ENABLED_TYPES.equals(parser.getName())) {
+                            continue;
+                        }
+                        final String app = XmlUtils.readStringAttribute(parser, ATT_PACKAGE);
+                        Set<Integer> allowedTypes = new ArraySet<>();
+                        final String typesString = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+                        if (!TextUtils.isEmpty(typesString)) {
+                            allowedTypes = Arrays.stream(typesString.split(","))
+                                    .map(Integer::valueOf)
+                                    .collect(Collectors.toSet());
+                        }
+                        // Empty type list is allowed, because empty type list signifies the user
+                        // has manually cleared the package of allowed types.
+                        mClassificationTypePackagesEnabledTypes.put(app, allowedTypes);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 65a38ae..f15c23e 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -187,3 +187,13 @@
   description: "Enables sound uri with vibration source in notification channel"
   bug: "351975435"
 }
+
+flag {
+  name: "nm_binder_perf_reduce_zen_broadcasts"
+  namespace: "systemui"
+  description: "Don't send duplicate zen-related (policy changed, etc) broadcasts"
+  bug: "324376849"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index c4e4c42..1726f0d 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -1594,12 +1594,9 @@
                 }
                 halParams.tids = params.tids;
             }
-            if (halParams.calculationWindowMillis
-                    == mDefaultCpuHeadroomCalculationWindowMillis) {
-                synchronized (mCpuHeadroomLock) {
-                    final CpuHeadroomResult res = mCpuHeadroomCache.get(halParams);
-                    if (res != null) return res;
-                }
+            synchronized (mCpuHeadroomLock) {
+                final CpuHeadroomResult res = mCpuHeadroomCache.get(halParams);
+                if (res != null) return res;
             }
             final boolean shouldCheckUserModeCpuTime =
                     mEnforceCpuHeadroomUserModeCpuTimeCheck
@@ -1622,11 +1619,8 @@
                     Slog.wtf(TAG, "CPU headroom from Power HAL is invalid");
                     return null;
                 }
-                if (halParams.calculationWindowMillis
-                        == mDefaultCpuHeadroomCalculationWindowMillis) {
-                    synchronized (mCpuHeadroomLock) {
-                        mCpuHeadroomCache.add(halParams, result);
-                    }
+                synchronized (mCpuHeadroomLock) {
+                    mCpuHeadroomCache.add(halParams, result);
                 }
                 if (shouldCheckUserModeCpuTime) {
                     synchronized (mCpuHeadroomLock) {
@@ -1737,12 +1731,9 @@
             final GpuHeadroomParams halParams = new GpuHeadroomParams();
             halParams.calculationType = params.calculationType;
             halParams.calculationWindowMillis = params.calculationWindowMillis;
-            if (halParams.calculationWindowMillis
-                    == mDefaultGpuHeadroomCalculationWindowMillis) {
-                synchronized (mGpuHeadroomLock) {
-                    final GpuHeadroomResult res = mGpuHeadroomCache.get(halParams);
-                    if (res != null) return res;
-                }
+            synchronized (mGpuHeadroomLock) {
+                final GpuHeadroomResult res = mGpuHeadroomCache.get(halParams);
+                if (res != null) return res;
             }
             // return from HAL directly
             try {
@@ -1751,11 +1742,8 @@
                     Slog.wtf(TAG, "GPU headroom from Power HAL is invalid");
                     return null;
                 }
-                if (halParams.calculationWindowMillis
-                        == mDefaultGpuHeadroomCalculationWindowMillis) {
-                    synchronized (mGpuHeadroomLock) {
-                        mGpuHeadroomCache.add(halParams, headroom);
-                    }
+                synchronized (mGpuHeadroomLock) {
+                    mGpuHeadroomCache.add(halParams, headroom);
                 }
                 return headroom;
             } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 66b77b9..4c2d849 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -50,6 +50,7 @@
 import static com.android.window.flags.Flags.balRequireOptInByPendingIntentCreator;
 import static com.android.window.flags.Flags.balShowToastsBlocked;
 import static com.android.window.flags.Flags.balStrictModeRo;
+import static com.android.window.flags.Flags.balStrictModeGracePeriod;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 import static java.util.Objects.requireNonNull;
@@ -516,7 +517,9 @@
                 return !callerExplicitOptOut();
             }
             return mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
-                    == MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+                    != MODE_BACKGROUND_ACTIVITY_START_DENIED
+                    && mCheckedOptions.getPendingIntentCreatorBackgroundActivityStartMode()
+                    != MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
         }
 
         public boolean realCallerExplicitOptInOrAutoOptIn() {
@@ -524,7 +527,9 @@
                 return !realCallerExplicitOptOut();
             }
             return mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
-                    == MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+                    != MODE_BACKGROUND_ACTIVITY_START_DENIED
+                    && mCheckedOptions.getPendingIntentBackgroundActivityStartMode()
+                    != MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
         }
 
         public boolean callerExplicitOptOut() {
@@ -1908,7 +1913,14 @@
                             (state.mOriginatingPendingIntent != null));
         }
 
-        logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_GRACE_PERIOD);
+        if (logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_GRACE_PERIOD)) {
+            if (balStrictModeRo() && balStrictModeGracePeriod()) {
+                String abortDebugMessage = "Activity start is only allowed by grace period. "
+                        + "This may stop working in the future. "
+                        + "intent: " + state.mIntent;
+                strictModeLaunchAborted(state.mRealCallingUid, abortDebugMessage);
+            }
+        }
         logIfOnlyAllowedBy(finalVerdict, state, BAL_ALLOW_NON_APP_VISIBLE_WINDOW);
 
         if (balImprovedMetrics()) {
@@ -1952,24 +1964,29 @@
      * Logs details about the activity starts if the only reason it is allowed is the provided
      * {@code balCode}.
      */
-    private static void logIfOnlyAllowedBy(BalVerdict finalVerdict, BalState state, int balCode) {
+    private static boolean logIfOnlyAllowedBy(BalVerdict finalVerdict, BalState state,
+            int balCode) {
         if (finalVerdict.getRawCode() == balCode) {
             if (state.realCallerExplicitOptInOrAutoOptIn()
                     && state.mResultForRealCaller != null
                     && state.mResultForRealCaller.allows()
                     && state.mResultForRealCaller.getRawCode() != balCode) {
                 // real caller could allow with a different exemption
+                return false;
             } else if (state.callerExplicitOptInOrAutoOptIn()
                     && state.mResultForCaller != null
                     && state.mResultForCaller.allows()
                     && state.mResultForCaller.getRawCode() != balCode) {
                 // caller could allow with a different exemption
+                return false;
             } else {
                 // log to determine grace period length distribution
                 Slog.wtf(TAG, "Activity start ONLY allowed by " + balCodeToString(balCode) + " "
                         + finalVerdict.mMessage + ": " + state);
+                return true;
             }
         }
+        return false;
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index cba606c..98ed6f7 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -101,7 +101,8 @@
             // isLeashReadyForDispatching (used to dispatch the leash of the control) is
             // depending on mGivenInsetsReady. Therefore, triggering notifyControlChanged here
             // again, so that the control with leash can be eventually dispatched
-            if (!mGivenInsetsReady && isServerVisible() && !givenInsetsPending) {
+            if (!mGivenInsetsReady && isServerVisible() && !givenInsetsPending
+                    && mControlTarget != null) {
                 mGivenInsetsReady = true;
                 ImeTracker.forLogging().onProgress(mStatsToken,
                         ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 7276007..d1585d0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -384,7 +384,7 @@
         }
         final boolean serverVisibleChanged = mServerVisible != isServerVisible;
         setServerVisible(isServerVisible);
-        if (mControl != null) {
+        if (mControl != null && mControlTarget != null) {
             final boolean positionChanged = updateInsetsControlPosition(windowState);
             if (!(positionChanged || mHasPendingPosition)
                     // The insets hint would be updated while changing the position. Here updates it
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ce85184..9df65f6 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -371,7 +371,7 @@
         array.add(provider);
     }
 
-    void notifyControlChanged(InsetsControlTarget target, InsetsSourceProvider provider) {
+    void notifyControlChanged(@NonNull InsetsControlTarget target, InsetsSourceProvider provider) {
         addToPendingControlMaps(target, provider);
         notifyPendingInsetsControlChanged();
     }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 813fec1..f634beb 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -345,6 +345,7 @@
     void setMouseReverseVerticalScrollingEnabled(bool enabled);
     void setMouseScrollingAccelerationEnabled(bool enabled);
     void setMouseSwapPrimaryButtonEnabled(bool enabled);
+    void setMouseAccelerationEnabled(bool enabled);
     void setTouchpadPointerSpeed(int32_t speed);
     void setTouchpadNaturalScrollingEnabled(bool enabled);
     void setTouchpadTapToClickEnabled(bool enabled);
@@ -502,6 +503,9 @@
         // True if the mouse primary button is swapped (left/right buttons).
         bool mouseSwapPrimaryButtonEnabled{false};
 
+        // True if the mouse cursor will accelerate as the mouse moves faster.
+        bool mousePointerAccelerationEnabled{true};
+
         // The touchpad pointer speed, as a number from -7 (slowest) to 7 (fastest).
         int32_t touchpadPointerSpeed{0};
 
@@ -847,6 +851,7 @@
         outConfig->mouseReverseVerticalScrollingEnabled =
                 mLocked.mouseReverseVerticalScrollingEnabled;
         outConfig->mouseSwapPrimaryButtonEnabled = mLocked.mouseSwapPrimaryButtonEnabled;
+        outConfig->mousePointerAccelerationEnabled = mLocked.mousePointerAccelerationEnabled;
 
         outConfig->touchpadPointerSpeed = mLocked.touchpadPointerSpeed;
         outConfig->touchpadNaturalScrollingEnabled = mLocked.touchpadNaturalScrollingEnabled;
@@ -1458,6 +1463,21 @@
             InputReaderConfiguration::Change::MOUSE_SETTINGS);
 }
 
+void NativeInputManager::setMouseAccelerationEnabled(bool enabled) {
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+
+        if (mLocked.mousePointerAccelerationEnabled == enabled) {
+            return;
+        }
+
+        mLocked.mousePointerAccelerationEnabled = enabled;
+    } // release lock
+
+    mInputManager->getReader().requestRefreshConfiguration(
+            InputReaderConfiguration::Change::POINTER_SPEED);
+}
+
 void NativeInputManager::setPointerSpeed(int32_t speed) {
     { // acquire lock
         std::scoped_lock _l(mLock);
@@ -3220,6 +3240,11 @@
     im->setMouseSwapPrimaryButtonEnabled(enabled);
 }
 
+static void nativeSetMouseAccelerationEnabled(JNIEnv* env, jobject nativeImplObj, bool enabled) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+    im->setMouseAccelerationEnabled(enabled);
+}
+
 static jboolean nativeSetKernelWakeEnabled(JNIEnv* env, jobject nativeImplObj, jint deviceId,
                                       jboolean enabled) {
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -3280,6 +3305,7 @@
         {"setMouseScrollingAccelerationEnabled", "(Z)V",
          (void*)nativeSetMouseScrollingAccelerationEnabled},
         {"setMouseSwapPrimaryButtonEnabled", "(Z)V", (void*)nativeSetMouseSwapPrimaryButtonEnabled},
+        {"setMouseAccelerationEnabled", "(Z)V", (void*)nativeSetMouseAccelerationEnabled},
         {"setTouchpadPointerSpeed", "(I)V", (void*)nativeSetTouchpadPointerSpeed},
         {"setTouchpadNaturalScrollingEnabled", "(Z)V",
          (void*)nativeSetTouchpadNaturalScrollingEnabled},
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index ea80f28..db6aeeb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -602,7 +602,7 @@
         mQueue.dumpDebug(new ProtoOutputStream(),
                 ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
         mQueue.dumpLocked(FileDescriptor.err, new PrintWriter(Writer.nullWriter()),
-                null, 0, true, true, true, null, false);
+                null, 0, true, true, true, null, null, false);
         mQueue.dumpToDropBoxLocked(TAG);
 
         BroadcastQueue.logv(TAG);
@@ -1019,7 +1019,7 @@
             mQueue.dumpDebug(new ProtoOutputStream(),
                     ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
             mQueue.dumpLocked(FileDescriptor.err, new PrintWriter(Writer.nullWriter()),
-                    null, 0, true, true, true, null, false);
+                    null, 0, true, true, true, null, null, false);
         }
 
         waitForIdle();
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index bd15bd0..cd94c0f 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -1411,7 +1411,6 @@
         halParams3.tids = tids;
         halParams3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
 
-        // this params should not be cached as the window is not default
         CpuHeadroomParamsInternal params4 = new CpuHeadroomParamsInternal();
         params4.calculationWindowMillis = 123;
         CpuHeadroomParams halParams4 = new CpuHeadroomParams();
@@ -1450,11 +1449,7 @@
         assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
         assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3));
         assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4));
-        verify(mIPowerMock, times(1)).getCpuHeadroom(any());
-        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1));
-        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams2));
-        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3));
-        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4));
+        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
 
         // after 500ms more it should be served with cache
         Thread.sleep(500);
@@ -1463,11 +1458,7 @@
         assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
         assertEquals(halRet3, service.getBinderServiceInstance().getCpuHeadroom(params3));
         assertEquals(halRet4, service.getBinderServiceInstance().getCpuHeadroom(params4));
-        verify(mIPowerMock, times(1)).getCpuHeadroom(any());
-        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams1));
-        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams2));
-        verify(mIPowerMock, times(0)).getCpuHeadroom(eq(halParams3));
-        verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams4));
+        verify(mIPowerMock, times(0)).getCpuHeadroom(any());
 
         // after 1+ seconds it should be served from HAL as it exceeds 1000 millis interval
         Thread.sleep(600);
@@ -1574,18 +1565,14 @@
         clearInvocations(mIPowerMock);
         assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
         assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
-        verify(mIPowerMock, times(1)).getGpuHeadroom(any());
-        verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1));
-        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
+        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
 
         // after 500ms it should be served with cache
         Thread.sleep(500);
         clearInvocations(mIPowerMock);
         assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
         assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
-        verify(mIPowerMock, times(1)).getGpuHeadroom(any());
-        verify(mIPowerMock, times(0)).getGpuHeadroom(eq(halParams1));
-        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
+        verify(mIPowerMock, times(0)).getGpuHeadroom(any());
 
         // after 1+ seconds it should be served from HAL as it exceeds 1000 millis interval
         Thread.sleep(600);
diff --git a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
index c7a06b8..b1df0f1 100644
--- a/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/security/advancedprotection/AdvancedProtectionServiceTest.java
@@ -31,7 +31,6 @@
 import android.os.test.TestLooper;
 import android.provider.Settings;
 import android.security.advancedprotection.AdvancedProtectionFeature;
-import android.security.advancedprotection.AdvancedProtectionManager;
 import android.security.advancedprotection.IAdvancedProtectionCallback;
 
 import androidx.annotation.NonNull;
@@ -55,8 +54,7 @@
     private Context mContext;
     private AdvancedProtectionService.AdvancedProtectionStore mStore;
     private TestLooper mLooper;
-    AdvancedProtectionFeature mTestFeature2g = new AdvancedProtectionFeature(
-            AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G);
+    AdvancedProtectionFeature mFeature = new AdvancedProtectionFeature("test-id");
 
     @Before
     public void setup() throws Settings.SettingNotFoundException {
@@ -107,7 +105,7 @@
                     @NonNull
                     @Override
                     public AdvancedProtectionFeature getFeature() {
-                        return mTestFeature2g;
+                        return mFeature;
                     }
 
                     @Override
@@ -137,7 +135,7 @@
                     @NonNull
                     @Override
                     public AdvancedProtectionFeature getFeature() {
-                        return mTestFeature2g;
+                        return mFeature;
                     }
 
                     @Override
@@ -167,7 +165,7 @@
                     @NonNull
                     @Override
                     public AdvancedProtectionFeature getFeature() {
-                        return mTestFeature2g;
+                        return mFeature;
                     }
 
                     @Override
@@ -240,10 +238,8 @@
 
     @Test
     public void testGetFeatures() {
-        AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature(
-                AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G);
-        AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature(
-                AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES);
+        AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature("id-1");
+        AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature("id-2");
         AdvancedProtectionHook hook = new AdvancedProtectionHook(mContext, true) {
             @NonNull
             @Override
@@ -272,10 +268,8 @@
 
     @Test
     public void testGetFeatures_featureNotAvailable() {
-        AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature(
-                AdvancedProtectionManager.FEATURE_ID_DISALLOW_CELLULAR_2G);
-        AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature(
-                AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES);
+        AdvancedProtectionFeature feature1 = new AdvancedProtectionFeature("id-1");
+        AdvancedProtectionFeature feature2 = new AdvancedProtectionFeature("id-2");
         AdvancedProtectionHook hook = new AdvancedProtectionHook(mContext, true) {
             @NonNull
             @Override
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index d1dc8d6..4f5cdb7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -19,9 +19,13 @@
 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
 import static android.service.notification.Adjustment.TYPE_NEWS;
+import static android.service.notification.Adjustment.TYPE_OTHER;
 import static android.service.notification.Adjustment.TYPE_PROMOTION;
+import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
+import static android.service.notification.Flags.notificationClassification;
 
 import static com.android.server.notification.NotificationManagerService.DEFAULT_ALLOWED_ADJUSTMENTS;
+import static com.android.server.notification.NotificationManagerService.DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -144,6 +148,17 @@
         mAssistants.readXml(parser, mNm::canUseManagedServices, false, USER_ALL);
     }
 
+    private void setDefaultAllowedAdjustmentKeyTypes(NotificationAssistants assistants) {
+        assistants.setAssistantAdjustmentKeyTypeState(TYPE_OTHER, false);
+        assistants.setAssistantAdjustmentKeyTypeState(TYPE_PROMOTION, false);
+        assistants.setAssistantAdjustmentKeyTypeState(TYPE_SOCIAL_MEDIA, false);
+        assistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false);
+        assistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, false);
+
+        for (int type : DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES) {
+            assistants.setAssistantAdjustmentKeyTypeState(type, true);
+        }
+    }
 
     @Before
     public void setUp() throws Exception {
@@ -154,6 +169,9 @@
                 com.android.internal.R.string.config_defaultAssistantAccessComponent,
                 mCn.flattenToString());
         mAssistants = spy(mNm.new NotificationAssistants(mContext, mLock, mUserProfiles, miPm));
+        if (notificationClassification()) {
+            setDefaultAllowedAdjustmentKeyTypes(mAssistants);
+        }
         when(mNm.getBinderService()).thenReturn(mINm);
         mContext.ensureTestableResources();
 
@@ -695,7 +713,7 @@
         mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_CONTENT_RECOMMENDATION, true);
 
         assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
-                .containsExactlyElementsIn(List.of(TYPE_PROMOTION, TYPE_CONTENT_RECOMMENDATION));
+                .containsExactly(TYPE_PROMOTION, TYPE_CONTENT_RECOMMENDATION);
     }
 
     @Test
@@ -716,7 +734,7 @@
         writeXmlAndReload(USER_ALL);
 
         assertThat(mAssistants.getAllowedAdjustmentKeyTypes()).asList()
-                .containsExactlyElementsIn(List.of(TYPE_NEWS, TYPE_CONTENT_RECOMMENDATION));
+                .containsExactly(TYPE_NEWS, TYPE_CONTENT_RECOMMENDATION);
     }
 
     @Test
@@ -732,76 +750,146 @@
 
     @Test
     @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-    public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsAndDenies() {
-        // Given that a package is allowed to have its type adjusted,
-        String allowedPackage = "allowed.package";
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
-        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
-
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
-        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
-
-        // Set type adjustment disallowed for this package
-        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, false);
-
-        // Then the package is marked as denied
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
-                .containsExactly(allowedPackage);
-        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
-
-        // Set type adjustment allowed again
-        mAssistants.setTypeAdjustmentForPackageState(allowedPackage, true);
-
-        // Then the package is marked as allowed again
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).isEmpty();
-        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPackage));
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_usesGlobalDefault() {
+        String pkg = "my.package";
+        setDefaultAllowedAdjustmentKeyTypes(mAssistants);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_PROMOTION)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isFalse();
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactlyElementsIn(DEFAULT_ALLOWED_ADJUSTMENT_KEY_TYPES);
     }
 
     @Test
     @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
-    public void testSetAssistantAdjustmentKeyTypeStateForPackage_deniesMultiple() {
-        // Given packages not allowed to have their type adjusted,
-        String deniedPkg1 = "denied.Pkg1";
-        String deniedPkg2 = "denied.Pkg2";
-        String deniedPkg3 = "denied.Pkg3";
-        // Set type adjustment disallowed for these packages
-        mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
-        mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, false);
-        mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsAndDenies() {
+        setDefaultAllowedAdjustmentKeyTypes(mAssistants);
+        // Given that a package is set to have a type adjustment allowed,
+        String pkg = "my.package";
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_NEWS, true);
 
-        // Then the packages are marked as denied
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
-                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg2, deniedPkg3));
-        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
-        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
-        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+        // The newly set state is the combination of the global default and the newly set type.
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isTrue();
 
-        // And when we re-allow one of them,
-        mAssistants.setTypeAdjustmentForPackageState(deniedPkg2, true);
+        // Set type adjustment disallowed for this package
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_NEWS, false);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_PROMOTION, false);
 
-        // Then the rest of the original packages are still marked as denied.
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
-                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
-        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg1));
-        assertTrue(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg2));
-        assertFalse(mAssistants.isTypeAdjustmentAllowedForPackage(deniedPkg3));
+        // Then the package is marked as denied
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).isEmpty();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isFalse();
+
+        // Set type adjustment allowed again
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_NEWS, true);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_PROMOTION, true);
+
+        // Then the package is marked as allowed again
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_PROMOTION)).isTrue();
+
+        // Set type adjustment promotions false,
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_PROMOTION, false);
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactly(TYPE_NEWS);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_PROMOTION)).isFalse();
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_allowsMultiplePkgs() {
+        setDefaultAllowedAdjustmentKeyTypes(mAssistants);
+        // Given packages allowed to have their type adjusted to  TYPE_NEWS,
+        String allowedPkg1 = "allowed.Pkg1";
+        String allowedPkg2 = "allowed.Pkg2";
+        String allowedPkg3 = "allowed.Pkg3";
+        // Set type adjustment allowed for these packages
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg1, TYPE_NEWS, true);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg2, TYPE_NEWS, true);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg3, TYPE_NEWS, true);
+
+        // The newly set state is the combination of the global default and the newly set type.
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg1)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg2)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg3)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPkg1, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPkg2, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPkg3, TYPE_NEWS)).isTrue();
+
+        // And when we deny some of them,
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg2, TYPE_NEWS, false);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg2, TYPE_PROMOTION,
+                false);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg3, TYPE_PROMOTION,
+                false);
+
+        // Then the rest of the original packages are still marked as allowed.
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg1)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg2)).isEmpty();
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg3)).asList()
+                .containsExactly(TYPE_NEWS);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPkg1, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPkg2, TYPE_NEWS)).isFalse();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(allowedPkg3, TYPE_NEWS)).isTrue();
     }
 
     @Test
     @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
     public void testSetAssistantAdjustmentKeyTypeStateForPackage_readWriteXml() throws Exception {
+        setDefaultAllowedAdjustmentKeyTypes(mAssistants);
         mAssistants.loadDefaultsFromConfig(true);
         String deniedPkg1 = "denied.Pkg1";
         String allowedPkg2 = "allowed.Pkg2";
-        String deniedPkg3 = "denied.Pkg3";
+        String allowedPkg3 = "allowed.Pkg3";
         // Set type adjustment disallowed or allowed for these packages
-        mAssistants.setTypeAdjustmentForPackageState(deniedPkg1, false);
-        mAssistants.setTypeAdjustmentForPackageState(allowedPkg2, true);
-        mAssistants.setTypeAdjustmentForPackageState(deniedPkg3, false);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(deniedPkg1, TYPE_PROMOTION, false);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg2, TYPE_NEWS, true);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg3, TYPE_NEWS, true);
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(allowedPkg3, TYPE_SOCIAL_MEDIA,
+                true);
 
         writeXmlAndReload(USER_ALL);
 
-        assertThat(mAssistants.getTypeAdjustmentDeniedPackages()).asList()
-                .containsExactlyElementsIn(List.of(deniedPkg1, deniedPkg3));
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(deniedPkg1)).isEmpty();
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg2)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(allowedPkg3)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_SOCIAL_MEDIA, TYPE_PROMOTION);
+    }
+
+    @Test
+    @EnableFlags(android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI)
+    public void testSetAssistantAdjustmentKeyTypeStateForPackage_noGlobalImpact() throws Exception {
+        setDefaultAllowedAdjustmentKeyTypes(mAssistants);
+        // When the global state is changed,
+        mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true);
+
+        // The package state reflects the global state.
+        String pkg = "my.package";
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_PROMOTION)).isTrue();
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION);
+
+        // Once the package specific state is modified,
+        mAssistants.setAssistantAdjustmentKeyTypeStateForPackage(pkg, TYPE_SOCIAL_MEDIA, true);
+
+        // The package specific state combines the global state with those modifications
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_SOCIAL_MEDIA)).isTrue();
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION, TYPE_SOCIAL_MEDIA);
+
+        // And further changes to the global state are ignored.
+        mAssistants.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false);
+        assertThat(mAssistants.isTypeAdjustmentAllowedForPackage(pkg, TYPE_NEWS)).isTrue();
+        assertThat(mAssistants.getAllowedAdjustmentKeyTypesForPackage(pkg)).asList()
+                .containsExactly(TYPE_NEWS, TYPE_PROMOTION, TYPE_SOCIAL_MEDIA);
     }
 }
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 601023f..301165f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -365,6 +365,9 @@
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
@@ -380,9 +383,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Consumer;
 
-import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
-import platform.test.runner.parameterized.Parameters;
-
 @SmallTest
 @RunWith(ParameterizedAndroidJunit4.class)
 @RunWithLooper
@@ -644,6 +644,9 @@
         doNothing().when(mContext).sendBroadcast(any(), anyString());
         doNothing().when(mContext).sendBroadcastAsUser(any(), any());
         doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
+        doNothing().when(mContext).sendBroadcastMultiplePermissions(any(), any(), any(), any());
+        doReturn(mContext).when(mContext).createContextAsUser(eq(mUser), anyInt());
+
         TestableContentResolver cr = mock(TestableContentResolver.class);
         when(mContext.getContentResolver()).thenReturn(cr);
         doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt());
@@ -7631,7 +7634,7 @@
         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), anyInt())).thenReturn(true);
 
         // Set up notifications that will be adjusted
         final NotificationRecord r1 = spy(generateNotificationRecord(
@@ -11235,7 +11238,8 @@
     }
 
     @Test
-    public void onZenModeChanged_sendsBroadcasts() throws Exception {
+    @DisableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS)
+    public void onZenModeChanged_sendsBroadcasts_oldBehavior() throws Exception {
         when(mAmi.getCurrentUserId()).thenReturn(100);
         when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
         when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
@@ -11288,6 +11292,74 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS)
+    public void onZenModeChanged_sendsBroadcasts() throws Exception {
+        when(mAmi.getCurrentUserId()).thenReturn(100);
+        when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
+        when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
+            @Override
+            public List<String> answer(InvocationOnMock invocation) {
+                int userId = invocation.getArgument(0);
+                switch (userId) {
+                    case 100:
+                        return Lists.newArrayList("a", "b", "c");
+                    case 101:
+                        return Lists.newArrayList();
+                    case 102:
+                        return Lists.newArrayList("b");
+                    default:
+                        throw new IllegalArgumentException(
+                                "Why would you ask for packages of userId " + userId + "?");
+                }
+            }
+        });
+        Context context100 = mock(Context.class);
+        doReturn(context100).when(mContext).createContextAsUser(eq(UserHandle.of(100)), anyInt());
+        Context context101 = mock(Context.class);
+        doReturn(context101).when(mContext).createContextAsUser(eq(UserHandle.of(101)), anyInt());
+        Context context102 = mock(Context.class);
+        doReturn(context102).when(mContext).createContextAsUser(eq(UserHandle.of(102)), anyInt());
+
+        mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
+                "testing!", false);
+        waitForIdle();
+
+        // Verify broadcasts per user: registered receivers first, then DND packages.
+        InOrder inOrder = inOrder(context100, context101, context102);
+
+        inOrder.verify(context100).sendBroadcastMultiplePermissions(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
+                eq(new String[0]), eq(new String[0]), eq(new String[] {"a", "b", "c"}));
+        inOrder.verify(context100).sendBroadcast(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setPackage("a")
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+        inOrder.verify(context100).sendBroadcast(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setPackage("b")
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+        inOrder.verify(context100).sendBroadcast(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setPackage("c")
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+
+        inOrder.verify(context101).sendBroadcastMultiplePermissions(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
+                eq(new String[0]), eq(new String[0]), eq(new String[] {}));
+
+        inOrder.verify(context102).sendBroadcastMultiplePermissions(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
+                eq(new String[0]), eq(new String[0]), eq(new String[] {"b"}));
+        inOrder.verify(context102).sendBroadcast(
+                eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+                        .setPackage("b")
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+    }
+
+    @Test
     @EnableFlags(android.app.Flags.FLAG_MODES_API)
     public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception {
         mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged(
@@ -17305,7 +17377,7 @@
                 NotificationManagerService.WorkerHandler.class);
         mService.setHandler(handler);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), anyInt())).thenReturn(true);
 
         Bundle signals = new Bundle();
         signals.putInt(KEY_TYPE, TYPE_NEWS);
@@ -17349,7 +17421,11 @@
                 NotificationManagerService.WorkerHandler.class);
         mService.setHandler(handler);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), eq(TYPE_NEWS)))
+                .thenReturn(true);
+        // Blocking adjustments for a different type does nothing
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), eq(TYPE_PROMOTION)))
+                .thenReturn(false);
 
         Bundle signals = new Bundle();
         signals.putInt(KEY_TYPE, TYPE_NEWS);
@@ -17364,8 +17440,9 @@
 
         assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
 
-        // When we block adjustments for this package
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false);
+        // When we block adjustments for this package/type
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), eq(TYPE_PROMOTION)))
+                .thenReturn(false);
 
         signals.putInt(KEY_TYPE, TYPE_PROMOTION);
         mBinderService.applyAdjustmentFromAssistant(null, adjustment);
@@ -17695,7 +17772,7 @@
         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), anyInt())).thenReturn(true);
 
         // Post a single notification
         final boolean hasOriginalSummary = false;
@@ -17735,7 +17812,7 @@
         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), anyInt())).thenReturn(true);
 
         // Post grouped notifications
         final String originalGroupName = "originalGroup";
@@ -17784,7 +17861,7 @@
         when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
         when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true);
-        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true);
+        when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString(), anyInt())).thenReturn(true);
 
         // Post grouped notifications
         final String originalGroupName = "originalGroup";
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e7c9e92..e27dbe5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1869,10 +1869,18 @@
     }
 
     private boolean shouldDeleteObsoleteData(UserHandle userHandle) {
-        final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
-        // If a profile owner is not defined for the given user, obsolete data should be deleted
-        return dpmInternal == null
-                || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle) == null;
+        if (android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()) {
+            final SupervisionManagerInternal smInternal = getSupervisionManagerInternal();
+            // If supervision is not enabled for the given user, obsolete data should be deleted.
+            return smInternal == null
+                    || !smInternal.isSupervisionEnabledForUser(userHandle.getIdentifier());
+        } else {
+            final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
+            // If a profile owner is not defined for the given user, obsolete data should be deleted
+            return dpmInternal == null
+                    || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle)
+                            == null;
+        }
     }
 
     private String buildFullToken(String packageName, String token) {