Merge "Add flag for stashable bubbles" into main
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index c74c48c..5f57c39 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -31,6 +31,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.app.Notification;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
@@ -1366,6 +1367,7 @@
          * @return This object for method chaining
          */
         @FlaggedApi(Flags.FLAG_JOB_DEBUG_INFO_APIS)
+        @SuppressLint("BuilderSetStyle")
         @NonNull
         public Builder removeDebugTag(@NonNull String tag) {
             mDebugTags.remove(tag);
diff --git a/core/api/current.txt b/core/api/current.txt
index 13958d2..16de8fe7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3344,9 +3344,9 @@
   public abstract class AccessibilityService extends android.app.Service {
     ctor public AccessibilityService();
     method public void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl);
-    method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
+    method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public final void attachAccessibilityOverlayToDisplay(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl);
-    method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
+    method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public final void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method public boolean clearCache();
     method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo);
     method public final void disableSelf();
@@ -3354,7 +3354,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController();
     method @NonNull public final android.accessibilityservice.AccessibilityButtonController getAccessibilityButtonController(int);
-    method @FlaggedApi("android.view.accessibility.braille_display_hid") @NonNull public android.accessibilityservice.BrailleDisplayController getBrailleDisplayController();
+    method @FlaggedApi("android.view.accessibility.braille_display_hid") @NonNull public final android.accessibilityservice.BrailleDisplayController getBrailleDisplayController();
     method @NonNull @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public final android.accessibilityservice.FingerprintGestureController getFingerprintGestureController();
     method @Nullable public final android.accessibilityservice.InputMethod getInputMethod();
     method @NonNull public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index d70fa19..fd9600c 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -3554,8 +3554,8 @@
      * @see #OVERLAY_RESULT_INVALID
      * @see #OVERLAY_RESULT_INTERNAL_ERROR
      */
-    @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")
-    public void attachAccessibilityOverlayToDisplay(
+    @FlaggedApi(android.view.accessibility.Flags.FLAG_A11Y_OVERLAY_CALLBACKS)
+    public final void attachAccessibilityOverlayToDisplay(
             int displayId,
             @NonNull SurfaceControl sc,
             @NonNull @CallbackExecutor Executor executor,
@@ -3627,8 +3627,8 @@
      * @see #OVERLAY_RESULT_INVALID
      * @see #OVERLAY_RESULT_INTERNAL_ERROR
      */
-    @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks")
-    public void attachAccessibilityOverlayToWindow(
+    @FlaggedApi(android.view.accessibility.Flags.FLAG_A11Y_OVERLAY_CALLBACKS)
+    public final void attachAccessibilityOverlayToWindow(
             int accessibilityWindowId,
             @NonNull SurfaceControl sc,
             @NonNull @CallbackExecutor Executor executor,
@@ -3645,7 +3645,7 @@
      */
     @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
     @NonNull
-    public BrailleDisplayController getBrailleDisplayController() {
+    public final BrailleDisplayController getBrailleDisplayController() {
         BrailleDisplayController.checkApiFlagIsEnabled();
         synchronized (mLock) {
             if (mBrailleDisplayController == null) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e1cb630..79e2bd4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1183,6 +1183,7 @@
      * @see #setIntent(Intent, ComponentCaller)
      */
     @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+    @SuppressLint("OnNameExpected")
     public @Nullable ComponentCaller getCaller() {
         return mCaller;
     }
@@ -1203,6 +1204,7 @@
      * @see #getCaller
      */
     @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+    @SuppressLint("OnNameExpected")
     public void setIntent(@Nullable Intent newIntent, @Nullable ComponentCaller newCaller) {
         internalSetIntent(newIntent, newCaller);
     }
@@ -7161,6 +7163,7 @@
      * @see ComponentCaller
      */
     @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+    @SuppressLint("OnNameExpected")
     public @NonNull ComponentCaller getInitialCaller() {
         return mInitialCaller;
     }
@@ -7188,10 +7191,11 @@
      * @see #getCaller
      */
     @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS)
+    @SuppressLint("OnNameExpected")
     public @NonNull ComponentCaller getCurrentCaller() {
         if (mCurrentCaller == null) {
             throw new IllegalStateException("The caller is null because #getCurrentCaller should be"
-                    + " called within #onNewIntent method");
+                    + " called within #onNewIntent or #onActivityResult methods");
         }
         return mCurrentCaller;
     }
@@ -9634,6 +9638,7 @@
      *                            the default behaviour
      */
     @FlaggedApi(android.security.Flags.FLAG_ASM_RESTRICTIONS_ENABLED)
+    @SuppressLint("OnNameExpected")
     public void setAllowCrossUidActivitySwitchFromBelow(boolean allowed) {
         ActivityClient.getInstance().setAllowCrossUidActivitySwitchFromBelow(mToken, allowed);
     }
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d8df447..8e99e46b 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1282,4 +1282,15 @@
      */
     public abstract void addStartInfoTimestamp(int key, long timestampNs, int uid, int pid,
             int userId);
+
+    /**
+     * It is similar {@link IActivityManager#killApplication(String, int, int, String, int)} but
+     * it immediately stop the package.
+     *
+     * <p>Note: Do not call this method from inside PMS's lock, otherwise it'll run into
+     * watchdog reset.
+     * @hide
+     */
+    public abstract void killApplicationSync(String pkgName, int appId, int userId,
+            String reason, int exitInfoReason);
 }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index c6a1546..9ea55f5 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -103,8 +103,7 @@
     @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = {
             MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED,
             MODE_BACKGROUND_ACTIVITY_START_ALLOWED,
-            MODE_BACKGROUND_ACTIVITY_START_DENIED,
-            MODE_BACKGROUND_ACTIVITY_START_COMPAT})
+            MODE_BACKGROUND_ACTIVITY_START_DENIED})
     public @interface BackgroundActivityStartMode {}
     /**
      * No explicit value chosen. The system will decide whether to grant privileges.
@@ -118,13 +117,6 @@
      * Deny the {@link PendingIntent} to use the background activity start privileges.
      */
     public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2;
-    /**
-     * Special behavior for compatibility.
-     * Similar to {@link #MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED}
-     *
-     * @hide
-     */
-    public static final int MODE_BACKGROUND_ACTIVITY_START_COMPAT = -1;
 
     /**
      * The package name that created the options.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 54f6909..6865f9c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3583,6 +3583,9 @@
             return mAttributionTag;
         }
 
+        /**
+         * Persistent device Id of the proxy that noted the op
+         */
         @FlaggedApi(Flags.FLAG_DEVICE_ID_IN_OP_PROXY_INFO_ENABLED)
         public @Nullable String getDeviceId() { return mDeviceId; }
 
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
index 0e8e2e3..397477d 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityOptions.BackgroundActivityStartMode;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_COMPAT;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
 
@@ -55,7 +54,7 @@
     public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION =
             "android.pendingIntent.backgroundActivityAllowedByPermission";
 
-    private Integer mPendingIntentBalAllowed = MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
+    private @Nullable Boolean mPendingIntentBalAllowed = null;
     private boolean mPendingIntentBalAllowedByPermission = false;
 
     ComponentOptions() {
@@ -66,9 +65,12 @@
         // results they want, which is their loss.
         opts.setDefusable(true);
 
-        mPendingIntentBalAllowed =
-                opts.getInt(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
-                        MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
+        boolean pendingIntentBalAllowedIsSetExplicitly =
+                opts.containsKey(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED);
+        if (pendingIntentBalAllowedIsSetExplicitly) {
+            mPendingIntentBalAllowed =
+                    opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED);
+        }
         setPendingIntentBackgroundActivityLaunchAllowedByPermission(
                 opts.getBoolean(
                         KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, false));
@@ -83,8 +85,7 @@
      * @hide
      */
     @Deprecated public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) {
-        mPendingIntentBalAllowed = allowed ? MODE_BACKGROUND_ACTIVITY_START_ALLOWED
-                : MODE_BACKGROUND_ACTIVITY_START_DENIED;
+        mPendingIntentBalAllowed = allowed;
     }
 
     /**
@@ -97,8 +98,11 @@
      * @hide
      */
     @Deprecated public boolean isPendingIntentBackgroundActivityLaunchAllowed() {
-        // cannot return all detail, so return the value used up to API level 33 for compatibility
-        return mPendingIntentBalAllowed != MODE_BACKGROUND_ACTIVITY_START_DENIED;
+        if (mPendingIntentBalAllowed == null) {
+            // cannot return null, so return the value used up to API level 33 for compatibility
+            return true;
+        }
+        return mPendingIntentBalAllowed;
     }
 
     /**
@@ -115,15 +119,16 @@
             @BackgroundActivityStartMode int state) {
         switch (state) {
             case MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED:
-            case MODE_BACKGROUND_ACTIVITY_START_DENIED:
-            case MODE_BACKGROUND_ACTIVITY_START_COMPAT:
+                mPendingIntentBalAllowed = null;
+                break;
             case MODE_BACKGROUND_ACTIVITY_START_ALLOWED:
-                mPendingIntentBalAllowed = state;
+                mPendingIntentBalAllowed = true;
+                break;
+            case MODE_BACKGROUND_ACTIVITY_START_DENIED:
+                mPendingIntentBalAllowed = false;
                 break;
             default:
-                // Assume that future values are some variant of allowing the start.
-                mPendingIntentBalAllowed = MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-                break;
+                throw new IllegalArgumentException(state + " is not valid");
         }
         return this;
     }
@@ -136,7 +141,13 @@
      * @see #setPendingIntentBackgroundActivityStartMode(int)
      */
     public @BackgroundActivityStartMode int getPendingIntentBackgroundActivityStartMode() {
-        return mPendingIntentBalAllowed;
+        if (mPendingIntentBalAllowed == null) {
+            return MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
+        } else if (mPendingIntentBalAllowed) {
+            return MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
+        } else {
+            return MODE_BACKGROUND_ACTIVITY_START_DENIED;
+        }
     }
 
     /**
@@ -159,8 +170,8 @@
     /** @hide */
     public Bundle toBundle() {
         Bundle b = new Bundle();
-        if (mPendingIntentBalAllowed != MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED) {
-            b.putInt(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
+        if (mPendingIntentBalAllowed != null) {
+            b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, mPendingIntentBalAllowed);
         }
         if (mPendingIntentBalAllowedByPermission) {
             b.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0672064..7ea3091 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8892,6 +8892,62 @@
             }
         }
 
+        private void fixTitleAndTextForCompactMessaging(StandardTemplateParams p) {
+            Message m = findLatestIncomingMessage();
+            final CharSequence text = (m == null) ? null : m.mText;
+            CharSequence sender = m == null ? null
+                    : m.mSender == null || TextUtils.isEmpty(m.mSender.getName())
+                            ? mUser.getName() : m.mSender.getName();
+
+            CharSequence conversationTitle = mIsGroupConversation ? mConversationTitle : null;
+
+            // we want to have colon for possible title for conversation.
+            final BidiFormatter bidi = BidiFormatter.getInstance();
+            if (sender != null) {
+                sender = mBuilder.mContext.getString(
+                        com.android.internal.R.string.notification_messaging_title_template,
+                        bidi.unicodeWrap(sender), "");
+            } else if (conversationTitle != null) {
+                conversationTitle = mBuilder.mContext.getString(
+                        com.android.internal.R.string.notification_messaging_title_template,
+                        bidi.unicodeWrap(conversationTitle), "");
+            }
+
+            if (Flags.cleanUpSpansAndNewLines()) {
+                conversationTitle = stripStyling(conversationTitle);
+                sender = stripStyling(sender);
+            }
+
+            final boolean showOnlySenderName = showOnlySenderName();
+
+            final CharSequence title;
+            boolean isConversationTitleAvailable = !showOnlySenderName && conversationTitle != null;
+            if (isConversationTitleAvailable) {
+                title = conversationTitle;
+            } else {
+                title = sender;
+            }
+
+            p.title(title);
+            // when the conversation title is available, use headerTextSecondary for sender and
+            // summaryText for text
+            if (isConversationTitleAvailable) {
+                p.headerTextSecondary(sender);
+                p.summaryText(text);
+            } else {
+                // when it is not, use headerTextSecondary for text and don't use summaryText
+                p.headerTextSecondary(text);
+                p.summaryText(null);
+            }
+        }
+
+        /** developer settings to always show sender name */
+        private boolean showOnlySenderName() {
+            return SystemProperties.getBoolean(
+                    "persist.compact_heads_up_notification.show_only_sender_name",
+                    false);
+        }
+
         /**
          * @hide
          */
@@ -9211,19 +9267,19 @@
                 }
             }
 
-            // This method fills title and text
-            fixTitleAndTextExtras(mBuilder.mN.extras);
             final StandardTemplateParams p = mBuilder.mParams.reset()
                     .viewType(StandardTemplateParams.VIEW_TYPE_HEADS_UP)
                     .highlightExpander(isConversationLayout)
                     .fillTextsFrom(mBuilder)
-                    .hideTime(true)
-                    .summaryText("");
-            p.headerTextSecondary(p.mText);
+                    .hideTime(true);
+
+            fixTitleAndTextForCompactMessaging(p);
             TemplateBindResult bindResult = new TemplateBindResult();
 
             RemoteViews contentView = mBuilder.applyStandardTemplate(
                     mBuilder.getMessagingCompactHeadsUpLayoutResource(), p, bindResult);
+            contentView.setViewVisibility(R.id.header_text_secondary_divider, View.GONE);
+            contentView.setViewVisibility(R.id.header_text_divider, View.GONE);
             if (conversationIcon != null) {
                 contentView.setViewVisibility(R.id.icon, View.GONE);
                 contentView.setViewVisibility(R.id.conversation_icon, View.VISIBLE);
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index dc44764..0deb842 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -378,6 +378,14 @@
                 }
             ],
             "file_patterns": ["(/|^)ContextImpl.java"]
+        },
+        {
+            "file_patterns": [
+                "(/|^)Activity.*.java",
+                "(/|^)PendingIntent.java",
+                "(/|^)ComtextImpl.java"
+            ],
+            "name": "CtsWindowManagerBackgroundActivityTestCases"
         }
     ],
     "postsubmit": [
@@ -392,14 +400,6 @@
         {
             "file_patterns": ["(/|^)AppOpsManager.java"],
             "name": "CtsAppOpsTestCases"
-        },
-        {
-            "file_patterns": [
-                "(/|^)Activity.*.java",
-                "(/|^)PendingIntent.java",
-                "(/|^)ComtextImpl.java"
-            ],
-            "name": "CtsWindowManagerBackgroundActivityTestCases"
         }
     ]
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4bc1ce6..c529f7d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1698,7 +1698,7 @@
 
     /**
      * A boolean extra indicating whether device encryption can be skipped as part of
-     * <a href="#managed-provisioning>provisioning</a>.
+     * <a href="#managed-provisioning">provisioning</a>.
      *
      * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} or an intent with action
      * {@link #ACTION_PROVISION_MANAGED_DEVICE} that starts device owner provisioning.
diff --git a/core/java/android/app/prediction/OWNERS b/core/java/android/app/prediction/OWNERS
index fe012da..73168fb 100644
--- a/core/java/android/app/prediction/OWNERS
+++ b/core/java/android/app/prediction/OWNERS
@@ -1,2 +1,4 @@
+pinyaoting@google.com
+hyunyoungs@google.com
 adamcohen@google.com
 sunnygoyal@google.com
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 2e252c1..b074e8b 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -60,10 +60,6 @@
  * {@link android.app.PendingIntent#getIntentSender() PendingIntent.getIntentSender()}.
  */
 public class IntentSender implements Parcelable {
-    private static final Bundle SEND_INTENT_DEFAULT_OPTIONS =
-            ActivityOptions.makeBasic().setPendingIntentBackgroundActivityStartMode(
-                    ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_COMPAT).toBundle();
-
     @UnsupportedAppUsage
     private final IIntentSender mTarget;
     IBinder mWhitelistToken;
@@ -165,8 +161,7 @@
      */
     public void sendIntent(Context context, int code, Intent intent,
             OnFinished onFinished, Handler handler) throws SendIntentException {
-        sendIntent(context, code, intent, onFinished, handler, null,
-                SEND_INTENT_DEFAULT_OPTIONS);
+        sendIntent(context, code, intent, onFinished, handler, null, null /* options */);
     }
 
     /**
@@ -199,7 +194,7 @@
             OnFinished onFinished, Handler handler, String requiredPermission)
             throws SendIntentException {
         sendIntent(context, code, intent, onFinished, handler, requiredPermission,
-                SEND_INTENT_DEFAULT_OPTIONS);
+                null /* options */);
     }
 
     /**
diff --git a/core/java/android/content/TEST_MAPPING b/core/java/android/content/TEST_MAPPING
index f08395a..41a4288 100644
--- a/core/java/android/content/TEST_MAPPING
+++ b/core/java/android/content/TEST_MAPPING
@@ -56,6 +56,10 @@
         }
       ],
       "file_patterns": ["(/|^)Context.java", "(/|^)ContextWrapper.java"]
+    },
+    {
+      "name": "CtsWindowManagerBackgroundActivityTestCases",
+      "file_patterns": ["(/|^)IntentSender.java"]
     }
   ],
   "ravenwood-presubmit": [
@@ -65,9 +69,5 @@
     }
   ],
   "postsubmit": [
-    {
-      "name": "CtsWindowManagerBackgroundActivityTestCases",
-      "file_patterns": ["(/|^)IntentSender.java"]
-    }
   ]
 }
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 5056557..bb89e07 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -17,8 +17,11 @@
 package android.os;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.app.ActivityThread;
 
+import java.io.IOException;
 import java.util.Map;
 
 /**
@@ -113,5 +116,20 @@
     @TestApi
     public static native Long getTargetFrameworkCompatibilityMatrixVersion();
 
+    /**
+     * Executes a shell command using shell user identity, and return the standard output in string.
+     *
+     * @hide
+     */
+    private static @Nullable String runShellCommand(@NonNull String command) throws IOException {
+        var activityThread = ActivityThread.currentActivityThread();
+        var instrumentation = activityThread.getInstrumentation();
+        var automation = instrumentation.getUiAutomation();
+        var pfd = automation.executeShellCommand(command);
+        try (var is = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+            return new String(is.readAllBytes());
+        }
+    }
+
     private VintfObject() {}
 }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 120846c..708c196 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -2017,7 +2017,7 @@
                 return false;
             }
             final UserInfo userInfo = userManager.getUserInfo(userId);
-            return userInfo != null && !userInfo.isManagedProfile();
+            return userInfo != null && !userInfo.isProfile();
         }
 
         /**
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
index 793e58a..293015f 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceIntelligenceService.java
@@ -18,6 +18,9 @@
 
 import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
 
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.CallSuper;
 import android.annotation.CallbackExecutor;
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
@@ -40,13 +43,16 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
+import android.os.Looper;
 import android.os.OutcomeReceiver;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.infra.AndroidFuture;
@@ -88,6 +94,14 @@
     private static final String TAG = OnDeviceIntelligenceService.class.getSimpleName();
 
     private volatile IRemoteProcessingService mRemoteProcessingService;
+    private Handler mHandler;
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null /* callback */, true /* async */);
+    }
 
     /**
      * The {@link Intent} that must be declared as handled by the service. To be supported, the
@@ -107,38 +121,49 @@
     @Override
     public final IBinder onBind(@NonNull Intent intent) {
         if (SERVICE_INTERFACE.equals(intent.getAction())) {
-            // TODO(326052028) : Move the remote method calls to an app handler from the binder
-            //  thread.
             return new IOnDeviceIntelligenceService.Stub() {
                 /** {@inheritDoc} */
                 @Override
                 public void ready() {
-                    OnDeviceIntelligenceService.this.onReady();
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(OnDeviceIntelligenceService::onReady,
+                                    OnDeviceIntelligenceService.this));
                 }
 
                 @Override
                 public void getVersion(RemoteCallback remoteCallback) {
                     Objects.requireNonNull(remoteCallback);
-                    OnDeviceIntelligenceService.this.onGetVersion(l -> {
-                        Bundle b = new Bundle();
-                        b.putLong(OnDeviceIntelligenceManager.API_VERSION_BUNDLE_KEY, l);
-                        remoteCallback.sendResult(b);
-                    });
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onGetVersion,
+                                    OnDeviceIntelligenceService.this, l -> {
+                                        Bundle b = new Bundle();
+                                        b.putLong(
+                                                OnDeviceIntelligenceManager.API_VERSION_BUNDLE_KEY,
+                                                l);
+                                        remoteCallback.sendResult(b);
+                                    }));
                 }
 
                 @Override
                 public void listFeatures(int callerUid,
                         IListFeaturesCallback listFeaturesCallback) {
                     Objects.requireNonNull(listFeaturesCallback);
-                    OnDeviceIntelligenceService.this.onListFeatures(callerUid,
-                            wrapListFeaturesCallback(listFeaturesCallback));
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onListFeatures,
+                                    OnDeviceIntelligenceService.this, callerUid,
+                                    wrapListFeaturesCallback(listFeaturesCallback)));
                 }
 
                 @Override
                 public void getFeature(int callerUid, int id, IFeatureCallback featureCallback) {
                     Objects.requireNonNull(featureCallback);
-                    OnDeviceIntelligenceService.this.onGetFeature(callerUid,
-                            id, wrapFeatureCallback(featureCallback));
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onGetFeature,
+                                    OnDeviceIntelligenceService.this, callerUid,
+                                    id, wrapFeatureCallback(featureCallback)));
                 }
 
 
@@ -147,9 +172,11 @@
                         IFeatureDetailsCallback featureDetailsCallback) {
                     Objects.requireNonNull(feature);
                     Objects.requireNonNull(featureDetailsCallback);
-
-                    OnDeviceIntelligenceService.this.onGetFeatureDetails(callerUid,
-                            feature, wrapFeatureDetailsCallback(featureDetailsCallback));
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onGetFeatureDetails,
+                                    OnDeviceIntelligenceService.this, callerUid,
+                                    feature, wrapFeatureDetailsCallback(featureDetailsCallback)));
                 }
 
                 @Override
@@ -163,10 +190,13 @@
                         transport = CancellationSignal.createTransport();
                         cancellationSignalFuture.complete(transport);
                     }
-                    OnDeviceIntelligenceService.this.onDownloadFeature(callerUid,
-                            feature,
-                            CancellationSignal.fromTransport(transport),
-                            wrapDownloadCallback(downloadCallback));
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onDownloadFeature,
+                                    OnDeviceIntelligenceService.this, callerUid,
+                                    feature,
+                                    CancellationSignal.fromTransport(transport),
+                                    wrapDownloadCallback(downloadCallback)));
                 }
 
                 @Override
@@ -174,9 +204,11 @@
                         AndroidFuture<ParcelFileDescriptor> future) {
                     Objects.requireNonNull(fileName);
                     Objects.requireNonNull(future);
-
-                    OnDeviceIntelligenceService.this.onGetReadOnlyFileDescriptor(fileName,
-                            future);
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onGetReadOnlyFileDescriptor,
+                                    OnDeviceIntelligenceService.this, fileName,
+                                    future));
                 }
 
                 @Override
@@ -184,13 +216,15 @@
                         Feature feature, RemoteCallback remoteCallback) {
                     Objects.requireNonNull(feature);
                     Objects.requireNonNull(remoteCallback);
-
-                    OnDeviceIntelligenceService.this.onGetReadOnlyFeatureFileDescriptorMap(
-                            feature, parcelFileDescriptorMap -> {
-                                Bundle bundle = new Bundle();
-                                parcelFileDescriptorMap.forEach(bundle::putParcelable);
-                                remoteCallback.sendResult(bundle);
-                            });
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onGetReadOnlyFeatureFileDescriptorMap,
+                                    OnDeviceIntelligenceService.this, feature,
+                                    parcelFileDescriptorMap -> {
+                                        Bundle bundle = new Bundle();
+                                        parcelFileDescriptorMap.forEach(bundle::putParcelable);
+                                        remoteCallback.sendResult(bundle);
+                                    }));
                 }
 
                 @Override
@@ -201,12 +235,18 @@
 
                 @Override
                 public void notifyInferenceServiceConnected() {
-                    OnDeviceIntelligenceService.this.onInferenceServiceConnected();
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onInferenceServiceConnected,
+                                    OnDeviceIntelligenceService.this));
                 }
 
                 @Override
                 public void notifyInferenceServiceDisconnected() {
-                    OnDeviceIntelligenceService.this.onInferenceServiceDisconnected();
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceIntelligenceService::onInferenceServiceDisconnected,
+                                    OnDeviceIntelligenceService.this));
                 }
             };
         }
@@ -222,7 +262,8 @@
      * @hide
      */
     @TestApi
-    public void onReady() {}
+    public void onReady() {
+    }
 
 
     /**
@@ -410,12 +451,16 @@
             Slog.v(TAG,
                     "onGetReadOnlyFileDescriptor: " + fileName + " under internal app storage.");
             File f = new File(getBaseContext().getFilesDir(), fileName);
+            if (!f.exists()) {
+                f = new File(fileName);
+            }
             ParcelFileDescriptor pfd = null;
             try {
                 pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
                 Slog.d(TAG, "Successfully opened a file with ParcelFileDescriptor.");
             } catch (FileNotFoundException e) {
                 Slog.e(TAG, "Cannot open file. No ParcelFileDescriptor returned.");
+                future.completeExceptionally(e);
             } finally {
                 future.complete(pfd);
                 if (pfd != null) {
diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
index 8237b20..d00485c 100644
--- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
+++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java
@@ -19,7 +19,10 @@
 import static android.app.ondeviceintelligence.OnDeviceIntelligenceManager.AUGMENT_REQUEST_CONTENT_BUNDLE_KEY;
 import static android.app.ondeviceintelligence.flags.Flags.FLAG_ENABLE_ON_DEVICE_INTELLIGENCE;
 
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
 import android.annotation.CallbackExecutor;
+import android.annotation.CallSuper;
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -48,6 +51,7 @@
 import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
+import android.os.Looper;
 import android.os.OutcomeReceiver;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
@@ -120,7 +124,20 @@
      */
     public static final String MODEL_UNLOADED_BUNDLE_KEY = "model_unloaded";
 
+    /**
+     * @hide
+     */
+    public static final String DEVICE_CONFIG_UPDATE_BUNDLE_KEY = "device_config_update";
+
     private IRemoteStorageService mRemoteStorageService;
+    private Handler mHandler;
+
+    @CallSuper
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mHandler = new Handler(Looper.getMainLooper(), null /* callback */, true /* async */);
+    }
 
     /**
      * @hide
@@ -147,11 +164,15 @@
                         transport = CancellationSignal.createTransport();
                         cancellationSignalFuture.complete(transport);
                     }
-                    OnDeviceSandboxedInferenceService.this.onTokenInfoRequest(callerUid,
-                            feature,
-                            request,
-                            CancellationSignal.fromTransport(transport),
-                            wrapTokenInfoCallback(tokenInfoCallback));
+
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceSandboxedInferenceService::onTokenInfoRequest,
+                                    OnDeviceSandboxedInferenceService.this,
+                                    callerUid, feature,
+                                    request,
+                                    CancellationSignal.fromTransport(transport),
+                                    wrapTokenInfoCallback(tokenInfoCallback)));
                 }
 
                 @Override
@@ -173,13 +194,18 @@
                         processingSignalTransport = ProcessingSignal.createTransport();
                         processingSignalFuture.complete(processingSignalTransport);
                     }
-                    OnDeviceSandboxedInferenceService.this.onProcessRequestStreaming(callerUid,
-                            feature,
-                            request,
-                            requestType,
-                            CancellationSignal.fromTransport(transport),
-                            ProcessingSignal.fromTransport(processingSignalTransport),
-                            wrapStreamingResponseCallback(callback));
+
+
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceSandboxedInferenceService::onProcessRequestStreaming,
+                                    OnDeviceSandboxedInferenceService.this, callerUid,
+                                    feature,
+                                    request,
+                                    requestType,
+                                    CancellationSignal.fromTransport(transport),
+                                    ProcessingSignal.fromTransport(processingSignalTransport),
+                                    wrapStreamingResponseCallback(callback)));
                 }
 
                 @Override
@@ -200,11 +226,14 @@
                         processingSignalTransport = ProcessingSignal.createTransport();
                         processingSignalFuture.complete(processingSignalTransport);
                     }
-                    OnDeviceSandboxedInferenceService.this.onProcessRequest(callerUid, feature,
-                            request, requestType,
-                            CancellationSignal.fromTransport(transport),
-                            ProcessingSignal.fromTransport(processingSignalTransport),
-                            wrapResponseCallback(callback));
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceSandboxedInferenceService::onProcessRequest,
+                                    OnDeviceSandboxedInferenceService.this, callerUid, feature,
+                                    request, requestType,
+                                    CancellationSignal.fromTransport(transport),
+                                    ProcessingSignal.fromTransport(processingSignalTransport),
+                                    wrapResponseCallback(callback)));
                 }
 
                 @Override
@@ -212,10 +241,11 @@
                         IProcessingUpdateStatusCallback callback) {
                     Objects.requireNonNull(processingState);
                     Objects.requireNonNull(callback);
-
-                    OnDeviceSandboxedInferenceService.this.onUpdateProcessingState(processingState,
-                            wrapOutcomeReceiver(callback)
-                    );
+                    mHandler.executeOrSendMessage(
+                            obtainMessage(
+                                    OnDeviceSandboxedInferenceService::onUpdateProcessingState,
+                                    OnDeviceSandboxedInferenceService.this, processingState,
+                                    wrapOutcomeReceiver(callback)));
                 }
             };
         }
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index d22d2a5..e338bcf 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -78,6 +78,7 @@
     private final InputDeviceIdentifier mIdentifier;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private final boolean mIsExternal;
+    @Source
     private final int mSources;
     private final int mKeyboardType;
     private final KeyCharacterMap mKeyCharacterMap;
@@ -359,6 +360,28 @@
      */
     public static final int SOURCE_ANY = 0xffffff00;
 
+    /** @hide */
+    @IntDef(flag = true, prefix = { "SOURCE_" }, value = {
+            SOURCE_UNKNOWN,
+            SOURCE_KEYBOARD,
+            SOURCE_DPAD,
+            SOURCE_GAMEPAD,
+            SOURCE_TOUCHSCREEN,
+            SOURCE_MOUSE,
+            SOURCE_STYLUS,
+            SOURCE_BLUETOOTH_STYLUS,
+            SOURCE_TRACKBALL,
+            SOURCE_MOUSE_RELATIVE,
+            SOURCE_TOUCHPAD,
+            SOURCE_TOUCH_NAVIGATION,
+            SOURCE_ROTARY_ENCODER,
+            SOURCE_JOYSTICK,
+            SOURCE_HDMI,
+            SOURCE_SENSOR,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface Source {}
+
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_X}.
      *
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 32e3f5a..1e5b097 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -189,6 +189,10 @@
         @Nullable
         private IBinder mActivityToken;
 
+        /** @see #setOtherActivityToken(IBinder) */
+        @Nullable
+        private IBinder mOtherActivityToken;
+
         @Nullable
         private TaskFragmentParentInfo mTaskFragmentParentInfo;
 
@@ -210,6 +214,7 @@
             mActivityToken = in.readStrongBinder();
             mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR);
             mSurfaceControl = in.readTypedObject(SurfaceControl.CREATOR);
+            mOtherActivityToken = in.readStrongBinder();
         }
 
         @Override
@@ -224,6 +229,7 @@
             dest.writeStrongBinder(mActivityToken);
             dest.writeTypedObject(mTaskFragmentParentInfo, flags);
             dest.writeTypedObject(mSurfaceControl, flags);
+            dest.writeStrongBinder(mOtherActivityToken);
         }
 
         /** The change is related to the TaskFragment created with this unique token. */
@@ -292,6 +298,21 @@
         }
 
         /**
+         * Token of another activity.
+         * <p>For {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}, it is the next activity (behind the
+         * reparented one) that fills the Task and occludes other activities. It will be the
+         * actual activity token if the activity belongs to the same process as the organizer.
+         * Otherwise, it is {@code null}.
+         *
+         * @hide
+         */
+        @NonNull
+        public Change setOtherActivityToken(@NonNull IBinder activityToken) {
+            mOtherActivityToken = requireNonNull(activityToken);
+            return this;
+        }
+
+        /**
          * Sets info of the parent Task of the embedded TaskFragment.
          * @see TaskFragmentParentInfo
          *
@@ -350,6 +371,12 @@
             return mActivityToken;
         }
 
+        /** @hide */
+        @Nullable
+        public IBinder getOtherActivityToken() {
+            return mOtherActivityToken;
+        }
+
         /**
          * Obtains the {@link TaskFragmentParentInfo} for this transaction.
          */
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 760c916..f94766e 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -78,3 +78,10 @@
     description: "Allows for additional windows tied to WindowDecoration to be layered between status bar and notification shade."
     bug: "316186265"
 }
+
+flag {
+    name: "enable_app_header_with_task_density"
+    namespace: "lse_desktop_experience"
+    description: "Matches the App Header density to that of the app window, instead of SysUI's"
+    bug: "332414819"
+}
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 4d1b87a..b4678f6 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -124,7 +124,10 @@
 
 flag {
     namespace: "windowing_sdk"
-    name: "pip_restore_to_overlay"
+    name: "fix_pip_restore_to_overlay"
     description: "Restore exit-pip activity back to ActivityEmbedding overlay"
     bug: "297887697"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 97ce96e..1dcd893 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -1908,12 +1908,16 @@
             } else if (parser.getName().equals("package")) {
                 final TypedArray sa = res.obtainAttributes(parser,
                         R.styleable.AndroidManifestQueriesPackage);
-                final String packageName = sa.getNonConfigurationString(
-                        R.styleable.AndroidManifestQueriesPackage_name, 0);
-                if (TextUtils.isEmpty(packageName)) {
-                    return input.error("Package name is missing from package tag.");
+                try {
+                    final String packageName = sa.getNonConfigurationString(
+                            R.styleable.AndroidManifestQueriesPackage_name, 0);
+                    if (TextUtils.isEmpty(packageName)) {
+                        return input.error("Package name is missing from package tag.");
+                    }
+                    pkg.addQueriesPackage(packageName.intern());
+                } finally {
+                    sa.recycle();
                 }
-                pkg.addQueriesPackage(packageName.intern());
             } else if (parser.getName().equals("provider")) {
                 final TypedArray sa = res.obtainAttributes(parser,
                         R.styleable.AndroidManifestQueriesProvider);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 80a7599..d9c40c3 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -483,4 +483,8 @@
         "libnativehelper",
         "libvintf",
     ],
+
+    required: [
+        "vintf",
+    ],
 }
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 8dc9d0a..7a4854b 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -32,6 +32,8 @@
 static jmethodID gHashMapPut;
 static jclass gLongClazz;
 static jmethodID gLongValueOf;
+static jclass gVintfObjectClazz;
+static jmethodID gRunCommand;
 
 namespace android {
 
@@ -47,6 +49,56 @@
 using vintf::Vndk;
 using vintf::CheckFlags::ENABLE_ALL_CHECKS;
 
+// Instead of VintfObject::GetXxx(), we construct
+// HalManifest/CompatibilityMatrix objects by calling `vintf` through
+// UiAutomation.executeShellCommand() so that the commands are executed
+// using shell identity. Otherwise, we would need to allow "apps" to access
+// files like apex-info-list.xml which we don't want to open to apps.
+// This is okay because VintfObject is @TestApi and only used in CTS tests.
+
+static std::string runCmd(JNIEnv* env, const char* cmd) {
+    jstring jstr = (jstring)env->CallStaticObjectMethod(gVintfObjectClazz, gRunCommand,
+                                                        env->NewStringUTF(cmd));
+    std::string output;
+    if (jstr) {
+        auto cstr = env->GetStringUTFChars(jstr, nullptr);
+        output = std::string(cstr);
+        env->ReleaseStringUTFChars(jstr, cstr);
+    } else {
+        LOG(WARNING) << "Failed to run " << cmd;
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+    return output;
+}
+
+template <typename T>
+static std::shared_ptr<const T> fromXml(const std::string& content) {
+    std::shared_ptr<T> object = std::make_unique<T>();
+    std::string error;
+    if (fromXml(object.get(), content, &error)) {
+        return object;
+    }
+    LOG(WARNING) << "Unabled to parse: " << error;
+    return nullptr;
+}
+
+static std::shared_ptr<const HalManifest> getDeviceHalManifest(JNIEnv* env) {
+    return fromXml<HalManifest>(runCmd(env, "vintf dm"));
+}
+
+static std::shared_ptr<const HalManifest> getFrameworkHalManifest(JNIEnv* env) {
+    return fromXml<HalManifest>(runCmd(env, "vintf fm"));
+}
+
+static std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(JNIEnv* env) {
+    return fromXml<CompatibilityMatrix>(runCmd(env, "vintf dcm"));
+}
+
+static std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(JNIEnv* env) {
+    return fromXml<CompatibilityMatrix>(runCmd(env, "vintf fcm"));
+}
+
 template<typename V>
 static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
     size_t i;
@@ -83,12 +135,10 @@
 {
     std::vector<std::string> cStrings;
 
-    tryAddSchema(VintfObject::GetDeviceHalManifest(), "device manifest", &cStrings);
-    tryAddSchema(VintfObject::GetFrameworkHalManifest(), "framework manifest", &cStrings);
-    tryAddSchema(VintfObject::GetDeviceCompatibilityMatrix(), "device compatibility matrix",
-                 &cStrings);
-    tryAddSchema(VintfObject::GetFrameworkCompatibilityMatrix(), "framework compatibility matrix",
-                 &cStrings);
+    tryAddSchema(getDeviceHalManifest(env), "device manifest", &cStrings);
+    tryAddSchema(getFrameworkHalManifest(env), "framework manifest", &cStrings);
+    tryAddSchema(getDeviceCompatibilityMatrix(env), "device compatibility matrix", &cStrings);
+    tryAddSchema(getFrameworkCompatibilityMatrix(env), "framework compatibility matrix", &cStrings);
 
     return toJavaStringArray(env, cStrings);
 }
@@ -108,15 +158,13 @@
 
 static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
     std::set<std::string> halNames;
-    tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(),
-            "device manifest", &halNames);
-    tryAddHalNamesAndVersions(VintfObject::GetFrameworkHalManifest(),
-            "framework manifest", &halNames);
+    tryAddHalNamesAndVersions(getDeviceHalManifest(env), "device manifest", &halNames);
+    tryAddHalNamesAndVersions(getFrameworkHalManifest(env), "framework manifest", &halNames);
     return toJavaStringArray(env, halNames);
 }
 
 static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {
-    std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+    std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env);
     if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) {
         LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest";
         return nullptr;
@@ -126,8 +174,7 @@
 }
 
 static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jclass) {
-    std::shared_ptr<const CompatibilityMatrix> matrix =
-            VintfObject::GetFrameworkCompatibilityMatrix();
+    std::shared_ptr<const CompatibilityMatrix> matrix = getFrameworkCompatibilityMatrix(env);
     if (matrix == nullptr || matrix->type() != SchemaType::FRAMEWORK) {
         jniThrowRuntimeException(env, "Cannot get framework compatibility matrix");
         return nullptr;
@@ -148,7 +195,7 @@
 }
 
 static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {
-    std::shared_ptr<const HalManifest> manifest = VintfObject::GetFrameworkHalManifest();
+    std::shared_ptr<const HalManifest> manifest = getFrameworkHalManifest(env);
     if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) {
         LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest";
         return nullptr;
@@ -163,7 +210,7 @@
 }
 
 static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) {
-    std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+    std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env);
     if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) {
         return nullptr;
     }
@@ -188,19 +235,20 @@
 
 const char* const kVintfObjectPathName = "android/os/VintfObject";
 
-int register_android_os_VintfObject(JNIEnv* env)
-{
-
+int register_android_os_VintfObject(JNIEnv* env) {
     gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));
     gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap"));
     gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
-    gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
-            "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+    gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz, "put",
+                                   "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
     gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long"));
     gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;");
+    gVintfObjectClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kVintfObjectPathName));
+    gRunCommand = GetStaticMethodIDOrDie(env, gVintfObjectClazz, "runShellCommand",
+                                         "(Ljava/lang/String;)Ljava/lang/String;");
 
     return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
-            NELEM(gVintfObjectMethods));
+                                NELEM(gVintfObjectMethods));
 }
 
 extern int register_android_os_VintfRuntimeInfo(JNIEnv* env);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5bd2033..0676f72 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4723,6 +4723,8 @@
     <!-- The broadcast intent name for notifying when the on-device model has been unloaded  -->
     <string name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" translatable="false"></string>
 
+    <!-- The DeviceConfig namespace for the default system on-device sandboxed inference service. -->
+    <string name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" translatable="false"></string>
 
     <!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent for
          wearable sensing. -->
@@ -6951,9 +6953,6 @@
         an app is not changed during subsequent reboots.  -->
     <bool name="config_stopSystemPackagesByDefault">true</bool>
 
-    <!-- Whether to show weather on the lock screen by default. -->
-    <bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
-
     <!-- Whether we should persist the brightness value in nits for the default display even if
          the underlying display device changes. -->
     <bool name="config_persistBrightnessNitsForDefaultDisplay">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 28678c1..2da5e9a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -6491,9 +6491,9 @@
     <!-- Fingerprint dangling notification title -->
     <string name="fingerprint_dangling_notification_title">Set up Fingerprint Unlock again</string>
     <!-- Fingerprint dangling notification content for only 1 fingerprint deleted -->
-    <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted to improve performance</string>
+    <string name="fingerprint_dangling_notification_msg_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted</string>
     <!-- Fingerprint dangling notification content for more than 1 fingerprints deleted -->
-    <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted to improve performance</string>
+    <string name="fingerprint_dangling_notification_msg_2"><xliff:g id="fingerprint">%1$s</xliff:g> and <xliff:g id="fingerprint">%2$s</xliff:g> weren\'t working well and were deleted</string>
     <!-- Fingerprint dangling notification content for only 1 fingerprint deleted and no fingerprint left-->
     <string name="fingerprint_dangling_notification_msg_all_deleted_1"><xliff:g id="fingerprint">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint.</string>
     <!-- Fingerprint dangling notification content for more than 1 fingerprints deleted and no fingerprint left  -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index acd3b37..6c6764a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3947,6 +3947,7 @@
   <java-symbol type="string" name="config_defaultOnDeviceSandboxedInferenceService" />
   <java-symbol type="string" name="config_onDeviceIntelligenceModelLoadedBroadcastKey" />
   <java-symbol type="string" name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" />
+  <java-symbol type="string" name="config_defaultOnDeviceIntelligenceDeviceConfigNamespace" />
   <java-symbol type="string" name="config_retailDemoPackage" />
   <java-symbol type="string" name="config_retailDemoPackageSignature" />
 
@@ -5224,9 +5225,6 @@
   <java-symbol type="bool" name="config_hotspotNetworksEnabledForService"/>
   <java-symbol type="bool" name="config_knownNetworksEnabledForService"/>
 
-  <!-- Whether to show weather on the lockscreen by default. -->
-  <java-symbol type="bool" name="config_lockscreenWeatherEnabledByDefault" />
-
   <!-- For keyboard notification -->
   <java-symbol type="string" name="keyboard_layout_notification_selected_title"/>
   <java-symbol type="string" name="keyboard_layout_notification_one_selected_message"/>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
index 1fbaeea..29936cc 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java
@@ -33,7 +33,9 @@
 import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_RIGHT;
 import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_TOP;
 
-import android.annotation.DimenRes;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityThread;
@@ -53,9 +55,11 @@
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
+import android.view.VelocityTracker;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowlessWindowManager;
+import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.window.InputTransferToken;
@@ -97,6 +101,16 @@
     @VisibleForTesting
     static final int DEFAULT_DIVIDER_WIDTH_DP = 24;
 
+    @VisibleForTesting
+    static final PathInterpolator FLING_ANIMATION_INTERPOLATOR =
+            new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+    @VisibleForTesting
+    static final int FLING_ANIMATION_DURATION = 250;
+    @VisibleForTesting
+    static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
+    @VisibleForTesting
+    static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
+
     private final int mTaskId;
 
     @NonNull
@@ -109,6 +123,14 @@
     private final Executor mCallbackExecutor;
 
     /**
+     * The VelocityTracker of the divider, used to track the dragging velocity. This field is
+     * {@code null} until dragging starts.
+     */
+    @GuardedBy("mLock")
+    @Nullable
+    VelocityTracker mVelocityTracker;
+
+    /**
      * The {@link Properties} of the divider. This field is {@code null} when no divider should be
      * drawn, e.g. when the split doesn't have {@link DividerAttributes} or when the decor surface
      * is not available.
@@ -370,13 +392,11 @@
                 applicationContext.getResources().getDisplayMetrics());
     }
 
-    private static int getDimensionDp(@DimenRes int resId) {
-        final Context context = ActivityThread.currentActivityThread().getApplication();
-        final int px = context.getResources().getDimensionPixelSize(resId);
-        return (int) TypedValue.convertPixelsToDimension(
-                COMPLEX_UNIT_DIP,
-                px,
-                context.getResources().getDisplayMetrics());
+    private static float getDisplayDensity() {
+        // TODO(b/329193115) support divider on secondary display
+        final Context applicationContext =
+                ActivityThread.currentActivityThread().getApplication();
+        return applicationContext.getResources().getDisplayMetrics().density;
     }
 
     /**
@@ -487,24 +507,27 @@
     @Override
     public boolean onTouch(@NonNull View view, @NonNull MotionEvent event) {
         synchronized (mLock) {
-            final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
-            mDividerPosition = calculateDividerPosition(
-                    event, taskBounds, mRenderer.mDividerWidthPx, mProperties.mDividerAttributes,
-                    mProperties.mIsVerticalSplit, calculateMinPosition(), calculateMaxPosition());
-            mRenderer.setDividerPosition(mDividerPosition);
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    onStartDragging();
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    onFinishDragging();
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    onDrag();
-                    break;
-                default:
-                    break;
+            if (mProperties != null && mRenderer != null) {
+                final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
+                mDividerPosition = calculateDividerPosition(
+                        event, taskBounds, mRenderer.mDividerWidthPx,
+                        mProperties.mDividerAttributes, mProperties.mIsVerticalSplit,
+                        calculateMinPosition(), calculateMaxPosition());
+                mRenderer.setDividerPosition(mDividerPosition);
+                switch (event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        onStartDragging(event);
+                        break;
+                    case MotionEvent.ACTION_UP:
+                    case MotionEvent.ACTION_CANCEL:
+                        onFinishDragging(event);
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        onDrag(event);
+                        break;
+                    default:
+                        break;
+                }
             }
         }
 
@@ -514,7 +537,10 @@
     }
 
     @GuardedBy("mLock")
-    private void onStartDragging() {
+    private void onStartDragging(@NonNull MotionEvent event) {
+        mVelocityTracker = VelocityTracker.obtain();
+        mVelocityTracker.addMovement(event);
+
         mRenderer.mIsDragging = true;
         mRenderer.mDragHandle.setPressed(mRenderer.mIsDragging);
         mRenderer.updateSurface();
@@ -536,16 +562,81 @@
     }
 
     @GuardedBy("mLock")
-    private void onDrag() {
+    private void onDrag(@NonNull MotionEvent event) {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(event);
+        }
         mRenderer.updateSurface();
     }
 
     @GuardedBy("mLock")
-    private void onFinishDragging() {
-        mDividerPosition = adjustDividerPositionForSnapPoints(mDividerPosition);
-        mRenderer.setDividerPosition(mDividerPosition);
-        mRenderer.updateSurface();
+    private void onFinishDragging(@NonNull MotionEvent event) {
+        float velocity = 0.0f;
+        if (mVelocityTracker != null) {
+            mVelocityTracker.addMovement(event);
+            mVelocityTracker.computeCurrentVelocity(1000 /* units */);
+            velocity = mProperties.mIsVerticalSplit
+                    ? mVelocityTracker.getXVelocity()
+                    : mVelocityTracker.getYVelocity();
+            mVelocityTracker.recycle();
+        }
 
+        final int prevDividerPosition = mDividerPosition;
+        mDividerPosition = dividerPositionForSnapPoints(mDividerPosition, velocity);
+        if (mDividerPosition != prevDividerPosition) {
+            ValueAnimator animator = getFlingAnimator(prevDividerPosition, mDividerPosition);
+            animator.start();
+        } else {
+            onDraggingEnd();
+        }
+    }
+
+    @GuardedBy("mLock")
+    @NonNull
+    @VisibleForTesting
+    ValueAnimator getFlingAnimator(int prevDividerPosition, int snappedDividerPosition) {
+        final ValueAnimator animator =
+                getValueAnimator(prevDividerPosition, snappedDividerPosition);
+        animator.addUpdateListener(animation -> {
+            synchronized (mLock) {
+                updateDividerPosition((int) animation.getAnimatedValue());
+            }
+        });
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                synchronized (mLock) {
+                    onDraggingEnd();
+                }
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                synchronized (mLock) {
+                    onDraggingEnd();
+                }
+            }
+        });
+        return animator;
+    }
+
+    @VisibleForTesting
+    static ValueAnimator getValueAnimator(int prevDividerPosition, int snappedDividerPosition) {
+        ValueAnimator animator = ValueAnimator
+                .ofInt(prevDividerPosition, snappedDividerPosition)
+                .setDuration(FLING_ANIMATION_DURATION);
+        animator.setInterpolator(FLING_ANIMATION_INTERPOLATOR);
+        return animator;
+    }
+
+    @GuardedBy("mLock")
+    private void updateDividerPosition(int position) {
+        mRenderer.setDividerPosition(position);
+        mRenderer.updateSurface();
+    }
+
+    @GuardedBy("mLock")
+    private void onDraggingEnd() {
         // Veil visibility change should be applied together with the surface boost transaction in
         // the wct.
         final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -570,38 +661,78 @@
 
     /**
      * Returns the divider position adjusted for the min max ratio and fullscreen expansion.
-     *
-     * If the dragging position is above the {@link DividerAttributes#getPrimaryMaxRatio()} or below
-     * {@link DividerAttributes#getPrimaryMinRatio()} and
-     * {@link DividerAttributes#isDraggingToFullscreenAllowed} is {@code true}, the system will
-     * choose a snap algorithm to adjust the ending position to either fully expand one container or
-     * move the divider back to the specified min/max ratio.
-     *
-     * TODO(b/327067596) implement snap algorithm
-     *
      * The adjusted divider position is in the range of [minPosition, maxPosition] for a split, 0
      * for expanded right (bottom) container, or task width (height) minus the divider width for
      * expanded left (top) container.
      */
     @GuardedBy("mLock")
-    private int adjustDividerPositionForSnapPoints(int dividerPosition) {
+    private int dividerPositionForSnapPoints(int dividerPosition, float velocity) {
         final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds();
         final int minPosition = calculateMinPosition();
         final int maxPosition = calculateMaxPosition();
         final int fullyExpandedPosition = mProperties.mIsVerticalSplit
                 ? taskBounds.right - mRenderer.mDividerWidthPx
                 : taskBounds.bottom - mRenderer.mDividerWidthPx;
+
         if (isDraggingToFullscreenAllowed(mProperties.mDividerAttributes)) {
-            if (dividerPosition < minPosition) {
-                return 0;
-            }
-            if (dividerPosition > maxPosition) {
-                return fullyExpandedPosition;
-            }
+            final float displayDensity = getDisplayDensity();
+            return dividerPositionWithDraggingToFullscreenAllowed(
+                    dividerPosition,
+                    minPosition,
+                    maxPosition,
+                    fullyExpandedPosition,
+                    velocity,
+                    displayDensity);
         }
         return Math.clamp(dividerPosition, minPosition, maxPosition);
     }
 
+    /**
+     * Returns the divider position given a set of position options. A snap algorithm is used to
+     * adjust the ending position to either fully expand one container or move the divider back to
+     * the specified min/max ratio depending on the dragging velocity.
+     */
+    @VisibleForTesting
+    static int dividerPositionWithDraggingToFullscreenAllowed(int dividerPosition, int minPosition,
+            int maxPosition, int fullyExpandedPosition, float velocity, float displayDensity) {
+        final float minDismissVelocityPxPerSecond =
+                MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity;
+        final float minFlingVelocityPxPerSecond =
+                MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity;
+        if (dividerPosition < minPosition && velocity < -minDismissVelocityPxPerSecond) {
+            return 0;
+        }
+        if (dividerPosition > maxPosition && velocity > minDismissVelocityPxPerSecond) {
+            return fullyExpandedPosition;
+        }
+        if (Math.abs(velocity) < minFlingVelocityPxPerSecond) {
+            if (dividerPosition >= minPosition && dividerPosition <= maxPosition) {
+                return dividerPosition;
+            }
+            int[] possiblePositions = {0, minPosition, maxPosition, fullyExpandedPosition};
+            return snap(dividerPosition, possiblePositions);
+        }
+        if (velocity < 0) {
+            return 0;
+        } else {
+            return fullyExpandedPosition;
+        }
+    }
+
+    /** Calculates the snapped divider position based on the possible positions and distance. */
+    private static int snap(int dividerPosition, int[] possiblePositions) {
+        int snappedPosition = dividerPosition;
+        float minDistance = Float.MAX_VALUE;
+        for (int position : possiblePositions) {
+            float distance = Math.abs(dividerPosition - position);
+            if (distance < minDistance) {
+                snappedPosition = position;
+                minDistance = distance;
+            }
+        }
+        return snappedPosition;
+    }
+
     private static void setDecorSurfaceBoosted(
             @NonNull WindowContainerTransaction wct,
             @Nullable IBinder decorSurfaceOwner,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 13c2d1f..b764b6e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -50,6 +50,7 @@
 import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
 import static androidx.window.extensions.embedding.SplitPresenter.sanitizeBounds;
 import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit;
+import static androidx.window.extensions.embedding.TaskFragmentContainer.OverlayContainerRestoreParams;
 
 import android.annotation.CallbackExecutor;
 import android.app.Activity;
@@ -133,6 +134,13 @@
     private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
 
     /**
+     * Stores the token of the associated Activity that maps to the
+     * {@link OverlayContainerRestoreParams} of the most recent created overlay container.
+     */
+    @GuardedBy("mLock")
+    final ArrayMap<IBinder, OverlayContainerRestoreParams> mOverlayRestoreParams = new ArrayMap<>();
+
+    /**
      * A developer-defined {@link SplitAttributes} calculator to compute the current
      * {@link SplitAttributes} with the current device and window states.
      * It is registered via {@link #setSplitAttributesCalculator(Function)}
@@ -686,11 +694,20 @@
                                 exception);
                         break;
                     case TYPE_ACTIVITY_REPARENTED_TO_TASK:
+                        final IBinder candidateAssociatedActToken, lastOverlayToken;
+                        if (Flags.fixPipRestoreToOverlay()) {
+                            candidateAssociatedActToken = change.getOtherActivityToken();
+                            lastOverlayToken = change.getTaskFragmentToken();
+                        } else {
+                            candidateAssociatedActToken = lastOverlayToken = null;
+                        }
                         onActivityReparentedToTask(
                                 wct,
                                 taskId,
                                 change.getActivityIntent(),
-                                change.getActivityToken());
+                                change.getActivityToken(),
+                                candidateAssociatedActToken,
+                                lastOverlayToken);
                         break;
                     default:
                         throw new IllegalArgumentException(
@@ -917,11 +934,28 @@
      *                       different process, the server will generate a temporary token that
      *                       the organizer can use to reparent the activity through
      *                       {@link WindowContainerTransaction} if needed.
+     * @param candidateAssociatedActToken The token of the candidate associated-activity.
+     * @param lastOverlayToken The last parent overlay container token.
      */
     @VisibleForTesting
     @GuardedBy("mLock")
     void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
-            int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {
+            int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken,
+            @Nullable IBinder candidateAssociatedActToken, @Nullable IBinder lastOverlayToken) {
+        // Reparent the activity to an overlay container if needed.
+        final OverlayContainerRestoreParams params = getOverlayContainerRestoreParams(
+                candidateAssociatedActToken, lastOverlayToken);
+        if (params != null) {
+            final Activity associatedActivity = getActivity(candidateAssociatedActToken);
+            final TaskFragmentContainer targetContainer = createOrUpdateOverlayTaskFragmentIfNeeded(
+                    wct, params.mOptions, params.mIntent, associatedActivity);
+            if (targetContainer != null) {
+                wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(),
+                        activityToken);
+                return;
+            }
+        }
+
         // If the activity belongs to the current app process, we treat it as a new activity
         // launch.
         final Activity activity = getActivity(activityToken);
@@ -966,6 +1000,43 @@
     }
 
     /**
+     * Returns the {@link OverlayContainerRestoreParams} that stored last time the {@code
+     * associatedActivityToken} associated with and only if data matches the {@code overlayToken}.
+     * Otherwise, return {@code null}.
+     */
+    @VisibleForTesting
+    @GuardedBy("mLock")
+    @Nullable
+    OverlayContainerRestoreParams getOverlayContainerRestoreParams(
+            @Nullable IBinder associatedActivityToken, @Nullable IBinder overlayToken) {
+        if (!Flags.fixPipRestoreToOverlay()) {
+            return null;
+        }
+
+        if (associatedActivityToken == null || overlayToken == null) {
+            return null;
+        }
+
+        final TaskFragmentContainer.OverlayContainerRestoreParams params =
+                mOverlayRestoreParams.get(associatedActivityToken);
+        if (params == null) {
+            return null;
+        }
+
+        if (params.mOverlayToken != overlayToken) {
+            // Not the same overlay container, no need to restore.
+            return null;
+        }
+
+        final Activity associatedActivity = getActivity(associatedActivityToken);
+        if (associatedActivity == null || associatedActivity.isFinishing()) {
+            return null;
+        }
+
+        return params;
+    }
+
+    /**
      * Called when the {@link WindowContainerTransaction} created with
      * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
      *
@@ -1433,6 +1504,8 @@
         for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
             mTaskContainers.valueAt(i).onFinishingActivityPaused(wct, activityToken);
         }
+
+        mOverlayRestoreParams.remove(activity.getActivityToken());
         updateCallbackIfNecessary();
     }
 
@@ -1450,6 +1523,8 @@
         for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
             mTaskContainers.valueAt(i).onActivityDestroyed(wct, activityToken);
         }
+
+        mOverlayRestoreParams.remove(activity.getActivityToken());
         // We didn't trigger the callback if there were any pending appeared activities, so check
         // again after the pending is removed.
         updateCallbackIfNecessary();
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 4825543..d0b6a01 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -36,6 +36,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -274,6 +275,15 @@
             addPendingAppearedActivity(pendingAppearedActivity);
         }
         mPendingAppearedIntent = pendingAppearedIntent;
+
+        // Save the information necessary for restoring the overlay when needed.
+        if (Flags.fixPipRestoreToOverlay() && overlayTag != null && pendingAppearedIntent != null
+                && associatedActivity != null && !associatedActivity.isFinishing()) {
+            final IBinder associatedActivityToken = associatedActivity.getActivityToken();
+            final OverlayContainerRestoreParams params = new OverlayContainerRestoreParams(mToken,
+                    launchOptions, pendingAppearedIntent);
+            mController.mOverlayRestoreParams.put(associatedActivityToken, params);
+        }
     }
 
     /**
@@ -1105,4 +1115,25 @@
         }
         return sb.append("]").toString();
     }
+
+    static class OverlayContainerRestoreParams {
+        /** The token of the overlay container */
+        @NonNull
+        final IBinder mOverlayToken;
+
+        /** The launch options to create this container. */
+        @NonNull
+        final Bundle mOptions;
+
+        /** The Intent that used to be started in the overlay container. */
+        @NonNull
+        final Intent mIntent;
+
+        OverlayContainerRestoreParams(@NonNull IBinder overlayToken, @NonNull Bundle options,
+                @NonNull Intent intent) {
+            mOverlayToken = overlayToken;
+            mOptions = options;
+            mIntent = intent;
+        }
+    }
 }
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
index b0a45e2..746607c 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/DividerPresenterTest.java
@@ -19,6 +19,10 @@
 import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_OR_MOVE_TASK_FRAGMENT_DECOR_SURFACE;
 import static android.window.TaskFragmentOperation.OP_TYPE_REMOVE_TASK_FRAGMENT_DECOR_SURFACE;
 
+import static androidx.window.extensions.embedding.DividerPresenter.FLING_ANIMATION_DURATION;
+import static androidx.window.extensions.embedding.DividerPresenter.FLING_ANIMATION_INTERPOLATOR;
+import static androidx.window.extensions.embedding.DividerPresenter.MIN_DISMISS_VELOCITY_DP_PER_SECOND;
+import static androidx.window.extensions.embedding.DividerPresenter.MIN_FLING_VELOCITY_DP_PER_SECOND;
 import static androidx.window.extensions.embedding.DividerPresenter.getBoundsOffsetForDivider;
 import static androidx.window.extensions.embedding.DividerPresenter.getInitialDividerPosition;
 import static androidx.window.extensions.embedding.SplitPresenter.CONTAINER_POSITION_BOTTOM;
@@ -35,6 +39,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.content.res.Configuration;
 import android.graphics.Color;
@@ -637,6 +642,105 @@
                 DividerPresenter.getContainerBackgroundColor(container, defaultColor));
     }
 
+    @Test
+    public void testGetValueAnimator() {
+        ValueAnimator animator =
+                DividerPresenter.getValueAnimator(
+                        375 /* prevDividerPosition */,
+                        500 /* snappedDividerPosition */);
+
+        assertEquals(animator.getDuration(), FLING_ANIMATION_DURATION);
+        assertEquals(animator.getInterpolator(), FLING_ANIMATION_INTERPOLATOR);
+    }
+
+    @Test
+    public void testDividerPositionWithDraggingToFullscreenAllowed() {
+        final float displayDensity = 600F;
+        final float dismissVelocity = MIN_DISMISS_VELOCITY_DP_PER_SECOND * displayDensity + 10f;
+        final float nonFlingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity - 10f;
+        final float flingVelocity = MIN_FLING_VELOCITY_DP_PER_SECOND * displayDensity + 10f;
+
+        // Divider position is less than minPosition and the velocity is enough to be dismissed
+        assertEquals(
+                0, // Closed position
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        10 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        -dismissVelocity,
+                        displayDensity));
+
+        // Divider position is greater than maxPosition and the velocity is enough to be dismissed
+        assertEquals(
+                1200, // Fully expanded position
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        1000 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        dismissVelocity,
+                        displayDensity));
+
+        // Divider position is returned when the velocity is not fast enough for fling and is in
+        // between minPosition and maxPosition
+        assertEquals(
+                500, // dividerPosition is not snapped
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        500 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        nonFlingVelocity,
+                        displayDensity));
+
+        // Divider position is snapped when the velocity is not fast enough for fling and larger
+        // than maxPosition
+        assertEquals(
+                900, // Closest position is maxPosition
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        950 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        nonFlingVelocity,
+                        displayDensity));
+
+        // Divider position is snapped when the velocity is not fast enough for fling and smaller
+        // than minPosition
+        assertEquals(
+                30, // Closest position is minPosition
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        20 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        nonFlingVelocity,
+                        displayDensity));
+
+        // Divider position is greater than minPosition and the velocity is enough for fling
+        assertEquals(
+                0, // Closed position
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        50 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        -flingVelocity,
+                        displayDensity));
+
+        // Divider position is less than maxPosition and the velocity is enough for fling
+        assertEquals(
+                1200, // Fully expanded position
+                DividerPresenter.dividerPositionWithDraggingToFullscreenAllowed(
+                        800 /* dividerPosition */,
+                        30 /* minPosition */,
+                        900 /* maxPosition */,
+                        1200 /* fullyExpandedPosition */,
+                        flingVelocity,
+                        displayDensity));
+    }
+
     private TaskFragmentContainer createMockTaskFragmentContainer(
             @NonNull IBinder token, @NonNull Rect bounds) {
         final TaskFragmentContainer container = mock(TaskFragmentContainer.class);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 9ebcb759..f322257 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -836,6 +836,30 @@
                 any());
     }
 
+    @Test
+    public void testOnActivityReparentedToTask_overlayRestoration() {
+        mSetFlagRule.enableFlags(Flags.FLAG_FIX_PIP_RESTORE_TO_OVERLAY);
+
+        // Prepares and mock the data necessary for the test.
+        final IBinder activityToken = mActivity.getActivityToken();
+        final Intent intent = new Intent();
+        final IBinder fillTaskActivityToken = new Binder();
+        final IBinder lastOverlayToken = new Binder();
+        final TaskFragmentContainer overlayContainer = mSplitController.newContainer(intent,
+                mActivity, TASK_ID);
+        final TaskFragmentContainer.OverlayContainerRestoreParams params = mock(
+                TaskFragmentContainer.OverlayContainerRestoreParams.class);
+        doReturn(params).when(mSplitController).getOverlayContainerRestoreParams(any(), any());
+        doReturn(overlayContainer).when(mSplitController).createOrUpdateOverlayTaskFragmentIfNeeded(
+                any(), any(), any(), any());
+
+        // Verify the activity should be reparented to the overlay container.
+        mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken,
+                fillTaskActivityToken, lastOverlayToken);
+        verify(mTransaction).reparentActivityToTaskFragment(
+                eq(overlayContainer.getTaskFragmentToken()), eq(activityToken));
+    }
+
     /**
      * A simplified version of {@link SplitController#createOrUpdateOverlayTaskFragmentIfNeeded}
      */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 7d86ec2..35353db 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -397,7 +397,8 @@
     @Test
     public void testOnActivityReparentedToTask_sameProcess() {
         mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, new Intent(),
-                mActivity.getActivityToken());
+                mActivity.getActivityToken(), null /* fillTaskActivityToken */,
+                null /* lastOverlayToken */);
 
         // Treated as on activity created, but allow to split as primary.
         verify(mSplitController).resolveActivityToContainer(mTransaction,
@@ -413,7 +414,8 @@
         final IBinder activityToken = new Binder();
         final Intent intent = new Intent();
 
-        mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken);
+        mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken,
+                null /* fillTaskActivityToken */, null /* lastOverlayToken */);
 
         // Treated as starting new intent
         verify(mSplitController, never()).resolveActivityToContainer(any(), any(), anyBoolean());
@@ -1210,7 +1212,7 @@
         mSplitController.onTransactionReady(transaction);
 
         verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
-                eq(activityToken));
+                eq(activityToken), any(), any());
         verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
                 anyInt(), anyBoolean());
     }
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
index 8487e379..9e1440d 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
@@ -218,11 +218,10 @@
                 insets = Insets.of(10, 20, 5, 15),
                 windowBounds = Rect(0, 0, 1800, 2600)
             )
-        val bubbleBarBounds = Rect(1700, 2500, 1780, 2600)
 
         positioner.setShowingInBubbleBar(true)
         positioner.update(deviceConfig)
-        positioner.bubbleBarBounds = bubbleBarBounds
+        positioner.bubbleBarTopOnScreen = 2500
 
         val spaceBetweenTopInsetAndBubbleBarInLandscape = 1680
         val expandedViewVerticalSpacing =
@@ -246,10 +245,9 @@
                 insets = Insets.of(10, 20, 5, 15),
                 windowBounds = Rect(0, 0, screenWidth, 2600)
             )
-        val bubbleBarBounds = Rect(100, 2500, 280, 2550)
         positioner.setShowingInBubbleBar(true)
         positioner.update(deviceConfig)
-        positioner.bubbleBarBounds = bubbleBarBounds
+        positioner.bubbleBarTopOnScreen = 2500
 
         val spaceBetweenTopInsetAndBubbleBarInLandscape = 180
         val expandedViewSpacing =
@@ -597,16 +595,19 @@
 
     private fun testGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) {
         positioner.setShowingInBubbleBar(true)
+        val windowBounds = Rect(0, 0, 2000, 2600)
+        val insets = Insets.of(10, 20, 5, 15)
         val deviceConfig =
             defaultDeviceConfig.copy(
                 isLargeScreen = true,
                 isLandscape = true,
-                insets = Insets.of(10, 20, 5, 15),
-                windowBounds = Rect(0, 0, 2000, 2600)
+                insets = insets,
+                windowBounds = windowBounds
             )
         positioner.update(deviceConfig)
 
-        positioner.bubbleBarBounds = getBubbleBarBounds(onLeft, deviceConfig)
+        val bubbleBarHeight = 100
+        positioner.bubbleBarTopOnScreen = windowBounds.bottom - insets.bottom - bubbleBarHeight
 
         val expandedViewPadding =
             context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding)
@@ -624,7 +625,7 @@
             left = right - positioner.getExpandedViewWidthForBubbleBar(isOverflow)
         }
         // Above the bubble bar
-        val bottom = positioner.bubbleBarBounds.top - expandedViewPadding
+        val bottom = positioner.bubbleBarTopOnScreen - expandedViewPadding
         // Calculate right and top based on size
         val top = bottom - positioner.getExpandedViewHeightForBubbleBar(isOverflow)
         val expectedBounds = Rect(left, top, right, bottom)
@@ -666,21 +667,4 @@
                 positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
             return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent
         }
-
-    private fun getBubbleBarBounds(onLeft: Boolean, deviceConfig: DeviceConfig): Rect {
-        val width = 200
-        val height = 100
-        val bottom = deviceConfig.windowBounds.bottom - deviceConfig.insets.bottom
-        val top = bottom - height
-        val left: Int
-        val right: Int
-        if (onLeft) {
-            left = deviceConfig.insets.left
-            right = left + width
-        } else {
-            right = deviceConfig.windowBounds.right - deviceConfig.insets.right
-            left = right - width
-        }
-        return Rect(left, top, right, bottom)
-    }
 }
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
index 0764141..12d1927 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
@@ -53,7 +53,6 @@
         const val SCREEN_WIDTH = 2000
         const val SCREEN_HEIGHT = 1000
 
-        const val BUBBLE_BAR_WIDTH = 100
         const val BUBBLE_BAR_HEIGHT = 50
     }
 
@@ -84,14 +83,8 @@
                 insets = Insets.of(10, 20, 30, 40)
             )
         positioner.update(deviceConfig)
-        positioner.bubbleBarBounds =
-            Rect(
-                SCREEN_WIDTH - deviceConfig.insets.right - BUBBLE_BAR_WIDTH,
-                SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT,
-                SCREEN_WIDTH - deviceConfig.insets.right,
-                SCREEN_HEIGHT - deviceConfig.insets.bottom
-            )
-
+        positioner.bubbleBarTopOnScreen =
+            SCREEN_HEIGHT - deviceConfig.insets.bottom - BUBBLE_BAR_HEIGHT
         controller = BubbleExpandedViewPinController(context, container, positioner)
         testListener = TestLocationChangeListener()
         controller.setListener(testListener)
@@ -247,9 +240,10 @@
     private val dropTargetView: View?
         get() = container.findViewById(R.id.bubble_bar_drop_target)
 
-    private fun getExpectedDropTargetBounds(onLeft: Boolean): Rect = Rect().also {
-        positioner.getBubbleBarExpandedViewBounds(onLeft, false /* isOveflowExpanded */, it)
-    }
+    private fun getExpectedDropTargetBounds(onLeft: Boolean): Rect =
+        Rect().also {
+            positioner.getBubbleBarExpandedViewBounds(onLeft, false /* isOveflowExpanded */, it)
+        }
 
     private fun runOnMainSync(runnable: Runnable) {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable)
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 8d24c16..aa4fb44 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -247,13 +247,11 @@
     <!-- Padding for the bubble popup view contents. -->
     <dimen name="bubble_popup_padding">24dp</dimen>
     <!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
-    <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
+    <dimen name="bubble_bar_expanded_view_caption_height">36dp</dimen>
     <!-- The width of the caption bar at the top of bubble bar expanded view. -->
-    <dimen name="bubble_bar_expanded_view_caption_width">128dp</dimen>
-    <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
-    <dimen name="bubble_bar_expanded_view_caption_dot_size">4dp</dimen>
-    <!-- The spacing between the dots for the caption menu in the bubble bar expanded view.. -->
-    <dimen name="bubble_bar_expanded_view_caption_dot_spacing">4dp</dimen>
+    <dimen name="bubble_bar_expanded_view_caption_width">80dp</dimen>
+    <!-- The height of the handle shown for the caption menu in the bubble bar expanded view. -->
+    <dimen name="bubble_bar_expanded_view_handle_height">4dp</dimen>
     <!-- Width of the expanded bubble bar view shown when the bubble is expanded. -->
     <dimen name="bubble_bar_expanded_view_width">412dp</dimen>
     <!-- Minimum width of the bubble bar manage menu. -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 38c3443..42a4ab2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1189,10 +1189,12 @@
      * A bubble is no longer being dragged in Launcher. And was released in given location.
      * Will be called only when bubble bar is expanded.
      *
-     * @param location  location where bubble was released
+     * @param location location where bubble was released
+     * @param topOnScreen      top coordinate of the bubble bar on the screen after release
      */
-    public void stopBubbleDrag(BubbleBarLocation location) {
+    public void stopBubbleDrag(BubbleBarLocation location, int topOnScreen) {
         mBubblePositioner.setBubbleBarLocation(location);
+        mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
         if (mBubbleData.getSelectedBubble() != null) {
             mBubbleBarViewCallback.expansionChanged(/* isExpanded = */ true);
         }
@@ -1248,8 +1250,8 @@
      * <p>This is used by external callers (launcher).
      */
     @VisibleForTesting
-    public void expandStackAndSelectBubbleFromLauncher(String key, Rect bubbleBarBounds) {
-        mBubblePositioner.setBubbleBarBounds(bubbleBarBounds);
+    public void expandStackAndSelectBubbleFromLauncher(String key, int topOnScreen) {
+        mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
 
         if (BubbleOverflow.KEY.equals(key)) {
             mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
@@ -2364,10 +2366,9 @@
         }
 
         @Override
-        public void showBubble(String key, Rect bubbleBarBounds) {
+        public void showBubble(String key, int topOnScreen) {
             mMainExecutor.execute(
-                    () -> mController.expandStackAndSelectBubbleFromLauncher(
-                            key, bubbleBarBounds));
+                    () -> mController.expandStackAndSelectBubbleFromLauncher(key, topOnScreen));
         }
 
         @Override
@@ -2386,8 +2387,8 @@
         }
 
         @Override
-        public void stopBubbleDrag(BubbleBarLocation location) {
-            mMainExecutor.execute(() -> mController.stopBubbleDrag(location));
+        public void stopBubbleDrag(BubbleBarLocation location, int topOnScreen) {
+            mMainExecutor.execute(() -> mController.stopBubbleDrag(location, topOnScreen));
         }
 
         @Override
@@ -2408,9 +2409,9 @@
         }
 
         @Override
-        public void setBubbleBarBounds(Rect bubbleBarBounds) {
+        public void updateBubbleBarTopOnScreen(int topOnScreen) {
             mMainExecutor.execute(() -> {
-                mBubblePositioner.setBubbleBarBounds(bubbleBarBounds);
+                mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen);
                 if (mLayerView != null) mLayerView.updateExpandedView();
             });
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index a35a004..1e482ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -98,7 +98,7 @@
 
     private boolean mShowingInBubbleBar;
     private BubbleBarLocation mBubbleBarLocation = BubbleBarLocation.DEFAULT;
-    private final Rect mBubbleBarBounds = new Rect();
+    private int mBubbleBarTopOnScreen;
 
     public BubblePositioner(Context context, WindowManager windowManager) {
         mContext = context;
@@ -846,17 +846,17 @@
     }
 
     /**
-     * Sets the position of the bubble bar in display coordinates.
+     * Set top coordinate of bubble bar on screen
      */
-    public void setBubbleBarBounds(Rect bubbleBarBounds) {
-        mBubbleBarBounds.set(bubbleBarBounds);
+    public void setBubbleBarTopOnScreen(int topOnScreen) {
+        mBubbleBarTopOnScreen = topOnScreen;
     }
 
     /**
-     * Returns the display coordinates of the bubble bar.
+     * Returns the top coordinate of bubble bar on screen
      */
-    public Rect getBubbleBarBounds() {
-        return mBubbleBarBounds;
+    public int getBubbleBarTopOnScreen() {
+        return mBubbleBarTopOnScreen;
     }
 
     /**
@@ -908,7 +908,7 @@
 
     /** The bottom position of the expanded view when showing above the bubble bar. */
     public int getExpandedViewBottomForBubbleBar() {
-        return mBubbleBarBounds.top - mExpandedViewPadding;
+        return mBubbleBarTopOnScreen - mExpandedViewPadding;
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 1eff149..1db556c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -31,7 +31,7 @@
 
     oneway void unregisterBubbleListener(in IBubblesListener listener) = 2;
 
-    oneway void showBubble(in String key, in Rect bubbleBarBounds) = 3;
+    oneway void showBubble(in String key, in int topOnScreen) = 3;
 
     oneway void dragBubbleToDismiss(in String key) = 4;
 
@@ -45,7 +45,7 @@
 
     oneway void setBubbleBarLocation(in BubbleBarLocation location) = 9;
 
-    oneway void setBubbleBarBounds(in Rect bubbleBarBounds) = 10;
+    oneway void updateBubbleBarTopOnScreen(in int topOnScreen) = 10;
 
-    oneway void stopBubbleDrag(in BubbleBarLocation location) = 11;
+    oneway void stopBubbleDrag(in BubbleBarLocation location, in int topOnScreen) = 11;
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 45ad631..8e58db1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -237,12 +237,10 @@
 
     private void setScaleFromBubbleBar(AnimatableScaleMatrix matrix, float scale) {
         // Set the pivot point for the scale, so the view animates out from the bubble bar.
-        Rect bubbleBarBounds = mPositioner.getBubbleBarBounds();
-        matrix.setScale(
-                scale,
-                scale,
-                bubbleBarBounds.centerX(),
-                bubbleBarBounds.top);
+        Rect availableRect = mPositioner.getAvailableRect();
+        float pivotX = mPositioner.isBubbleBarOnLeft() ? availableRect.left : availableRect.right;
+        float pivotY = mPositioner.getBubbleBarTopOnScreen();
+        matrix.setScale(scale, scale, pivotX, pivotY);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
index 2b7a070..d54a6b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -37,15 +37,11 @@
  */
 public class BubbleBarHandleView extends View {
     private static final long COLOR_CHANGE_DURATION = 120;
-
-    // The handle view is currently rendered as 3 evenly spaced dots.
-    private int mDotSize;
-    private int mDotSpacing;
     // Path used to draw the dots
     private final Path mPath = new Path();
 
-    private @ColorInt int mHandleLightColor;
-    private @ColorInt int mHandleDarkColor;
+    private final @ColorInt int mHandleLightColor;
+    private final @ColorInt int mHandleDarkColor;
     private @Nullable ObjectAnimator mColorChangeAnim;
 
     public BubbleBarHandleView(Context context) {
@@ -63,10 +59,8 @@
     public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mDotSize = getResources().getDimensionPixelSize(
-                R.dimen.bubble_bar_expanded_view_caption_dot_size);
-        mDotSpacing = getResources().getDimensionPixelSize(
-                R.dimen.bubble_bar_expanded_view_caption_dot_spacing);
+        final int handleHeight = getResources().getDimensionPixelSize(
+                R.dimen.bubble_bar_expanded_view_handle_height);
         mHandleLightColor = ContextCompat.getColor(getContext(),
                 R.color.bubble_bar_expanded_view_handle_light);
         mHandleDarkColor = ContextCompat.getColor(getContext(),
@@ -76,27 +70,13 @@
         setOutlineProvider(new ViewOutlineProvider() {
             @Override
             public void getOutline(View view, Outline outline) {
-                final int handleCenterX = view.getWidth() / 2;
                 final int handleCenterY = view.getHeight() / 2;
-                final int handleTotalWidth = mDotSize * 3 + mDotSpacing * 2;
-                final int handleLeft = handleCenterX - handleTotalWidth / 2;
-                final int handleTop = handleCenterY - mDotSize / 2;
-                final int handleBottom = handleTop + mDotSize;
-                RectF dot1 = new RectF(
-                        handleLeft, handleTop,
-                        handleLeft + mDotSize, handleBottom);
-                RectF dot2 = new RectF(
-                        dot1.right + mDotSpacing, handleTop,
-                        dot1.right + mDotSpacing + mDotSize, handleBottom
-                );
-                RectF dot3 = new RectF(
-                        dot2.right + mDotSpacing, handleTop,
-                        dot2.right + mDotSpacing + mDotSize, handleBottom
-                );
+                final int handleTop = handleCenterY - handleHeight / 2;
+                final int handleBottom = handleTop + handleHeight;
+                final int radius = handleHeight / 2;
+                RectF handle = new RectF(/* left = */ 0, handleTop, view.getWidth(), handleBottom);
                 mPath.reset();
-                mPath.addOval(dot1, Path.Direction.CW);
-                mPath.addOval(dot2, Path.Direction.CW);
-                mPath.addOval(dot3, Path.Direction.CW);
+                mPath.addRoundRect(handle, radius, radius, Path.Direction.CW);
                 outline.setPath(mPath);
             }
         });
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 607a3b5..2234041 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -347,7 +347,7 @@
                 if (mMoving) {
                     final int position = mSplitLayout.getDividerPosition() + touchPos - mStartPos;
                     mLastDraggingPosition = position;
-                    mSplitLayout.updateDividerBounds(position);
+                    mSplitLayout.updateDividerBounds(position, true /* shouldUseParallaxEffect */);
                 }
                 break;
             case MotionEvent.ACTION_UP:
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 30eb8b5d..de016d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -31,7 +31,6 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -57,7 +56,13 @@
 import java.util.function.Consumer;
 
 /**
- * Handles split decor like showing resizing hint for a specific split.
+ * Handles additional layers over a running task in a split pair, for example showing a veil with an
+ * app icon when the task is being resized (usually to hide weird layouts while the app is being
+ * stretched). One SplitDecorManager is initialized on each window.
+ * <br>
+ * Currently, we show a veil when:
+ *  a) Task is resizing down from a fullscreen window.
+ *  b) Task is being stretched past its original bounds.
  */
 public class SplitDecorManager extends WindowlessWindowManager {
     private static final String TAG = SplitDecorManager.class.getSimpleName();
@@ -78,7 +83,11 @@
 
     private boolean mShown;
     private boolean mIsResizing;
-    private final Rect mOldBounds = new Rect();
+    /** The original bounds of the main task, captured at the beginning of a resize transition. */
+    private final Rect mOldMainBounds = new Rect();
+    /** The original bounds of the side task, captured at the beginning of a resize transition. */
+    private final Rect mOldSideBounds = new Rect();
+    /** The current bounds of the main task, mid-resize. */
     private final Rect mResizingBounds = new Rect();
     private final Rect mTempRect = new Rect();
     private ValueAnimator mFadeAnimator;
@@ -184,29 +193,38 @@
         mResizingIconView = null;
         mIsResizing = false;
         mShown = false;
-        mOldBounds.setEmpty();
+        mOldMainBounds.setEmpty();
+        mOldSideBounds.setEmpty();
         mResizingBounds.setEmpty();
     }
 
     /** Showing resizing hint. */
     public void onResizing(ActivityManager.RunningTaskInfo resizingTask, Rect newBounds,
             Rect sideBounds, SurfaceControl.Transaction t, int offsetX, int offsetY,
-            boolean immediately) {
+            boolean immediately, float[] veilColor) {
         if (mResizingIconView == null) {
             return;
         }
 
         if (!mIsResizing) {
             mIsResizing = true;
-            mOldBounds.set(newBounds);
+            mOldMainBounds.set(newBounds);
+            mOldSideBounds.set(sideBounds);
         }
         mResizingBounds.set(newBounds);
         mOffsetX = offsetX;
         mOffsetY = offsetY;
 
-        final boolean show =
-                newBounds.width() > mOldBounds.width() || newBounds.height() > mOldBounds.height();
-        final boolean update = show != mShown;
+        // Show a veil when:
+        //  a) Task is resizing down from a fullscreen window.
+        //  b) Task is being stretched past its original bounds.
+        final boolean isResizingDownFromFullscreen =
+                mOldSideBounds.width() <= 1 || mOldSideBounds.height() <= 1;
+        final boolean isStretchingPastOriginalBounds =
+                newBounds.width() > mOldMainBounds.width()
+                        || newBounds.height() > mOldMainBounds.height();
+        final boolean showVeil = isResizingDownFromFullscreen || isStretchingPastOriginalBounds;
+        final boolean update = showVeil != mShown;
         if (update && mFadeAnimator != null && mFadeAnimator.isRunning()) {
             // If we need to animate and animator still running, cancel it before we ensure both
             // background and icon surfaces are non null for next animation.
@@ -216,18 +234,18 @@
         if (mBackgroundLeash == null) {
             mBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
                     RESIZING_BACKGROUND_SURFACE_NAME, mSurfaceSession);
-            t.setColor(mBackgroundLeash, getResizingBackgroundColor(resizingTask))
+            t.setColor(mBackgroundLeash, veilColor)
                     .setLayer(mBackgroundLeash, Integer.MAX_VALUE - 1);
         }
 
         if (mGapBackgroundLeash == null && !immediately) {
             final boolean isLandscape = newBounds.height() == sideBounds.height();
-            final int left = isLandscape ? mOldBounds.width() : 0;
-            final int top = isLandscape ? 0 : mOldBounds.height();
+            final int left = isLandscape ? mOldMainBounds.width() : 0;
+            final int top = isLandscape ? 0 : mOldMainBounds.height();
             mGapBackgroundLeash = SurfaceUtils.makeColorLayer(mHostLeash,
                     GAP_BACKGROUND_SURFACE_NAME, mSurfaceSession);
             // Fill up another side bounds area.
-            t.setColor(mGapBackgroundLeash, getResizingBackgroundColor(resizingTask))
+            t.setColor(mGapBackgroundLeash, veilColor)
                     .setLayer(mGapBackgroundLeash, Integer.MAX_VALUE - 2)
                     .setPosition(mGapBackgroundLeash, left, top)
                     .setWindowCrop(mGapBackgroundLeash, sideBounds.width(), sideBounds.height());
@@ -251,12 +269,12 @@
 
         if (update) {
             if (immediately) {
-                t.setVisibility(mBackgroundLeash, show);
-                t.setVisibility(mIconLeash, show);
+                t.setVisibility(mBackgroundLeash, showVeil);
+                t.setVisibility(mIconLeash, showVeil);
             } else {
-                startFadeAnimation(show, false, null);
+                startFadeAnimation(showVeil, false, null);
             }
-            mShown = show;
+            mShown = showVeil;
         }
     }
 
@@ -309,7 +327,8 @@
         mIsResizing = false;
         mOffsetX = 0;
         mOffsetY = 0;
-        mOldBounds.setEmpty();
+        mOldMainBounds.setEmpty();
+        mOldSideBounds.setEmpty();
         mResizingBounds.setEmpty();
         if (mFadeAnimator != null && mFadeAnimator.isRunning()) {
             if (!mShown) {
@@ -346,14 +365,14 @@
 
     /** Screenshot host leash and attach on it if meet some conditions */
     public void screenshotIfNeeded(SurfaceControl.Transaction t) {
-        if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+        if (!mShown && mIsResizing && !mOldMainBounds.equals(mResizingBounds)) {
             if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
                 mScreenshotAnimator.cancel();
             } else if (mScreenshot != null) {
                 t.remove(mScreenshot);
             }
 
-            mTempRect.set(mOldBounds);
+            mTempRect.set(mOldMainBounds);
             mTempRect.offsetTo(0, 0);
             mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
                     Integer.MAX_VALUE - 1);
@@ -364,7 +383,7 @@
     public void setScreenshotIfNeeded(SurfaceControl screenshot, SurfaceControl.Transaction t) {
         if (screenshot == null || !screenshot.isValid()) return;
 
-        if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) {
+        if (!mShown && mIsResizing && !mOldMainBounds.equals(mResizingBounds)) {
             if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) {
                 mScreenshotAnimator.cancel();
             } else if (mScreenshot != null) {
@@ -465,9 +484,4 @@
             mIcon = null;
         }
     }
-
-    private static float[] getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
-        final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
-        return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).getComponents();
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 2ea32f4..8331654 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -496,10 +496,10 @@
      * Updates bounds with the passing position. Usually used to update recording bounds while
      * performing animation or dragging divider bar to resize the splits.
      */
-    void updateDividerBounds(int position) {
+    void updateDividerBounds(int position, boolean shouldUseParallaxEffect) {
         updateBounds(position);
         mSplitLayoutHandler.onLayoutSizeChanging(this, mSurfaceEffectPolicy.mParallaxOffset.x,
-                mSurfaceEffectPolicy.mParallaxOffset.y);
+                mSurfaceEffectPolicy.mParallaxOffset.y, shouldUseParallaxEffect);
     }
 
     void setDividerPosition(int position, boolean applyLayoutChange) {
@@ -647,7 +647,9 @@
                 .setDuration(duration);
         mDividerFlingAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         mDividerFlingAnimator.addUpdateListener(
-                animation -> updateDividerBounds((int) animation.getAnimatedValue()));
+                animation -> updateDividerBounds(
+                        (int) animation.getAnimatedValue(), false /* shouldUseParallaxEffect */)
+        );
         mDividerFlingAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -897,7 +899,8 @@
          * @see #applySurfaceChanges(SurfaceControl.Transaction, SurfaceControl, SurfaceControl,
          * SurfaceControl, SurfaceControl, boolean)
          */
-        void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY);
+        void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY,
+                boolean shouldUseParallaxEffect);
 
         /**
          * Calls when finish resizing the split bounds.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
index f9259e7..e8226051 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -16,8 +16,6 @@
 
 package com.android.wm.shell.common.split;
 
-import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED;
-
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
@@ -26,25 +24,18 @@
 
 import android.app.ActivityManager;
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.Rect;
-import android.os.UserHandle;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.wm.shell.Flags;
 import com.android.wm.shell.ShellTaskOrganizer;
 
-import java.util.Arrays;
-import java.util.List;
-
 /** Helper utility class for split screen components to use. */
 public class SplitScreenUtils {
     /** Reverse the split position. */
@@ -137,4 +128,10 @@
             return isLandscape;
         }
     }
+
+    /** Returns the specified background color that matches a RunningTaskInfo. */
+    public static Color getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+        final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+        return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index fb0a1ab..4e9e8f9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -100,6 +100,7 @@
 import com.android.wm.shell.unfold.qualifier.UnfoldTransition;
 import com.android.wm.shell.windowdecor.CaptionWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
+import com.android.wm.shell.windowdecor.ResizeHandleSizeRepository;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
 import dagger.Binds;
@@ -220,7 +221,8 @@
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            ResizeHandleSizeRepository resizeHandleSizeRepository) {
         if (DesktopModeStatus.canEnterDesktopMode(context)) {
             return new DesktopModeWindowDecorViewModel(
                     context,
@@ -237,7 +239,8 @@
                     syncQueue,
                     transitions,
                     desktopTasksController,
-                    rootTaskDisplayAreaOrganizer);
+                    rootTaskDisplayAreaOrganizer,
+                    resizeHandleSizeRepository);
         }
         return new CaptionWindowDecorViewModel(
                 context,
@@ -247,7 +250,8 @@
                 displayController,
                 rootTaskDisplayAreaOrganizer,
                 syncQueue,
-                transitions);
+                transitions,
+                resizeHandleSizeRepository);
     }
 
     //
@@ -529,7 +533,8 @@
                 exitDesktopTransitionHandler, toggleResizeDesktopTaskTransitionHandler,
                 dragToDesktopTransitionHandler, desktopModeTaskRepository,
                 desktopModeLoggerTransitionObserver, launchAdjacentController,
-                recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter);
+                recentsTransitionHandler, multiInstanceHelper,
+                mainExecutor, desktopTasksLimiter);
     }
 
     @WMSingleton
@@ -622,6 +627,12 @@
         return new DesktopModeEventLogger();
     }
 
+    @WMSingleton
+    @Provides
+    static ResizeHandleSizeRepository provideResizeHandleSizeRepository() {
+        return new ResizeHandleSizeRepository();
+    }
+
     //
     // Drag and drop
     //
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 2dc4573..79a2090 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -906,7 +906,8 @@
                     task.taskId
             )
             return WindowContainerTransaction().also { wct ->
-                addMoveToFullscreenChanges(wct, task)
+                bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
+                wct.reorder(task.token, true)
             }
         }
         // Desktop Mode is showing and we're launching a new Task - we might need to minimize
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 59d6969..4bb10df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -22,11 +22,11 @@
 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor;
 import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM;
 import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT;
 import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
@@ -41,7 +41,6 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -278,7 +277,7 @@
                 final int activityType = taskInfo1.getActivityType();
                 if (activityType == ACTIVITY_TYPE_STANDARD) {
                     Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
-                    int bgColor1 = getResizingBackgroundColor(taskInfo1);
+                    int bgColor1 = getResizingBackgroundColor(taskInfo1).toArgb();
                     mDropZoneView1.setAppInfo(bgColor1, icon1);
                     mDropZoneView2.setAppInfo(bgColor1, icon1);
                     updateDropZoneSizes(null, null); // passing null splits the views evenly
@@ -298,10 +297,10 @@
                     mSplitScreenController.getTaskInfo(SPLIT_POSITION_BOTTOM_OR_RIGHT);
             if (topOrLeftTask != null && bottomOrRightTask != null) {
                 Drawable topOrLeftIcon = mIconProvider.getIcon(topOrLeftTask.topActivityInfo);
-                int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask);
+                int topOrLeftColor = getResizingBackgroundColor(topOrLeftTask).toArgb();
                 Drawable bottomOrRightIcon = mIconProvider.getIcon(
                         bottomOrRightTask.topActivityInfo);
-                int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask);
+                int bottomOrRightColor = getResizingBackgroundColor(bottomOrRightTask).toArgb();
                 mDropZoneView1.setAppInfo(topOrLeftColor, topOrLeftIcon);
                 mDropZoneView2.setAppInfo(bottomOrRightColor, bottomOrRightIcon);
             }
@@ -556,11 +555,6 @@
         }
     }
 
-    private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
-        final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
-        return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
-    }
-
     /**
      * Dumps information about this drag layout.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 8e97068..4299088 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -43,6 +43,7 @@
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.common.split.SplitScreenConstants.splitPositionToString;
+import static com.android.wm.shell.common.split.SplitScreenUtils.getResizingBackgroundColor;
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
 import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
@@ -2388,14 +2389,20 @@
     }
 
     @Override
-    public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY) {
+    public void onLayoutSizeChanging(SplitLayout layout, int offsetX, int offsetY,
+            boolean shouldUseParallaxEffect) {
         final SurfaceControl.Transaction t = mTransactionPool.acquire();
         t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
-        updateSurfaceBounds(layout, t, true /* applyResizingOffset */);
+        updateSurfaceBounds(layout, t, shouldUseParallaxEffect);
         getMainStageBounds(mTempRect1);
         getSideStageBounds(mTempRect2);
-        mMainStage.onResizing(mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately);
-        mSideStage.onResizing(mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately);
+        // TODO (b/307490004): "commonColor" below is a temporary fix to ensure the colors on both
+        //  sides match. When b/307490004 is fixed, this code can be reverted.
+        float[] commonColor = getResizingBackgroundColor(mSideStage.mRootTaskInfo).getComponents();
+        mMainStage.onResizing(
+                mTempRect1, mTempRect2, t, offsetX, offsetY, mShowDecorImmediately, commonColor);
+        mSideStage.onResizing(
+                mTempRect2, mTempRect1, t, offsetX, offsetY, mShowDecorImmediately, commonColor);
         t.apply();
         mTransactionPool.release(t);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index f77c80d..0f3d6ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -314,10 +314,10 @@
     }
 
     void onResizing(Rect newBounds, Rect sideBounds, SurfaceControl.Transaction t, int offsetX,
-            int offsetY, boolean immediately) {
+            int offsetY, boolean immediately, float[] veilColor) {
         if (mSplitDecorManager != null && mRootTaskInfo != null) {
             mSplitDecorManager.onResizing(mRootTaskInfo, newBounds, sideBounds, t, offsetX,
-                    offsetY, immediately);
+                    offsetY, immediately, veilColor);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index e85cb64..bfa163c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -63,6 +63,7 @@
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
     private final SyncTransactionQueue mSyncQueue;
     private final Transitions mTransitions;
+    private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
     private TaskOperations mTaskOperations;
 
     private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
@@ -75,7 +76,8 @@
             DisplayController displayController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
             SyncTransactionQueue syncQueue,
-            Transitions transitions) {
+            Transitions transitions,
+            ResizeHandleSizeRepository resizeHandleSizeRepository) {
         mContext = context;
         mMainHandler = mainHandler;
         mMainChoreographer = mainChoreographer;
@@ -84,6 +86,7 @@
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
+        mResizeHandleSizeRepository = resizeHandleSizeRepository;
         if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
             mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
         }
@@ -231,7 +234,8 @@
                         taskSurface,
                         mMainHandler,
                         mMainChoreographer,
-                        mSyncQueue);
+                        mSyncQueue,
+                        mResizeHandleSizeRepository);
         mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
 
         final FluidResizeTaskPositioner taskPositioner =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 6671391..1be3b02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.windowdecor;
 
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getFineResizeCornerPixels;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getLargeResizeCornerPixels;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.WindowingMode;
@@ -45,6 +45,8 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 
+import java.util.function.Consumer;
+
 /**
  * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
  * {@link CaptionWindowDecorViewModel}. The caption bar contains a back button, minimize button,
@@ -58,12 +60,28 @@
     private View.OnClickListener mOnCaptionButtonClickListener;
     private View.OnTouchListener mOnCaptionTouchListener;
     private DragPositioningCallback mDragPositioningCallback;
+    // Listener for handling drag resize events. Will be null if the task cannot be resized.
+    @Nullable
     private DragResizeInputListener mDragResizeListener;
     private DragDetector mDragDetector;
 
     private RelayoutParams mRelayoutParams = new RelayoutParams();
     private final RelayoutResult<WindowDecorLinearLayout> mResult =
             new RelayoutResult<>();
+    private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
+    private final Consumer<ResizeHandleSizeRepository> mResizeHandleSizeChangedFunction =
+            (ResizeHandleSizeRepository sizeRepository) -> {
+                if (mDragResizeListener == null) {
+                    return;
+                }
+                final Resources res = mResult.mRootView.getResources();
+                mDragResizeListener.setGeometry(
+                        new DragResizeWindowGeometry(0 /* taskCornerRadius */,
+                                new Size(mResult.mWidth, mResult.mHeight),
+                                sizeRepository.getResizeEdgeHandlePixels(res),
+                                getFineResizeCornerPixels(res), getLargeResizeCornerPixels(res)),
+                        mDragDetector.getTouchSlop());
+            };
 
     CaptionWindowDecoration(
             Context context,
@@ -73,13 +91,16 @@
             SurfaceControl taskSurface,
             Handler handler,
             Choreographer choreographer,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue,
+            ResizeHandleSizeRepository resizeHandleSizeRepository) {
         super(context, displayController, taskOrganizer, taskInfo, taskSurface,
                 taskInfo.getConfiguration());
 
         mHandler = handler;
         mChoreographer = choreographer;
         mSyncQueue = syncQueue;
+        mResizeHandleSizeRepository = resizeHandleSizeRepository;
+        mResizeHandleSizeRepository.registerSizeChangeFunction(mResizeHandleSizeChangedFunction);
     }
 
     void setCaptionListeners(
@@ -238,10 +259,7 @@
                 .getScaledTouchSlop();
         mDragDetector.setTouchSlop(touchSlop);
 
-        final Resources res = mResult.mRootView.getResources();
-        mDragResizeListener.setGeometry(new DragResizeWindowGeometry(0 /* taskCornerRadius */,
-                new Size(mResult.mWidth, mResult.mHeight), getResizeEdgeHandleSize(res),
-                getFineResizeCornerSize(res), getLargeResizeCornerSize(res)), touchSlop);
+        mResizeHandleSizeChangedFunction.accept(mResizeHandleSizeRepository);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 9afb057..10ab13a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -149,6 +149,7 @@
             new DesktopModeKeyguardChangeListener();
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
     private final DisplayInsetsController mDisplayInsetsController;
+    private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
     private final Region mExclusionRegion = Region.obtain();
     private boolean mInImmersiveMode;
 
@@ -181,7 +182,8 @@
             SyncTransactionQueue syncQueue,
             Transitions transitions,
             Optional<DesktopTasksController> desktopTasksController,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            ResizeHandleSizeRepository resizeHandleSizeRepository
     ) {
         this(
                 context,
@@ -202,7 +204,8 @@
                 new InputMonitorFactory(),
                 SurfaceControl.Transaction::new,
                 rootTaskDisplayAreaOrganizer,
-                new SparseArray<>());
+                new SparseArray<>(),
+                resizeHandleSizeRepository);
     }
 
     @VisibleForTesting
@@ -225,7 +228,8 @@
             InputMonitorFactory inputMonitorFactory,
             Supplier<SurfaceControl.Transaction> transactionFactory,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
-            SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId) {
+            SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId,
+            ResizeHandleSizeRepository resizeHandleSizeRepository) {
         mContext = context;
         mMainExecutor = shellExecutor;
         mMainHandler = mainHandler;
@@ -246,6 +250,7 @@
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
         mInputManager = mContext.getSystemService(InputManager.class);
         mWindowDecorByTaskId = windowDecorByTaskId;
+        mResizeHandleSizeRepository = resizeHandleSizeRepository;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -1060,7 +1065,8 @@
                         mMainHandler,
                         mMainChoreographer,
                         mSyncQueue,
-                        mRootTaskDisplayAreaOrganizer);
+                        mRootTaskDisplayAreaOrganizer,
+                        mResizeHandleSizeRepository);
         mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
 
         final DragPositioningCallback dragPositioningCallback;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 4d4dc3c..18c3113 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -24,11 +24,11 @@
 import static android.view.MotionEvent.ACTION_UP;
 
 import static com.android.launcher3.icons.BaseIconFactory.MODE_DEFAULT;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getFineResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getLargeResizeCornerSize;
-import static com.android.wm.shell.windowdecor.DragResizeWindowGeometry.getResizeEdgeHandleSize;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getFineResizeCornerPixels;
+import static com.android.wm.shell.windowdecor.ResizeHandleSizeRepository.getLargeResizeCornerPixels;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.WindowConfiguration.WindowingMode;
 import android.content.Context;
@@ -60,6 +60,7 @@
 import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.IconProvider;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -75,6 +76,7 @@
 
 import kotlin.Unit;
 
+import java.util.function.Function;
 import java.util.function.Supplier;
 
 /**
@@ -96,6 +98,8 @@
     private View.OnLongClickListener mOnCaptionLongClickListener;
     private View.OnGenericMotionListener mOnCaptionGenericMotionListener;
     private DragPositioningCallback mDragPositioningCallback;
+    // Listener for handling drag resize events. Will be null if the task cannot be resized.
+    @Nullable
     private DragResizeInputListener mDragResizeListener;
     private DragDetector mDragDetector;
 
@@ -118,6 +122,19 @@
 
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
 
+    private final ResizeHandleSizeRepository mResizeHandleSizeRepository;
+    private final Function<ResizeHandleSizeRepository, Boolean> mResizeHandleSizeChangedFunction =
+            (ResizeHandleSizeRepository sizeRepository) -> {
+                final Resources res = mResult.mRootView.getResources();
+                return mDragResizeListener == null || mDragResizeListener.setGeometry(
+                        new DragResizeWindowGeometry(mRelayoutParams.mCornerRadius,
+                                new Size(mResult.mWidth, mResult.mHeight),
+                                sizeRepository.getResizeEdgeHandlePixels(res),
+                                getFineResizeCornerPixels(res),
+                                getLargeResizeCornerPixels(res)),
+                        mDragDetector.getTouchSlop());
+            };
+
     DesktopModeWindowDecoration(
             Context context,
             DisplayController displayController,
@@ -128,12 +145,13 @@
             Handler handler,
             Choreographer choreographer,
             SyncTransactionQueue syncQueue,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            ResizeHandleSizeRepository resizeHandleSizeRepository) {
         this (context, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorConfig,
                 handler, choreographer, syncQueue, rootTaskDisplayAreaOrganizer,
-                SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
-                WindowContainerTransaction::new, SurfaceControl::new,
-                new SurfaceControlViewHostFactory() {});
+                resizeHandleSizeRepository, SurfaceControl.Builder::new,
+                SurfaceControl.Transaction::new, WindowContainerTransaction::new,
+                SurfaceControl::new, new SurfaceControlViewHostFactory() {});
     }
 
     DesktopModeWindowDecoration(
@@ -147,6 +165,7 @@
             Choreographer choreographer,
             SyncTransactionQueue syncQueue,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            ResizeHandleSizeRepository resizeHandleSizeRepository,
             Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
             Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
             Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
@@ -160,6 +179,9 @@
         mChoreographer = choreographer;
         mSyncQueue = syncQueue;
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
+        mResizeHandleSizeRepository = resizeHandleSizeRepository;
+        mResizeHandleSizeRepository.registerSizeChangeFunction(
+                mResizeHandleSizeChangedFunction::apply);
     }
 
     void setCaptionListeners(
@@ -305,11 +327,7 @@
 
         // If either task geometry or position have changed, update this task's
         // exclusion region listener
-        final Resources res = mResult.mRootView.getResources();
-        if (mDragResizeListener.setGeometry(
-                new DragResizeWindowGeometry(mRelayoutParams.mCornerRadius,
-                        new Size(mResult.mWidth, mResult.mHeight), getResizeEdgeHandleSize(res),
-                        getFineResizeCornerSize(res), getLargeResizeCornerSize(res)), touchSlop)
+        if (mResizeHandleSizeChangedFunction.apply(mResizeHandleSizeRepository)
                 || !mTaskInfo.positionInParent.equals(mPositionInParent)) {
             updateExclusionRegion();
         }
@@ -332,13 +350,16 @@
             boolean applyStartTransactionOnDraw,
             boolean shouldSetTaskPositionAndCrop) {
         final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
+        final boolean isAppHeader =
+                captionLayoutId == R.layout.desktop_mode_app_controls_window_decor;
+        final boolean isAppHandle = captionLayoutId == R.layout.desktop_mode_focused_window_decor;
         relayoutParams.reset();
         relayoutParams.mRunningTaskInfo = taskInfo;
         relayoutParams.mLayoutResId = captionLayoutId;
         relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
         relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
 
-        if (captionLayoutId == R.layout.desktop_mode_app_controls_window_decor) {
+        if (isAppHeader) {
             if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
                 // If the app is requesting to customize the caption bar, allow input to fall
                 // through to the windows below so that the app can respond to input events on
@@ -359,7 +380,7 @@
             controlsElement.mWidthResId = R.dimen.desktop_mode_customizable_caption_margin_end;
             controlsElement.mAlignment = RelayoutParams.OccludingCaptionElement.Alignment.END;
             relayoutParams.mOccludingCaptionElements.add(controlsElement);
-        } else if (captionLayoutId == R.layout.desktop_mode_focused_window_decor) {
+        } else if (isAppHandle) {
             // The focused decor (fullscreen/split) does not need to handle input because input in
             // the App Handle is handled by the InputMonitor in DesktopModeWindowDecorViewModel.
             relayoutParams.mInputFeatures
@@ -372,19 +393,25 @@
         }
         relayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
         relayoutParams.mSetTaskPositionAndCrop = shouldSetTaskPositionAndCrop;
-        // The configuration used to lay out the window decoration. The system context's config is
-        // used when the task density has been overridden to a custom density so that the resources
-        // and views of the decoration aren't affected and match the rest of the System UI, if not
-        // then just use the task's configuration. A copy is made instead of using the original
-        // reference so that the configuration isn't mutated on config changes and diff checks can
-        // be made in WindowDecoration#relayout using the pre/post-relayout configuration.
-        // See b/301119301.
+
+        // The configuration used to layout the window decoration. A copy is made instead of using
+        // the original reference so that the configuration isn't mutated on config changes and
+        // diff checks can be made in WindowDecoration#relayout using the pre/post-relayout
+        // configuration. See b/301119301.
         // TODO(b/301119301): consider moving the config data needed for diffs to relayout params
         // instead of using a whole Configuration as a parameter.
         final Configuration windowDecorConfig = new Configuration();
-        windowDecorConfig.setTo(DesktopTasksController.isDesktopDensityOverrideSet()
-                ? context.getResources().getConfiguration() // Use system context.
-                : taskInfo.configuration); // Use task configuration.
+        if (Flags.enableAppHeaderWithTaskDensity() && isAppHeader) {
+            // Should match the density of the task. The task may have had its density overridden
+            // to be different that SysUI's.
+            windowDecorConfig.setTo(taskInfo.configuration);
+        } else if (DesktopTasksController.isDesktopDensityOverrideSet()) {
+            // The task has had its density overridden, but keep using the system's density to
+            // layout the header.
+            windowDecorConfig.setTo(context.getResources().getConfiguration());
+        } else {
+            windowDecorConfig.setTo(taskInfo.configuration);
+        }
         relayoutParams.mWindowDecorConfig = windowDecorConfig;
 
         if (DesktopModeStatus.useRoundedCorners()) {
@@ -936,7 +963,8 @@
                 Handler handler,
                 Choreographer choreographer,
                 SyncTransactionQueue syncQueue,
-                RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+                RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+                ResizeHandleSizeRepository resizeHandleSizeRepository) {
             final Configuration windowDecorConfig =
                     DesktopTasksController.isDesktopDensityOverrideSet()
                     ? context.getResources().getConfiguration() // Use system context
@@ -951,7 +979,8 @@
                     handler,
                     choreographer,
                     syncQueue,
-                    rootTaskDisplayAreaOrganizer);
+                    rootTaskDisplayAreaOrganizer,
+                    resizeHandleSizeRepository);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index da26898..a3b0a71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -119,6 +119,10 @@
         mTouchSlop = touchSlop;
     }
 
+    int getTouchSlop() {
+        return mTouchSlop;
+    }
+
     private void resetState() {
         mIsDragEvent = false;
         mInputDownPoint.set(0, 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
index 4f513f0..80d60d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometry.java
@@ -26,7 +26,6 @@
 import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED;
 
 import android.annotation.NonNull;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -36,8 +35,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.wm.shell.R;
-
 import java.util.Objects;
 
 /**
@@ -63,6 +60,10 @@
     // Extra-large edge bounds for logging to help debug when an edge resize is ignored.
     private final @Nullable TaskEdges mDebugTaskEdges;
 
+    /**
+     * Constructs an instance representing the drag resize touch input regions, where all sizes
+     * are represented in pixels.
+     */
     DragResizeWindowGeometry(int taskCornerRadius, @NonNull Size taskSize,
             int resizeHandleThickness, int fineCornerSize, int largeCornerSize) {
         mTaskCornerRadius = taskCornerRadius;
@@ -82,31 +83,6 @@
     }
 
     /**
-     * Returns the resource value to use for the resize handle on the edge of the window.
-     */
-    static int getResizeEdgeHandleSize(@NonNull Resources res) {
-        return enableWindowingEdgeDragResize()
-                ? res.getDimensionPixelSize(R.dimen.desktop_mode_edge_handle)
-                : res.getDimensionPixelSize(R.dimen.freeform_resize_handle);
-    }
-
-    /**
-     * Returns the resource value to use for course input, such as touch, that benefits from a large
-     * square on each of the window's corners.
-     */
-    static int getLargeResizeCornerSize(@NonNull Resources res) {
-        return res.getDimensionPixelSize(R.dimen.desktop_mode_corner_resize_large);
-    }
-
-    /**
-     * Returns the resource value to use for fine input, such as stylus, that can use a smaller
-     * square on each of the window's corners.
-     */
-    static int getFineResizeCornerSize(@NonNull Resources res) {
-        return res.getDimensionPixelSize(R.dimen.freeform_resize_corner);
-    }
-
-    /**
      * Returns the size of the task this geometry is calculated for.
      */
     @NonNull Size getTaskSize() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepository.kt
new file mode 100644
index 0000000..be7a301
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepository.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor
+
+import android.content.res.Resources
+import com.android.window.flags.Flags.enableWindowingEdgeDragResize
+import com.android.wm.shell.R
+import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
+import com.android.wm.shell.util.KtProtoLog
+import java.util.function.Consumer
+
+/** Repository for desktop mode drag resize handle sizes. */
+class ResizeHandleSizeRepository {
+    private val TAG = "ResizeHandleSizeRepository"
+    private var edgeResizeHandleSizePixels: Int? = null
+    private var sizeChangeFunctions: MutableList<Consumer<ResizeHandleSizeRepository>> =
+        mutableListOf()
+
+    /**
+     * Resets the window edge resize handle size if necessary.
+     */
+    fun resetResizeEdgeHandlePixels() {
+        if (enableWindowingEdgeDragResize() && edgeResizeHandleSizePixels != null) {
+            edgeResizeHandleSizePixels = null
+            applyToAll()
+        }
+    }
+
+    /**
+     * Sets the window edge resize handle to the given size in pixels.
+     */
+    fun setResizeEdgeHandlePixels(sizePixels: Int) {
+        if (enableWindowingEdgeDragResize()) {
+            KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "$TAG: Set edge handle size to $sizePixels")
+            if (edgeResizeHandleSizePixels != null && edgeResizeHandleSizePixels == sizePixels) {
+                // Skip updating since override is the same size
+                return
+            }
+            edgeResizeHandleSizePixels = sizePixels
+            applyToAll()
+        } else {
+            KtProtoLog.d(
+                WM_SHELL_DESKTOP_MODE,
+                "$TAG: Can't set edge handle size to $sizePixels since " +
+                    "enable_windowing_edge_drag_resize disabled"
+            )
+        }
+    }
+
+    /**
+     * Returns the resource value, in pixels, to use for the resize handle on the edge of the
+     * window.
+     */
+    fun getResizeEdgeHandlePixels(res: Resources): Int {
+        try {
+            return if (enableWindowingEdgeDragResize()) {
+                val resPixelSize = res.getDimensionPixelSize(R.dimen.desktop_mode_edge_handle)
+                val size = edgeResizeHandleSizePixels ?: resPixelSize
+                KtProtoLog.d(
+                    WM_SHELL_DESKTOP_MODE,
+                    "$TAG: Get edge handle size of $size from (vs base value $resPixelSize)"
+                )
+                size
+            } else {
+                KtProtoLog.d(
+                    WM_SHELL_DESKTOP_MODE,
+                    "$TAG: Get edge handle size from freeform since flag is disabled"
+                )
+                res.getDimensionPixelSize(R.dimen.freeform_resize_handle)
+            }
+        } catch (e: Resources.NotFoundException) {
+            KtProtoLog.e(WM_SHELL_DESKTOP_MODE, "$TAG: Unable to get edge handle size", e)
+            return 0
+        }
+    }
+
+    /** Register function to run when the resize handle size changes. */
+    fun registerSizeChangeFunction(function: Consumer<ResizeHandleSizeRepository>) {
+        sizeChangeFunctions.add(function)
+    }
+
+    private fun applyToAll() {
+        for (f in sizeChangeFunctions) {
+            f.accept(this)
+        }
+    }
+
+    companion object {
+        private val TAG = "ResizeHandleSizeRepositoryCompanion"
+
+        /**
+         * Returns the resource value in pixels to use for course input, such as touch, that
+         * benefits from a large square on each of the window's corners.
+         */
+        @JvmStatic
+        fun getLargeResizeCornerPixels(res: Resources): Int {
+            return try {
+                res.getDimensionPixelSize(R.dimen.desktop_mode_corner_resize_large)
+            } catch (e: Resources.NotFoundException) {
+                KtProtoLog.e(WM_SHELL_DESKTOP_MODE, "$TAG: Unable to get large corner size", e)
+                0
+            }
+        }
+
+        /**
+         * Returns the resource value, in pixels, to use for fine input, such as stylus, that can
+         * use a smaller square on each of the window's corners.
+         */
+        @JvmStatic
+        fun getFineResizeCornerPixels(res: Resources): Int {
+            return try {
+                res.getDimensionPixelSize(R.dimen.freeform_resize_corner)
+            } catch (e: Resources.NotFoundException) {
+                KtProtoLog.e(WM_SHELL_DESKTOP_MODE, "$TAG: Unable to get fine corner size", e)
+                0
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 8de60b7..cfe8e07 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -26,6 +26,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
@@ -115,9 +116,9 @@
 
     @Test
     public void testUpdateDivideBounds() {
-        mSplitLayout.updateDividerBounds(anyInt());
+        mSplitLayout.updateDividerBounds(anyInt(), anyBoolean());
         verify(mSplitLayoutHandler).onLayoutSizeChanging(any(SplitLayout.class), anyInt(),
-                anyInt());
+                anyInt(), anyBoolean());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index f67da55..14f57bd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -1072,7 +1072,7 @@
     }
 
     @Test
-    fun handleRequest_freeformTask_freeformNotVisible_returnSwitchToFullscreenWCT() {
+    fun handleRequest_freeformTask_freeformNotVisible_reorderedToTop() {
         assumeTrue(ENABLE_SHELL_TRANSITIONS)
 
         val freeformTask1 = setUpFreeformTask()
@@ -1084,30 +1084,32 @@
                 Binder(),
                 createTransition(freeformTask2, type = TRANSIT_TO_FRONT)
             )
-        assertThat(result?.changes?.get(freeformTask2.token.asBinder())?.windowingMode)
-            .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+
+        assertThat(result?.hierarchyOps?.size).isEqualTo(2)
+        result!!.assertReorderAt(1, freeformTask2, toTop = true)
     }
 
     @Test
-    fun handleRequest_freeformTask_noOtherTasks_returnSwitchToFullscreenWCT() {
+    fun handleRequest_freeformTask_noOtherTasks_reorderedToTop() {
         assumeTrue(ENABLE_SHELL_TRANSITIONS)
 
         val task = createFreeformTask()
         val result = controller.handleRequest(Binder(), createTransition(task))
-        assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
-            .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+
+        assertThat(result?.hierarchyOps?.size).isEqualTo(1)
+        result!!.assertReorderAt(0, task, toTop = true)
     }
 
     @Test
-    fun handleRequest_freeformTask_freeformOnOtherDisplayOnly_returnSwitchToFullscreenWCT() {
+    fun handleRequest_freeformTask_freeformOnOtherDisplayOnly_reorderedToTop() {
         assumeTrue(ENABLE_SHELL_TRANSITIONS)
 
         val taskDefaultDisplay = createFreeformTask(displayId = DEFAULT_DISPLAY)
-        createFreeformTask(displayId = SECOND_DISPLAY)
+        val taskSecondDisplay = createFreeformTask(displayId = SECOND_DISPLAY)
 
         val result = controller.handleRequest(Binder(), createTransition(taskDefaultDisplay))
-        assertThat(result?.changes?.get(taskDefaultDisplay.token.asBinder())?.windowingMode)
-            .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+        assertThat(result?.hierarchyOps?.size).isEqualTo(1)
+        result!!.assertReorderAt(0, taskDefaultDisplay, toTop = true)
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index aa2cee7..282495d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -121,6 +121,7 @@
     @Mock private lateinit var mockShellController: ShellController
     @Mock private lateinit var mockShellExecutor: ShellExecutor
     @Mock private lateinit var mockRootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+    @Mock private lateinit var mockResizeHandleSizeRepository: ResizeHandleSizeRepository
     @Mock private lateinit var mockShellCommandHandler: ShellCommandHandler
     @Mock private lateinit var mockWindowManager: IWindowManager
 
@@ -156,7 +157,8 @@
                 mockInputMonitorFactory,
                 transactionFactory,
                 mockRootTaskDisplayAreaOrganizer,
-            windowDecorByTaskIdSpy
+                windowDecorByTaskIdSpy,
+                mockResizeHandleSizeRepository
         )
 
         whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout)
@@ -197,7 +199,8 @@
                 mockMainHandler,
                 mockMainChoreographer,
                 mockSyncQueue,
-                mockRootTaskDisplayAreaOrganizer
+                mockRootTaskDisplayAreaOrganizer,
+                mockResizeHandleSizeRepository
         )
         verify(decoration).close()
     }
@@ -221,7 +224,8 @@
                 mockMainHandler,
                 mockMainChoreographer,
                 mockSyncQueue,
-                mockRootTaskDisplayAreaOrganizer
+                mockRootTaskDisplayAreaOrganizer,
+                mockResizeHandleSizeRepository
         )
 
         task.setWindowingMode(WINDOWING_MODE_FREEFORM)
@@ -236,7 +240,8 @@
                 mockMainHandler,
                 mockMainChoreographer,
                 mockSyncQueue,
-                mockRootTaskDisplayAreaOrganizer
+                mockRootTaskDisplayAreaOrganizer,
+                mockResizeHandleSizeRepository
         )
     }
 
@@ -296,7 +301,7 @@
         onTaskChanging(task)
 
         verify(mockDesktopModeWindowDecorFactory, never())
-                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
     }
 
     @Test
@@ -309,7 +314,7 @@
         onTaskOpening(task)
 
         verify(mockDesktopModeWindowDecorFactory, never())
-                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
     }
 
     @Test
@@ -406,7 +411,7 @@
 
             onTaskOpening(task)
             verify(mockDesktopModeWindowDecorFactory, never())
-                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
         } finally {
             mockitoSession.finishMocking()
         }
@@ -430,7 +435,7 @@
 
             onTaskOpening(task)
             verify(mockDesktopModeWindowDecorFactory)
-                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
         } finally {
             mockitoSession.finishMocking()
         }
@@ -453,7 +458,7 @@
 
             onTaskOpening(task)
             verify(mockDesktopModeWindowDecorFactory)
-                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+                .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
         } finally {
             mockitoSession.finishMocking()
         }
@@ -497,7 +502,7 @@
         val decoration = mock(DesktopModeWindowDecoration::class.java)
         whenever(
             mockDesktopModeWindowDecorFactory.create(
-                any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+                any(), any(), any(), eq(task), any(), any(), any(), any(), any(), any())
         ).thenReturn(decoration)
         decoration.mTaskInfo = task
         whenever(decoration.isFocused).thenReturn(task.isFocused)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 608f74b..cff9313 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -39,6 +40,9 @@
 import android.content.res.TypedArray;
 import android.os.Handler;
 import android.os.SystemProperties;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
 import android.view.Choreographer;
@@ -51,6 +55,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
@@ -61,6 +66,7 @@
 
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -83,6 +89,8 @@
     private static final String USE_ROUNDED_CORNERS_SYSPROP_KEY =
             "persist.wm.debug.desktop_use_rounded_corners";
 
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
     @Mock
     private DisplayController mMockDisplayController;
     @Mock
@@ -107,6 +115,8 @@
     private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
     @Mock
     private TypedArray mMockRoundedCornersRadiusArray;
+    @Mock
+    private ResizeHandleSizeRepository mMockResizeHandleSizeRepository;
 
     private final Configuration mConfiguration = new Configuration();
 
@@ -175,6 +185,48 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
+    public void updateRelayoutParams_appHeader_usesTaskDensity() {
+        final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
+                .getConfiguration().densityDpi;
+        final int customTaskDensity = systemDensity + 300;
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        taskInfo.configuration.densityDpi = customTaskDensity;
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(customTaskDensity);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY)
+    public void updateRelayoutParams_appHeader_usesSystemDensity() {
+        final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources()
+                .getConfiguration().densityDpi;
+        final int customTaskDensity = systemDensity + 300;
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        taskInfo.configuration.densityDpi = customTaskDensity;
+        final RelayoutParams relayoutParams = new RelayoutParams();
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false);
+
+        assertThat(relayoutParams.mWindowDecorConfig.densityDpi).isEqualTo(systemDensity);
+    }
+
+    @Test
     public void updateRelayoutParams_freeformAndTransparentAppearance_allowsInputFallthrough() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
         taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -296,8 +348,8 @@
         return new DesktopModeWindowDecoration(mContext, mMockDisplayController,
                 mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, mConfiguration,
                 mMockHandler, mMockChoreographer, mMockSyncQueue, mMockRootTaskDisplayAreaOrganizer,
-                SurfaceControl.Builder::new, mMockTransactionSupplier,
-                WindowContainerTransaction::new, SurfaceControl::new,
+                mMockResizeHandleSizeRepository, SurfaceControl.Builder::new,
+                mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
                 mMockSurfaceControlViewHostFactory);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
index 5464508..62fb1c4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeWindowGeometryTests.java
@@ -27,10 +27,7 @@
 import android.annotation.NonNull;
 import android.graphics.Point;
 import android.graphics.Region;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.AndroidTestingRunner;
 import android.util.Size;
 
@@ -74,7 +71,7 @@
             TASK_SIZE.getHeight() + EDGE_RESIZE_THICKNESS / 2);
 
     @Rule
-    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
     /**
      * Check that both groups of objects satisfy equals/hashcode within each group, and that each
@@ -147,8 +144,8 @@
      * capture all eligible input regardless of source (touch or cursor).
      */
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
     public void testRegionUnion_edgeDragResizeEnabled_containsLargeCorners() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
         Region region = new Region();
         GEOMETRY.union(region);
         // Make sure we're choosing a point outside of any debug region buffer.
@@ -164,8 +161,8 @@
      * size.
      */
     @Test
-    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
     public void testRegionUnion_edgeDragResizeDisabled_containsFineCorners() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
         Region region = new Region();
         GEOMETRY.union(region);
         final int cornerRadius = DragResizeWindowGeometry.DEBUG
@@ -176,16 +173,16 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
     public void testCalculateControlType_edgeDragResizeEnabled_edges() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
         // The input source (touch or cursor) shouldn't impact the edge resize size.
         validateCtrlTypeForEdges(/* isTouch= */ false);
         validateCtrlTypeForEdges(/* isTouch= */ true);
     }
 
     @Test
-    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
     public void testCalculateControlType_edgeDragResizeDisabled_edges() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
         // Edge resizing is not supported when the flag is disabled.
         validateCtrlTypeForEdges(/* isTouch= */ false);
         validateCtrlTypeForEdges(/* isTouch= */ false);
@@ -203,8 +200,8 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
     public void testCalculateControlType_edgeDragResizeEnabled_corners() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
         final TestPoints fineTestPoints = new TestPoints(TASK_SIZE, FINE_CORNER_SIZE / 2);
         final TestPoints largeCornerTestPoints = new TestPoints(TASK_SIZE, LARGE_CORNER_SIZE / 2);
 
@@ -226,8 +223,8 @@
     }
 
     @Test
-    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
     public void testCalculateControlType_edgeDragResizeDisabled_corners() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE);
         final TestPoints fineTestPoints = new TestPoints(TASK_SIZE, FINE_CORNER_SIZE / 2);
         final TestPoints largeCornerTestPoints = new TestPoints(TASK_SIZE, LARGE_CORNER_SIZE / 2);
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryParameterizedTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryParameterizedTests.kt
new file mode 100644
index 0000000..a9fddc6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryParameterizedTests.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor
+
+import android.content.Context
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import java.util.function.Consumer
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameter
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+/**
+ * Tests for {@link ResizeHandleSizeRepository}.
+ *
+ * Build/Install/Run: atest WMShellUnitTests:ResizeHandleSizeRepositoryParameterizedTests
+ */
+@SmallTest
+@RunWith(Parameterized::class)
+class ResizeHandleSizeRepositoryParameterizedTests {
+    private val resources = ApplicationProvider.getApplicationContext<Context>().resources
+    private val resizeHandleSizeRepository = ResizeHandleSizeRepository()
+    @Mock private lateinit var mockSizeChangeFunctionOne: Consumer<ResizeHandleSizeRepository>
+    @Mock private lateinit var mockSizeChangeFunctionTwo: Consumer<ResizeHandleSizeRepository>
+
+    @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+    @Parameter(0) lateinit var name: String
+    // The current ResizeHandleSizeRepository API under test.
+
+    @Parameter(1) lateinit var operation: (ResizeHandleSizeRepository) -> Unit
+
+    @Before
+    fun setOverrideBeforeResetResizeHandle() {
+        MockitoAnnotations.initMocks(this)
+        if (name != "reset") return
+        val originalEdgeHandle =
+            resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources)
+        resizeHandleSizeRepository.setResizeEdgeHandlePixels(originalEdgeHandle + 2)
+    }
+
+    companion object {
+        @Parameters(name = "{index}: {0}")
+        @JvmStatic
+        fun data(): Iterable<Array<Any>> {
+            return listOf(
+                arrayOf(
+                    "reset",
+                    { sizeRepository: ResizeHandleSizeRepository ->
+                        sizeRepository.resetResizeEdgeHandlePixels()
+                    }
+                ),
+                arrayOf(
+                    "set",
+                    { sizeRepository: ResizeHandleSizeRepository ->
+                        sizeRepository.setResizeEdgeHandlePixels(99)
+                    }
+                )
+            )
+        }
+    }
+
+    // =================
+    // Validate that listeners are notified correctly for reset resize handle API.
+    // =================
+
+    @Test
+    fun testUpdateResizeHandleSize_flagDisabled() {
+        setFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        registerSizeChangeFunctions()
+        operation.invoke(resizeHandleSizeRepository)
+        // Nothing is notified since flag is disabled.
+        verify(mockSizeChangeFunctionOne, never()).accept(any())
+        verify(mockSizeChangeFunctionTwo, never()).accept(any())
+    }
+
+    @Test
+    fun testUpdateResizeHandleSize_flagEnabled_noListeners() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        operation.invoke(resizeHandleSizeRepository)
+        // Nothing is notified since nothing was registered.
+        verify(mockSizeChangeFunctionOne, never()).accept(any())
+        verify(mockSizeChangeFunctionTwo, never()).accept(any())
+    }
+
+    @Test
+    fun testUpdateResizeHandleSize_flagEnabled_listenersNotified() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        registerSizeChangeFunctions()
+        operation.invoke(resizeHandleSizeRepository)
+        // Functions notified when reset.
+        verify(mockSizeChangeFunctionOne).accept(any())
+        verify(mockSizeChangeFunctionTwo).accept(any())
+    }
+
+    @Test
+    fun testUpdateResizeHandleSize_flagEnabled_listenerFails() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        registerSizeChangeFunctions()
+        operation.invoke(resizeHandleSizeRepository)
+        // Functions notified when reset.
+        verify(mockSizeChangeFunctionOne).accept(any())
+        verify(mockSizeChangeFunctionTwo).accept(any())
+    }
+
+    @Test
+    fun testUpdateResizeHandleSize_flagEnabled_ignoreSecondListener() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        registerSizeChangeFunctions()
+        val extraConsumerMock = mock(Consumer::class.java) as Consumer<ResizeHandleSizeRepository>
+        resizeHandleSizeRepository.registerSizeChangeFunction(extraConsumerMock)
+        // First listener succeeds, second one that fails is ignored.
+        operation.invoke(resizeHandleSizeRepository)
+        // Functions notified when reset.
+        verify(mockSizeChangeFunctionOne).accept(any())
+        verify(mockSizeChangeFunctionTwo).accept(any())
+        verify(extraConsumerMock).accept(any())
+    }
+
+    private fun registerSizeChangeFunctions() {
+        resizeHandleSizeRepository.registerSizeChangeFunction(mockSizeChangeFunctionOne)
+        resizeHandleSizeRepository.registerSizeChangeFunction(mockSizeChangeFunctionTwo)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryTests.kt
new file mode 100644
index 0000000..59bbc72
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/ResizeHandleSizeRepositoryTests.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor
+
+import android.content.Context
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Tests for {@link ResizeHandleSizeRepository}. Validate that get/reset/set work correctly.
+ *
+ * Build/Install/Run: atest WMShellUnitTests:ResizeHandleSizeRepositoryTests
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ResizeHandleSizeRepositoryTests {
+    private val resources = ApplicationProvider.getApplicationContext<Context>().resources
+    private val resizeHandleSizeRepository = ResizeHandleSizeRepository()
+
+    @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+    @Test
+    fun testOverrideResizeEdgeHandlePixels_flagEnabled_resetSucceeds() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        // Reset does nothing when no override is set.
+        val originalEdgeHandle =
+            resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources)
+        resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+        assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+            .isEqualTo(originalEdgeHandle)
+
+        // Now try to set the value; reset should succeed.
+        resizeHandleSizeRepository.setResizeEdgeHandlePixels(originalEdgeHandle + 2)
+        resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+        assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+            .isEqualTo(originalEdgeHandle)
+    }
+
+    @Test
+    fun testOverrideResizeEdgeHandlePixels_flagDisabled_resetFails() {
+        setFlagsRule.disableFlags(Flags.FLAG_ENABLE_WINDOWING_EDGE_DRAG_RESIZE)
+        // Reset does nothing when no override is set.
+        val originalEdgeHandle =
+            resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources)
+        resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+        assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+            .isEqualTo(originalEdgeHandle)
+
+        // Now try to set the value; reset should do nothing.
+        val newEdgeHandle = originalEdgeHandle + 2
+        resizeHandleSizeRepository.setResizeEdgeHandlePixels(newEdgeHandle)
+        resizeHandleSizeRepository.resetResizeEdgeHandlePixels()
+        assertThat(resizeHandleSizeRepository.getResizeEdgeHandlePixels(resources))
+            .isEqualTo(originalEdgeHandle)
+    }
+}
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
index 0417533..473094c 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/mappers/CredentialSelectorUiStateGetMapper.kt
@@ -22,6 +22,7 @@
 import com.android.credentialmanager.CredentialSelectorUiState.Get.MultipleEntry.PerUserNameEntries
 import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.model.get.CredentialEntryInfo
+import java.time.Instant
 
 fun Request.Get.toGet(isPrimary: Boolean): CredentialSelectorUiState.Get {
     val accounts = providerInfos
@@ -67,4 +68,4 @@
 val comparator = compareBy<CredentialEntryInfo> { entryInfo ->
     // Passkey type always go first
     entryInfo.credentialType.let { if (it == CredentialType.PASSKEY) 0 else 1 }
-}.thenByDescending { it.lastUsedTimeMillis ?: 0 }
+}.thenByDescending { it.lastUsedTimeMillis ?: Instant.EPOCH }
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
new file mode 100644
index 0000000..eda7daa
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_preference_category_no_title.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:baselineAligned="false"
+    android:layout_marginTop="16dp">
+</LinearLayout>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 6e9bde4..8276e18 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -29,36 +29,46 @@
 import kotlinx.coroutines.flow.map
 
 interface IAppOpsController {
-    val mode: Flow<Int>
+    val modeFlow: Flow<Int>
     val isAllowed: Flow<Boolean>
-        get() = mode.map { it == MODE_ALLOWED }
+        get() = modeFlow.map { it == MODE_ALLOWED }
 
     fun setAllowed(allowed: Boolean)
 
     @Mode fun getMode(): Int
 }
 
+data class AppOps(
+    val op: Int,
+    val modeForNotAllowed: Int = MODE_ERRORED,
+
+    /**
+     * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed.
+     *
+     * Security or privacy related app-ops should be set with setUidMode() instead of setMode().
+     */
+    val setModeByUid: Boolean = false,
+)
+
 class AppOpsController(
     context: Context,
     private val app: ApplicationInfo,
-    private val op: Int,
-    private val modeForNotAllowed: Int = MODE_ERRORED,
-    private val setModeByUid: Boolean = false,
+    private val appOps: AppOps,
 ) : IAppOpsController {
     private val appOpsManager = context.appOpsManager
     private val packageManager = context.packageManager
-    override val mode = appOpsManager.opModeFlow(op, app)
+    override val modeFlow = appOpsManager.opModeFlow(appOps.op, app)
 
     override fun setAllowed(allowed: Boolean) {
-        val mode = if (allowed) MODE_ALLOWED else modeForNotAllowed
+        val mode = if (allowed) MODE_ALLOWED else appOps.modeForNotAllowed
 
-        if (setModeByUid) {
-            appOpsManager.setUidMode(op, app.uid, mode)
+        if (appOps.setModeByUid) {
+            appOpsManager.setUidMode(appOps.op, app.uid, mode)
         } else {
-            appOpsManager.setMode(op, app.uid, app.packageName, mode)
+            appOpsManager.setMode(appOps.op, app.uid, app.packageName, mode)
         }
 
-        val permission = AppOpsManager.opToPermission(op)
+        val permission = AppOpsManager.opToPermission(appOps.op)
         if (permission != null) {
             packageManager.updatePermissionFlags(permission, app.packageName,
                     PackageManager.FLAG_PERMISSION_USER_SET,
@@ -67,5 +77,6 @@
         }
     }
 
-    @Mode override fun getMode(): Int = appOpsManager.getOpMode(op, app)
+    @Mode
+    override fun getMode(): Int = appOpsManager.getOpMode(appOps.op, app)
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
index 5db5eae..37b1d73 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -23,6 +23,7 @@
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.settingslib.spa.framework.util.asyncMapItem
 import com.android.settingslib.spa.framework.util.filterItem
+import com.android.settingslib.spaprivileged.model.app.AppOps
 import com.android.settingslib.spaprivileged.model.app.AppOpsController
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.IAppOpsController
@@ -44,11 +45,11 @@
     private val packageManagers: IPackageManagers = PackageManagers,
 ) : TogglePermissionAppListModel<AppOpPermissionRecord> {
 
-    abstract val appOp: Int
+    abstract val appOps: AppOps
     abstract val permission: String
 
     override val enhancedConfirmationKey: String?
-        get() = AppOpsManager.opToPublicName(appOp)
+        get() = AppOpsManager.opToPublicName(appOps.op)
 
     /**
      * When set, specifies the broader permission who trumps the [permission].
@@ -65,27 +66,12 @@
      */
     open val permissionHasAppOpFlag: Boolean = true
 
-    open val modeForNotAllowed: Int = AppOpsManager.MODE_ERRORED
-
-    /**
-     * Use AppOpsManager#setUidMode() instead of AppOpsManager#setMode() when set allowed.
-     *
-     * Security or privacy related app-ops should be set with setUidMode() instead of setMode().
-     */
-    open val setModeByUid = false
-
     /** These not changeable packages will also be hidden from app list. */
     private val notChangeablePackages =
         setOf("android", "com.android.systemui", context.packageName)
 
     private fun createAppOpsController(app: ApplicationInfo) =
-        AppOpsController(
-            context = context,
-            app = app,
-            op = appOp,
-            setModeByUid = setModeByUid,
-            modeForNotAllowed = modeForNotAllowed,
-        )
+        AppOpsController(context, app, appOps)
 
     private fun createRecord(
         app: ApplicationInfo,
@@ -166,7 +152,7 @@
         return { true }
     }
 
-    val mode = appOpsController.mode.collectAsStateWithLifecycle(initialValue = null)
+    val mode = appOpsController.modeFlow.collectAsStateWithLifecycle(initialValue = null)
     return {
         when (mode.value) {
             null -> null
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
index 91bbd9f..74a7c14 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
@@ -27,16 +27,14 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spaprivileged.framework.common.appOpsManager
 import com.google.common.truth.Truth.assertThat
-import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Spy
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
-import org.mockito.kotlin.any
-import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
@@ -44,28 +42,18 @@
 class AppOpsControllerTest {
     @get:Rule val mockito: MockitoRule = MockitoJUnit.rule()
 
-    @Spy private val context: Context = ApplicationProvider.getApplicationContext()
+    private val appOpsManager = mock<AppOpsManager>()
 
-    @Mock private lateinit var appOpsManager: AppOpsManager
+    private val packageManager = mock<PackageManager>()
 
-    @Mock private lateinit var packageManager: PackageManager
-
-    @Before
-    fun setUp() {
-        whenever(context.appOpsManager).thenReturn(appOpsManager)
-        whenever(context.packageManager).thenReturn(packageManager)
-        doNothing().whenever(packageManager)
-                .updatePermissionFlags(any(), any(), any(), any(), any())
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { appOpsManager } doReturn appOpsManager
+        on { packageManager } doReturn packageManager
     }
 
     @Test
     fun setAllowed_setToTrue() {
-        val controller =
-            AppOpsController(
-                context = context,
-                app = APP,
-                op = OP,
-            )
+        val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
 
         controller.setAllowed(true)
 
@@ -74,12 +62,7 @@
 
     @Test
     fun setAllowed_setToFalse() {
-        val controller =
-            AppOpsController(
-                context = context,
-                app = APP,
-                op = OP,
-            )
+        val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
 
         controller.setAllowed(false)
 
@@ -88,13 +71,11 @@
 
     @Test
     fun setAllowed_setToFalseWithModeForNotAllowed() {
-        val controller =
-            AppOpsController(
-                context = context,
-                app = APP,
-                op = OP,
-                modeForNotAllowed = MODE_IGNORED,
-            )
+        val controller = AppOpsController(
+            context = context,
+            app = APP,
+            appOps = AppOps(op = OP, modeForNotAllowed = MODE_IGNORED),
+        )
 
         controller.setAllowed(false)
 
@@ -103,13 +84,11 @@
 
     @Test
     fun setAllowed_setToTrueByUid() {
-        val controller =
-            AppOpsController(
-                context = context,
-                app = APP,
-                op = OP,
-                setModeByUid = true,
-            )
+        val controller = AppOpsController(
+            context = context,
+            app = APP,
+            appOps = AppOps(op = OP, setModeByUid = true),
+        )
 
         controller.setAllowed(true)
 
@@ -118,13 +97,11 @@
 
     @Test
     fun setAllowed_setToFalseByUid() {
-        val controller =
-            AppOpsController(
-                context = context,
-                app = APP,
-                op = OP,
-                setModeByUid = true,
-            )
+        val controller = AppOpsController(
+            context = context,
+            app = APP,
+            appOps = AppOps(op = OP, setModeByUid = true),
+        )
 
         controller.setAllowed(false)
 
@@ -135,12 +112,7 @@
     fun getMode() {
         whenever(appOpsManager.checkOpNoThrow(OP, APP.uid, APP.packageName))
             .thenReturn(MODE_ALLOWED)
-        val controller =
-            AppOpsController(
-                context = context,
-                app = APP,
-                op = OP,
-            )
+        val controller = AppOpsController(context = context, app = APP, appOps = AppOps(OP))
 
         val mode = controller.getMode()
 
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
index bb25cf3..07ccdd5 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
@@ -25,6 +25,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
 import com.android.settingslib.spaprivileged.framework.common.appOpsManager
+import com.android.settingslib.spaprivileged.model.app.AppOps
 import com.android.settingslib.spaprivileged.model.app.IAppOpsController
 import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.test.R
@@ -39,7 +40,6 @@
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
-import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
@@ -287,16 +287,6 @@
         assertThat(appOpsController.setAllowedCalledWith).isTrue()
     }
 
-    @Test
-    fun setAllowed_setModeByUid() {
-        listModel.setModeByUid = true
-        val record = listModel.transformItem(APP)
-
-        listModel.setAllowed(record = record, newAllowed = true)
-
-        verify(appOpsManager).setUidMode(listModel.appOp, APP.uid, AppOpsManager.MODE_ALLOWED)
-    }
-
     private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
         lateinit var isAllowedState: () -> Boolean?
         composeTestRule.setContent { isAllowedState = listModel.isAllowed(record) }
@@ -309,11 +299,9 @@
         override val switchTitleResId = R.string.test_app_op_permission_switch_title
         override val footerResId = R.string.test_app_op_permission_footer
 
-        override val appOp = AppOpsManager.OP_MANAGE_MEDIA
+        override val appOps = AppOps(AppOpsManager.OP_MANAGE_MEDIA)
         override val permission = PERMISSION
         override var broaderPermission: String? = null
-
-        override var setModeByUid = false
     }
 
     private companion object {
@@ -329,7 +317,7 @@
 private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
     var setAllowedCalledWith: Boolean? = null
 
-    override val mode = flowOf(fakeMode)
+    override val modeFlow = flowOf(fakeMode)
 
     override fun setAllowed(allowed: Boolean) {
         setAllowedCalledWith = allowed
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 4ea7460..363045e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -214,6 +214,10 @@
     <string name="bluetooth_battery_level_untethered_left">Left: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery</string>
     <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the right part of the untethered headset. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_battery_level_untethered_right">Right: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected, showing remote device battery level for the left part of the untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="tv_bluetooth_battery_level_untethered_left">Left <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
+    <!-- Connected devices settings. Message when Bluetooth is connected, showing remote device battery level for the right part of the untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="tv_bluetooth_battery_level_untethered_right">Right <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
     <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_active_no_battery_level">Active</string>
     <!-- Connected devices settings. Message shown when bluetooth device is disconnected but is a known, previously connected device [CHAR LIMIT=NONE] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index c2a83b1..0fec61c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1532,7 +1532,7 @@
             // the left.
             if (leftBattery >= 0) {
                 String left = res.getString(
-                        R.string.bluetooth_battery_level_untethered_left,
+                        R.string.tv_bluetooth_battery_level_untethered_left,
                         Utils.formatPercentage(leftBattery));
                 addBatterySpan(spannableBuilder, left, isBatteryLow(leftBattery,
                                 BluetoothDevice.METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD),
@@ -1543,7 +1543,7 @@
                     spannableBuilder.append(" ");
                 }
                 String right = res.getString(
-                        R.string.bluetooth_battery_level_untethered_right,
+                        R.string.tv_bluetooth_battery_level_untethered_right,
                         Utils.formatPercentage(rightBattery));
                 addBatterySpan(spannableBuilder, right, isBatteryLow(rightBattery,
                                 BluetoothDevice.METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD),
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 b9bf9ca..0d81494 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
@@ -780,9 +780,8 @@
         mBatteryLevel = 10;
 
         // Act & Assert:
-        //   Get "Left: 10% battery" result with Battery Level 10.
-        assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
-                "Left: 10% battery");
+        //   Get "Left 10%" result with Battery Level 10.
+        assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Left 10%");
     }
 
     @Test
@@ -815,9 +814,9 @@
         mBatteryLevel = 10;
 
         // Act & Assert:
-        //   Get "Left: 10% battery" result with Battery Level 10.
+        //   Get "Left 10%" result with Battery Level 10.
         assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
-                "Left: 10% battery");
+                "Left 10%");
     }
 
     @Test
@@ -925,9 +924,9 @@
         mBatteryLevel = 10;
 
         // Act & Assert:
-        //   Get "Left: 10% battery Right: 10% battery" result with Battery Level 10.
+        //   Get "Left 10% Right 10%" result with Battery Level 10.
         assertThat(mCachedDevice.getTvConnectionSummary().toString())
-                .isEqualTo("Left: 10% battery Right: 10% battery");
+                .isEqualTo("Left 10% Right 10%");
     }
 
     @Test
@@ -1226,7 +1225,7 @@
                 TWS_BATTERY_RIGHT.getBytes());
 
         assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo(
-                "Left: 15% battery Right: 25% battery");
+                "Left 15% Right 25%");
     }
 
     @Test
@@ -1262,11 +1261,7 @@
                 TWS_BATTERY_RIGHT.getBytes());
 
         assertThat(mCachedDevice.getTvConnectionSummary().toString())
-                .isEqualTo(
-                        mContext.getString(R.string.bluetooth_battery_level_untethered_left, "15%")
-                                + " "
-                                + mContext.getString(
-                                        R.string.bluetooth_battery_level_untethered_right, "25%"));
+                .isEqualTo("Left 15% Right 25%");
     }
 
     @Test
@@ -1283,10 +1278,8 @@
                 .thenReturn(TWS_BATTERY_RIGHT.getBytes());
 
         int lowBatteryColor = mContext.getColor(LOW_BATTERY_COLOR);
-        String leftBattery =
-                mContext.getString(R.string.bluetooth_battery_level_untethered_left, "15%");
-        String rightBattery =
-                mContext.getString(R.string.bluetooth_battery_level_untethered_right, "25%");
+        String leftBattery = "Left 15%";
+        String rightBattery = "Right 25%";
 
         // Default low battery threshold, only left battery is low
         CharSequence summary = mCachedDevice.getTvConnectionSummary(LOW_BATTERY_COLOR);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index d2ca112..8b60ed0 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -87,6 +87,52 @@
         "tests/src/**/systemui/util/sensors/AsyncManagerTest.java",
         "tests/src/**/systemui/util/sensors/ThresholdSensorImplTest.java",
         "tests/src/**/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java",
+        "tests/src/**/systemui/statusbar/KeyboardShortcutListSearchTest.java",
+        "tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java",
+        "tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt",
+        "tests/src/**/systemui/statusbar/notification/AssistantFeedbackControllerTest.java",
+        "tests/src/**/systemui/statusbar/notification/collection/NotifCollectionTest.java",
+        "tests/src/**/systemui/statusbar/notification/collection/NotificationEntryTest.java",
+        "tests/src/**/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt",
+        "tests/src/**/systemui/statusbar/notification/collection/ShadeListBuilderTest.java",
+        "tests/src/**/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java",
+        "tests/src/**/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java",
+        "tests/src/**/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt",
+        "tests/src/**/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt",
+        "tests/src/**/systemui/statusbar/NotificationLockscreenUserManagerTest.java",
+        "tests/src/**/systemui/statusbar/notification/logging/NotificationLoggerTest.java",
+        "tests/src/**/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java",
+        "tests/src/**/systemui/statusbar/notification/row/NotificationContentInflaterTest.java",
+        "tests/src/**/systemui/statusbar/notification/row/NotificationContentViewTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/NotificationConversationInfoTest.java",
+        "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerTest.java",
+        "tests/src/**/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt",
+        "tests/src/**/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt",
+        "tests/src/**/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java",
+        "tests/src/**/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java",
+        "tests/src/**/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt",
+        "tests/src/**/systemui/statusbar/phone/AutoTileManagerTest.java",
+        "tests/src/**/systemui/statusbar/phone/CentralSurfacesImplTest.java",
+        "tests/src/**/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java",
+        "tests/src/**/systemui/statusbar/phone/PhoneStatusBarTransitionsTest.kt",
+        "tests/src/**/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt",
+        "tests/src/**/systemui/statusbar/phone/PhoneStatusBarView.java",
+        "tests/src/**/systemui/statusbar/phone/PhoneStatusBarViewTest.kt",
+        "tests/src/**/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt",
+        "tests/src/**/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileViewTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt",
+        "tests/src/**/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt",
+        "tests/src/**/systemui/statusbar/policy/CallbackControllerTest.java",
+        "tests/src/**/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java",
+        "tests/src/**/systemui/statusbar/policy/InflatedSmartRepliesTest.java",
+        "tests/src/**/systemui/statusbar/policy/LocationControllerImplTest.java",
+        "tests/src/**/systemui/statusbar/policy/RemoteInputViewTest.java",
+        "tests/src/**/systemui/statusbar/policy/SmartReplyViewTest.java",
+        "tests/src/**/systemui/statusbar/StatusBarStateControllerImplTest.kt",
     ],
 }
 
diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig
index 755fe2a..55edff6 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -4,6 +4,13 @@
 # NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
 
 flag {
+    name: "create_windowless_window_magnifier"
+    namespace: "accessibility"
+    description: "Uses SurfaceControlViewHost to create the magnifier for window magnification."
+    bug: "280992417"
+}
+
+flag {
     name: "delay_show_magnification_button"
     namespace: "accessibility"
     description: "Delays the showing of magnification mode switch button."
@@ -66,8 +73,11 @@
 }
 
 flag {
-    name: "create_windowless_window_magnifier"
+    name: "save_and_restore_magnification_settings_buttons"
     namespace: "accessibility"
-    description: "Uses SurfaceControlViewHost to create the magnifier for window magnification."
-    bug: "280992417"
+    description: "Saves the selected button status in magnification settings and restore the status when revisiting the same smallest screen DP."
+    bug: "325567876"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 10ba7bd..f3e2272 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -26,14 +26,6 @@
 }
 
 flag {
-
-    name: "notification_heads_up_cycling"
-    namespace: "systemui"
-    description: "Heads-up notification cycling animation for the Notification Avalanche feature."
-    bug: "316404716"
-}
-
-flag {
    name: "priority_people_section"
    namespace: "systemui"
    description: "Add a new section for priority people (aka important conversations)."
@@ -422,6 +414,13 @@
 }
 
 flag {
+   name: "confine_notification_touch_to_view_width"
+   namespace: "systemui"
+   description: "Use notification view width when detecting gestures."
+   bug: "335828150"
+}
+
+flag {
   name: "fix_image_wallpaper_crash_surface_already_released"
   namespace: "systemui"
   description: "Make sure ImageWallpaper doesn't return from OnSurfaceDestroyed until any drawing is finished"
@@ -976,3 +975,13 @@
   description: "Shows a vertical bar at the right edge to indicate the user can swipe to open the glanceable hub"
   bug: "339667383"
 }
+
+flag {
+   name: "register_wallpaper_notifier_background"
+   namespace: "systemui"
+   description: "Decide whether to register wallpaper change broadcast receiver on background executor."
+   bug: "327315860"
+   metadata {
+     purpose: PURPOSE_BUGFIX
+   }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index d109988..54a98dd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -69,7 +69,7 @@
 
 private fun SceneScope.stateForQuickSettingsContent(
     isSplitShade: Boolean,
-    squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default
+    squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default }
 ): QSSceneAdapter.State {
     return when (val transitionState = layoutState.transitionState) {
         is TransitionState.Idle -> {
@@ -125,9 +125,9 @@
     heightProvider: () -> Int,
     isSplitShade: Boolean,
     modifier: Modifier = Modifier,
-    squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default,
+    squishiness: () -> Float = { QuickSettings.SharedValues.SquishinessValues.Default },
 ) {
-    val contentState = stateForQuickSettingsContent(isSplitShade, squishiness)
+    val contentState = { stateForQuickSettingsContent(isSplitShade, squishiness) }
     val transitionState = layoutState.transitionState
     val isClosing =
         transitionState is TransitionState.Transition &&
@@ -161,7 +161,7 @@
 @Composable
 private fun QuickSettingsContent(
     qsSceneAdapter: QSSceneAdapter,
-    state: QSSceneAdapter.State,
+    state: () -> QSSceneAdapter.State,
     modifier: Modifier = Modifier,
 ) {
     val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle(null)
@@ -185,10 +185,10 @@
                 AndroidView(
                     modifier = Modifier.fillMaxWidth(),
                     factory = { _ ->
-                        qsSceneAdapter.setState(state)
+                        qsSceneAdapter.setState(state())
                         view
                     },
-                    update = { qsSceneAdapter.setState(state) }
+                    update = { qsSceneAdapter.setState(state()) }
                 )
             }
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index a0278a6..9d689fc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -279,7 +279,7 @@
                                     viewModel.qsSceneAdapter,
                                     { viewModel.qsSceneAdapter.qqsHeight },
                                     isSplitShade = false,
-                                    squishiness = tileSquishiness,
+                                    squishiness = { tileSquishiness },
                                 )
                             }
 
@@ -468,7 +468,7 @@
                                     heightProvider = { viewModel.qsSceneAdapter.qsHeight },
                                     isSplitShade = true,
                                     modifier = Modifier.fillMaxWidth(),
-                                    squishiness = tileSquishiness,
+                                    squishiness = { tileSquishiness },
                                 )
                             }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt
index ca824cb..5757f67 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/NightDisplayRepositoryTest.kt
@@ -42,7 +42,6 @@
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers
@@ -90,11 +89,6 @@
             locationController,
         )
 
-    @Before
-    fun setup() {
-        enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
-    }
-
     @Test
     fun nightDisplayState_matchesAutoMode() =
         scope.runTest {
@@ -126,6 +120,8 @@
     @Test
     fun nightDisplayState_matchesIsNightDisplayActivated() =
         scope.runTest {
+            enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
+
             val callbackCaptor = argumentCaptor<NightDisplayListener.Callback>()
 
             val lastState by collectLastValue(underTest.nightDisplayState(testUser))
@@ -148,6 +144,7 @@
         scope.runTest {
             whenever(colorDisplayManager.nightDisplayAutoMode)
                 .thenReturn(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME)
+            enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
 
             val lastState by collectLastValue(underTest.nightDisplayState(testUser))
             runCurrent()
@@ -160,6 +157,7 @@
         scope.runTest {
             whenever(colorDisplayManager.nightDisplayAutoMode)
                 .thenReturn(ColorDisplayManager.AUTO_MODE_TWILIGHT)
+            enrollInForcedNightDisplayAutoMode(INITIALLY_FORCE_AUTO_MODE, testUser)
 
             val lastState by collectLastValue(underTest.nightDisplayState(testUser))
             runCurrent()
@@ -167,6 +165,24 @@
             assertThat(lastState!!.autoMode).isEqualTo(ColorDisplayManager.AUTO_MODE_TWILIGHT)
         }
 
+    /**
+     * When the value of the raw auto mode is missing the call to nightDisplayState should not crash
+     */
+    @Test
+    fun nightDisplayState_whenAutoModeSettingIsNotInitialized_loadsDataWithoutException() =
+        scope.runTest {
+            // only auto mode_available is set, and the raw auto_mode has nothing set
+            globalSettings.putString(
+                Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE,
+                NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE
+            )
+
+            val lastState by collectLastValue(underTest.nightDisplayState(testUser))
+            runCurrent()
+
+            assertThat(lastState!!.shouldForceAutoMode).isTrue()
+        }
+
     @Test
     fun nightDisplayState_matchesForceAutoMode() =
         scope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 766798c..83227e1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -204,14 +204,14 @@
         }
 
     @Test
-    fun isCommunalAvailable_whenDreaming_true() =
+    fun isCommunalAvailable_whenKeyguardShowing_true() =
         testScope.runTest {
             val isAvailable by collectLastValue(underTest.isCommunalAvailable)
             assertThat(isAvailable).isFalse()
 
             keyguardRepository.setIsEncryptedOrLockdown(false)
             userRepository.setSelectedUserInfo(mainUser)
-            keyguardRepository.setDreaming(true)
+            keyguardRepository.setKeyguardShowing(true)
 
             assertThat(isAvailable).isTrue()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
index c660ff3..afe7b8f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
@@ -257,7 +257,7 @@
             runCurrent()
             clearInvocations(qsImpl!!)
 
-            underTest.setState(QSSceneAdapter.State.UnsquishingQQS(squishiness))
+            underTest.setState(QSSceneAdapter.State.UnsquishingQQS { squishiness })
             with(qsImpl!!) {
                 verify(this).setQsVisible(true)
                 verify(this)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
index ebd65fd..63ce67c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
@@ -32,7 +32,7 @@
 
     @Test
     fun expanding_squishiness1() {
-        assertThat(QSSceneAdapter.State.Expanding(0.3f).squishiness).isEqualTo(1f)
+        assertThat(QSSceneAdapter.State.Expanding(0.3f).squishiness()).isEqualTo(1f)
     }
 
     @Test
@@ -51,14 +51,14 @@
     @Test
     fun unsquishingQQS_expansionSameAsQQS() {
         val squishiness = 0.6f
-        assertThat(QSSceneAdapter.State.UnsquishingQQS(squishiness).expansion)
+        assertThat(QSSceneAdapter.State.UnsquishingQQS { squishiness }.expansion)
             .isEqualTo(QSSceneAdapter.State.QQS.expansion)
     }
 
     @Test
     fun unsquishingQS_expansionSameAsQS() {
         val squishiness = 0.6f
-        assertThat(QSSceneAdapter.State.UnsquishingQS(squishiness).expansion)
+        assertThat(QSSceneAdapter.State.UnsquishingQS { squishiness }.expansion)
             .isEqualTo(QSSceneAdapter.State.QS.expansion)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
index dddf582..9a95274 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepositoryTest.kt
@@ -18,20 +18,13 @@
 
 import android.bluetooth.BluetoothDevice
 import android.net.Uri
+import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.settingslib.media.MediaDevice
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.android.systemui.volume.localMediaRepository
-import com.android.systemui.volume.localMediaRepositoryFactory
 import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
 import com.android.systemui.volume.panel.component.anc.sliceViewManager
 import com.google.common.truth.Truth.assertThat
@@ -41,10 +34,14 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 class AncSliceRepositoryTest : SysuiTestCase() {
 
     private val kosmos = testKosmos()
@@ -57,23 +54,23 @@
             val slice = FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
             whenever(sliceViewManager.bindSlice(any<Uri>())).thenReturn(slice)
 
-            underTest =
-                AncSliceRepositoryImpl(
-                    localMediaRepositoryFactory,
-                    testScope.testScheduler,
-                    testScope.testScheduler,
-                    sliceViewManager,
-                )
+            underTest = AncSliceRepositoryImpl(testScope.testScheduler, sliceViewManager)
         }
     }
 
     @Test
-    fun noConnectedDevice_noSlice() {
+    fun connectedDevice_noUri_noSlice() {
         with(kosmos) {
             testScope.runTest {
-                localMediaRepository.updateCurrentConnectedDevice(null)
-
-                val slice by collectLastValue(underTest.ancSlice(1, false, false))
+                val slice by
+                    collectLastValue(
+                        underTest.ancSlice(
+                            device = createMediaDevice(""),
+                            width = 1,
+                            isCollapsed = false,
+                            hideLabel = false,
+                        )
+                    )
                 runCurrent()
 
                 assertThat(slice).isNull()
@@ -82,12 +79,18 @@
     }
 
     @Test
-    fun connectedDevice_sliceReturned() {
+    fun connectedDevice_hasUri_sliceReturned() {
         with(kosmos) {
             testScope.runTest {
-                localMediaRepository.updateCurrentConnectedDevice(createMediaDevice())
-
-                val slice by collectLastValue(underTest.ancSlice(1, false, false))
+                val slice by
+                    collectLastValue(
+                        underTest.ancSlice(
+                            device = createMediaDevice("content://test.slice"),
+                            width = 1,
+                            isCollapsed = false,
+                            hideLabel = false,
+                        )
+                    )
                 runCurrent()
 
                 assertThat(slice).isNotNull()
@@ -95,21 +98,13 @@
         }
     }
 
-    private fun createMediaDevice(sliceUri: String = "content://test.slice"): MediaDevice {
-        val bluetoothDevice: BluetoothDevice = mock {
-            whenever(getMetadata(any()))
-                .thenReturn(
-                    ("<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" +
-                            sliceUri +
-                            "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>")
-                        .toByteArray()
-                )
-        }
-        val cachedBluetoothDevice: CachedBluetoothDevice = mock {
-            whenever(device).thenReturn(bluetoothDevice)
-        }
-        return mock<BluetoothMediaDevice> {
-            whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
-        }
+    private fun createMediaDevice(sliceUri: String): BluetoothDevice = mock {
+        on { getMetadata(any()) }
+            .thenReturn(
+                ("<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" +
+                        sliceUri +
+                        "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>")
+                    .toByteArray()
+            )
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt
index 553aed8..8d052fe 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/AncAvailabilityCriteriaTest.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.volume.panel.component.anc.domain
 
+import android.media.AudioManager
 import android.net.Uri
+import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -26,10 +28,13 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.data.repository.audioRepository
+import com.android.systemui.volume.localMediaRepository
 import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
 import com.android.systemui.volume.panel.component.anc.ancSliceInteractor
 import com.android.systemui.volume.panel.component.anc.ancSliceRepository
 import com.android.systemui.volume.panel.component.anc.sliceViewManager
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.TestMediaDevicesFactory
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
@@ -41,6 +46,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 class AncAvailabilityCriteriaTest : SysuiTestCase() {
 
     private val kosmos = testKosmos()
@@ -74,6 +80,10 @@
     fun hasSlice_available() {
         with(kosmos) {
             testScope.runTest {
+                audioRepository.setMode(AudioManager.MODE_NORMAL)
+                localMediaRepository.updateCurrentConnectedDevice(
+                    TestMediaDevicesFactory.bluetoothMediaDevice()
+                )
                 ancSliceRepository.putSlice(
                     1,
                     FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
index 81e6ac4..741671e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractorTest.kt
@@ -16,15 +16,21 @@
 
 package com.android.systemui.volume.panel.component.anc.domain.interactor
 
+import android.media.AudioManager
+import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
+import com.android.systemui.volume.data.repository.audioRepository
+import com.android.systemui.volume.localMediaRepository
 import com.android.systemui.volume.panel.component.anc.FakeSliceFactory
+import com.android.systemui.volume.panel.component.anc.ancSliceInteractor
 import com.android.systemui.volume.panel.component.anc.ancSliceRepository
 import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.TestMediaDevicesFactory
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
@@ -36,6 +42,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
 class AncSliceInteractorTest : SysuiTestCase() {
 
     private val kosmos = testKosmos()
@@ -43,14 +50,12 @@
     private lateinit var underTest: AncSliceInteractor
 
     @Before
-    fun setup() {
-        with(kosmos) {
-            underTest = AncSliceInteractor(ancSliceRepository, testScope.backgroundScope)
-        }
+    fun setUp() {
+        underTest = kosmos.ancSliceInteractor
     }
 
     @Test
-    fun errorSlice_returnsNull() {
+    fun errorSlice_returnsUnavailable() {
         with(kosmos) {
             testScope.runTest {
                 ancSliceRepository.putSlice(
@@ -67,7 +72,7 @@
     }
 
     @Test
-    fun noSliceItem_returnsNull() {
+    fun noSliceItem_returnsUnavailable() {
         with(kosmos) {
             testScope.runTest {
                 ancSliceRepository.putSlice(
@@ -84,9 +89,31 @@
     }
 
     @Test
+    fun sliceItem_noError_noDevice_returnsUnavailable() {
+        with(kosmos) {
+            testScope.runTest {
+                ancSliceRepository.putSlice(
+                    1,
+                    FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
+                )
+
+                val slice by collectLastValue(underTest.ancSlices)
+                runCurrent()
+
+                assertThat(slice).isInstanceOf(AncSlices.Unavailable::class.java)
+            }
+        }
+    }
+
+    @Test
     fun sliceItem_noError_returnsSlice() {
         with(kosmos) {
             testScope.runTest {
+                audioRepository.setMode(AudioManager.MODE_NORMAL)
+                localMediaRepository.updateCurrentConnectedDevice(
+                    TestMediaDevicesFactory.bluetoothMediaDevice()
+                )
+
                 ancSliceRepository.putSlice(
                     1,
                     FakeSliceFactory.createSlice(hasError = false, hasSliceItem = true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
index 737b7f3..777240c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
@@ -19,13 +19,13 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.media.spatializerInteractor
-import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.domain.interactor.audioOutputInteractor
 import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
 
 val Kosmos.spatialAudioComponentInteractor by
     Kosmos.Fixture {
         SpatialAudioComponentInteractor(
-            mediaOutputInteractor,
+            audioOutputInteractor,
             spatializerInteractor,
             testScope.backgroundScope
         )
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
index e36ae60..c6c46fa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
@@ -29,7 +29,6 @@
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.spatializerInteractor
 import com.android.systemui.media.spatializerRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.mock
@@ -37,9 +36,9 @@
 import com.android.systemui.volume.localMediaController
 import com.android.systemui.volume.localMediaRepository
 import com.android.systemui.volume.mediaControllerRepository
-import com.android.systemui.volume.mediaOutputInteractor
 import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
 import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
+import com.android.systemui.volume.panel.component.spatial.spatialAudioComponentInteractor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
@@ -76,12 +75,7 @@
 
             mediaControllerRepository.setActiveSessions(listOf(localMediaController))
 
-            underTest =
-                SpatialAudioComponentInteractor(
-                    mediaOutputInteractor,
-                    spatializerInteractor,
-                    testScope.backgroundScope,
-                )
+            underTest = spatialAudioComponentInteractor
         }
     }
 
diff --git a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
index a30a122..c32acf2 100644
--- a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml
@@ -15,16 +15,10 @@
   -->
 <ripple xmlns:android="http://schemas.android.com/apk/res/android"
     android:color="@color/qs_tile_ripple_color">
-    <!-- We don't really use the ripple effect here, but changing it to LayerDrawable causes
-         performance regression, see: b/339412453.
-         Since this ripple has just one layer inside, we can try to remove that extra "background"
-         layer. However this should only be done when the flag
-         com.android.systemui.qs_tile_focus_state has completed all its stages and this drawable
-         fully replaces the previous one to ensure consistency with code sections searching for
-         specific ids in drawable hierarchy 
-         -->
     <item
-        android:id="@id/background">
+        android:id="@android:id/mask"
+        android:drawable="@drawable/qs_tile_background_shape" />
+    <item android:id="@id/background">
         <layer-list>
             <item
                 android:id="@+id/qs_tile_background_base"
@@ -32,22 +26,8 @@
             <item android:id="@+id/qs_tile_background_overlay">
                 <selector>
                     <item
-                        android:state_hovered="true"
-                        android:drawable="@drawable/qs_tile_background_shape" />
-                </selector>
-            </item>
-            <!-- In the layer below we have negative insets because we need the focus outline
-                 to draw outside the bounds, around the main background. We use 5dp because
-                 the outline stroke is 3dp and the required padding is 2dp.-->
-            <item
-                android:top="-5dp"
-                android:right="-5dp"
-                android:left="-5dp"
-                android:bottom="-5dp">
-                <selector>
-                    <item
-                        android:state_focused="true"
-                        android:drawable="@drawable/qs_tile_focused_background"/>
+                        android:drawable="@drawable/qs_tile_background_shape"
+                        android:state_hovered="true" />
                 </selector>
             </item>
         </layer-list>
diff --git a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
index fd456df..33f0d02 100644
--- a/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
+++ b/packages/SystemUI/res/drawable/qs_tile_focused_background.xml
@@ -13,10 +13,14 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:shape="rectangle">
-    <corners android:radius="30dp"/>
-    <stroke android:width="3dp" android:color="?androidprv:attr/materialColorSecondaryFixed"/>
-</shape>
\ No newline at end of file
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:inset="-5dp">
+    <shape xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:shape="rectangle">
+        <corners android:radius="30dp" />
+        <stroke
+            android:width="3dp"
+            android:color="?androidprv:attr/materialColorSecondaryFixed" />
+    </shape>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9d0319c..b960813 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -913,10 +913,6 @@
         obvious when corner radii differ.-->
     <dimen name="communal_enforced_rounded_corner_max_radius">28dp</dimen>
 
-    <!-- Width and height used to filter widgets displayed in the communal widget picker -->
-    <dimen name="communal_widget_picker_desired_width">360dp</dimen>
-    <dimen name="communal_widget_picker_desired_height">240dp</dimen>
-
     <!-- The width/height of the unlock icon view on keyguard. -->
     <dimen name="keyguard_lock_height">42dp</dimen>
     <dimen name="keyguard_lock_padding">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8da8316f..6df48a0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -765,7 +765,7 @@
     <!-- QuickSettings: Wifi secondary label shown when the wifi is being enabled [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_secondary_label_transient">Turning on&#8230;</string>
     <!-- QuickSettings: Cast title [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_cast_title">Screen Cast</string>
+    <string name="quick_settings_cast_title">Cast</string>
     <!-- QuickSettings: Cast detail panel, status text when casting [CHAR LIMIT=NONE] -->
     <string name="quick_settings_casting">Casting</string>
     <!-- QuickSettings: Cast detail panel, default device name [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index e66261c..5458ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -240,7 +240,7 @@
     private boolean mEditSizeEnable = false;
     private boolean mSettingsPanelVisibility = false;
     @VisibleForTesting
-    WindowMagnificationSizePrefs mWindowMagnificationSizePrefs;
+    WindowMagnificationFrameSizePrefs mWindowMagnificationFrameSizePrefs;
 
     @Nullable
     private final MirrorWindowControl mMirrorWindowControl;
@@ -270,7 +270,7 @@
         mSysUiState = sysUiState;
         mScvhSupplier = scvhSupplier;
         mConfiguration = new Configuration(context.getResources().getConfiguration());
-        mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext);
+        mWindowMagnificationFrameSizePrefs = new WindowMagnificationFrameSizePrefs(mContext);
 
         final Display display = mContext.getDisplay();
         mDisplayId = mContext.getDisplayId();
@@ -457,7 +457,7 @@
 
         if (!enable) {
             // Keep the magnifier size when exiting edit mode
-            mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(
+            mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(
                     new Size(mMagnificationFrame.width(), mMagnificationFrame.height()));
         }
     }
@@ -944,7 +944,7 @@
     }
 
     private void setMagnificationFrame(int width, int height, int centerX, int centerY) {
-        mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(new Size(width, height));
+        mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(new Size(width, height));
 
         // Sets the initial frame area for the mirror and place it to the given center on the
         // display.
@@ -954,11 +954,11 @@
     }
 
     private Size restoreMagnificationWindowFrameSizeIfPossible() {
-        if (!mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity()) {
+        if (!mWindowMagnificationFrameSizePrefs.isPreferenceSavedForCurrentDensity()) {
             return getDefaultMagnificationWindowFrameSize();
         }
 
-        return mWindowMagnificationSizePrefs.getSizeForCurrentDensity();
+        return mWindowMagnificationFrameSizePrefs.getSizeForCurrentDensity();
     }
 
     private Size getDefaultMagnificationWindowFrameSize() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java
rename to packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
index a401f2a..e83e85e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSizePrefs.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefs.java
@@ -23,14 +23,14 @@
 /**
  * Class to handle SharedPreference for window magnification size.
  */
-final class WindowMagnificationSizePrefs {
+final class WindowMagnificationFrameSizePrefs {
 
     private static final String WINDOW_MAGNIFICATION_PREFERENCES =
             "window_magnification_preferences";
     Context mContext;
     SharedPreferences mWindowMagnificationSizePreferences;
 
-    public WindowMagnificationSizePrefs(Context context) {
+    WindowMagnificationFrameSizePrefs(Context context) {
         mContext = context;
         mWindowMagnificationSizePreferences = mContext
                 .getSharedPreferences(WINDOW_MAGNIFICATION_PREFERENCES, Context.MODE_PRIVATE);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt
index bf44fab..b33746c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/NightDisplayRepository.kt
@@ -149,12 +149,7 @@
                 secureSettings
                     .observerFlow(userHandle.identifier, DISPLAY_AUTO_MODE_RAW_SETTING_NAME)
                     .onStart { emit(Unit) }
-                    .map {
-                        secureSettings.getIntForUser(
-                            DISPLAY_AUTO_MODE_RAW_SETTING_NAME,
-                            userHandle.identifier
-                        ) == NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET
-                    }
+                    .map { isNightDisplayAutoModeRawSettingNotSet(userHandle.identifier) }
             }
             .distinctUntilChanged()
 
@@ -179,12 +174,19 @@
             colorDisplayManager.nightDisplayCustomEndTime,
             globalSettings.getString(IS_FORCE_AUTO_MODE_AVAILABLE_SETTING_NAME) ==
                 NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE &&
-                secureSettings.getIntForUser(DISPLAY_AUTO_MODE_RAW_SETTING_NAME, user.identifier) ==
-                    NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET,
+                isNightDisplayAutoModeRawSettingNotSet(user.identifier),
             locationController.isLocationEnabled,
         )
     }
 
+    private fun isNightDisplayAutoModeRawSettingNotSet(userId: Int): Boolean {
+        return secureSettings.getIntForUser(
+            DISPLAY_AUTO_MODE_RAW_SETTING_NAME,
+            NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET,
+            userId
+        ) == NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET
+    }
+
     private companion object {
         const val NIGHT_DISPLAY_AUTO_MODE_RAW_NOT_SET = -1
         const val NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE = "1"
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
index 1f04599..d5e911e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuAnimationController.java
@@ -37,7 +37,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Flags;
 
 import java.util.HashMap;
 
@@ -339,15 +338,11 @@
         mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ true);
         final PointF position = mMenuView.getMenuPosition();
         final PointF tuckedPosition = getTuckedMenuPosition();
-        if (Flags.floatingMenuAnimatedTuck()) {
-            flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_X,
-                    Math.signum(tuckedPosition.x - position.x) * ESCAPE_VELOCITY,
-                    FLING_FRICTION_SCALAR,
-                    createDefaultSpringForce(),
-                    tuckedPosition.x);
-        } else {
-            moveToPosition(tuckedPosition);
-        }
+        flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_X,
+                Math.signum(tuckedPosition.x - position.x) * ESCAPE_VELOCITY,
+                FLING_FRICTION_SCALAR,
+                createDefaultSpringForce(),
+                tuckedPosition.x);
 
         // Keep the touch region let users could click extra space to pop up the menu view
         // from the screen edge
@@ -359,23 +354,19 @@
     void moveOutEdgeAndShow() {
         mMenuView.updateMenuMoveToTucked(/* isMoveToTucked= */ false);
 
-        if (Flags.floatingMenuAnimatedTuck()) {
-            PointF position = mMenuView.getMenuPosition();
-            springMenuWith(DynamicAnimation.TRANSLATION_X,
-                    createDefaultSpringForce(),
-                    0,
-                    position.x,
-                    true
-            );
-            springMenuWith(DynamicAnimation.TRANSLATION_Y,
-                    createDefaultSpringForce(),
-                    0,
-                    position.y,
-                    true
-            );
-        } else {
-            mMenuView.onPositionChanged();
-        }
+        PointF position = mMenuView.getMenuPosition();
+        springMenuWith(DynamicAnimation.TRANSLATION_X,
+                createDefaultSpringForce(),
+                0,
+                position.x,
+                true
+        );
+        springMenuWith(DynamicAnimation.TRANSLATION_Y,
+                createDefaultSpringForce(),
+                0,
+                position.y,
+                true
+        );
 
         mMenuView.onEdgeChangedIfNeeded();
     }
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 be75e10..9d9e7df 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -321,22 +321,6 @@
         if (mMoveToTuckedListener != null) {
             mMoveToTuckedListener.onMoveToTuckedChanged(isMoveToTucked);
         }
-
-        if (!Flags.floatingMenuAnimatedTuck()) {
-            if (isMoveToTucked) {
-                final float halfWidth = getMenuWidth() / 2.0f;
-                final boolean isOnLeftSide = mMenuAnimationController.isOnLeftSide();
-                final Rect clipBounds = new Rect(
-                        (int) (!isOnLeftSide ? 0 : halfWidth),
-                        0,
-                        (int) (!isOnLeftSide ? halfWidth : getMenuWidth()),
-                        getMenuHeight()
-                );
-                setClipBounds(clipBounds);
-            } else {
-                setClipBounds(null);
-            }
-        }
     }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 6dce1bb..0c67c50 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -322,9 +322,8 @@
         }
         addView(mMessageView, LayerIndex.MESSAGE_VIEW);
 
-        if (Flags.floatingMenuAnimatedTuck()) {
-            setClipChildren(true);
-        }
+        setClipChildren(true);
+
         setClickable(false);
         setFocusable(false);
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -476,10 +475,8 @@
             mMenuAnimationController.startTuckedAnimationPreview();
         }
 
-        if (Flags.floatingMenuAnimatedTuck()) {
-            if (!mMenuView.isMoveToTucked()) {
-                setClipBounds(null);
-            }
+        if (!mMenuView.isMoveToTucked()) {
+            setClipBounds(null);
         }
         mMenuView.onArrivalAtPosition(false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 298c0f7..b75b292 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -362,7 +362,7 @@
 
         mPromptSelectorInteractorProvider = promptSelectorInteractorProvider;
         mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId,
-                biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName,
+                getRequestId(), biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName,
                 false /*onSwitchToCredential*/);
 
         final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
@@ -436,7 +436,7 @@
                 addCredentialView(true, false);
             }
         } else {
-            mPromptSelectorInteractorProvider.get().resetPrompt();
+            mPromptSelectorInteractorProvider.get().resetPrompt(getRequestId());
         }
     }
 
@@ -884,7 +884,8 @@
         final Runnable endActionRunnable = () -> {
             setVisibility(View.INVISIBLE);
             if (Flags.customBiometricPrompt() && constraintBp()) {
-                mPromptSelectorInteractorProvider.get().resetPrompt();
+                // TODO(b/288175645): resetPrompt calls should be lifecycle aware
+                mPromptSelectorInteractorProvider.get().resetPrompt(getRequestId());
             }
             removeWindowIfAttached();
         };
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
index 58b238b..230b30b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.biometrics.data.repository
 
 import android.hardware.biometrics.PromptInfo
+import android.util.Log
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.biometrics.shared.model.PromptKind
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
@@ -49,6 +50,9 @@
     /** The user that the prompt is for. */
     val userId: StateFlow<Int?>
 
+    /** The request that the prompt is for. */
+    val requestId: StateFlow<Long?>
+
     /** The gatekeeper challenge, if one is associated with this prompt. */
     val challenge: StateFlow<Long?>
 
@@ -69,13 +73,14 @@
     fun setPrompt(
         promptInfo: PromptInfo,
         userId: Int,
+        requestId: Long,
         gatekeeperChallenge: Long?,
         kind: PromptKind,
         opPackageName: String,
     )
 
     /** Unset the prompt info. */
-    fun unsetPrompt()
+    fun unsetPrompt(requestId: Long)
 }
 
 @SysUISingleton
@@ -109,6 +114,9 @@
     private val _userId: MutableStateFlow<Int?> = MutableStateFlow(null)
     override val userId = _userId.asStateFlow()
 
+    private val _requestId: MutableStateFlow<Long?> = MutableStateFlow(null)
+    override val requestId = _requestId.asStateFlow()
+
     private val _promptKind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None)
     override val promptKind = _promptKind.asStateFlow()
 
@@ -132,23 +140,30 @@
     override fun setPrompt(
         promptInfo: PromptInfo,
         userId: Int,
+        requestId: Long,
         gatekeeperChallenge: Long?,
         kind: PromptKind,
         opPackageName: String,
     ) {
         _promptKind.value = kind
         _userId.value = userId
+        _requestId.value = requestId
         _challenge.value = gatekeeperChallenge
         _promptInfo.value = promptInfo
         _opPackageName.value = opPackageName
     }
 
-    override fun unsetPrompt() {
-        _promptInfo.value = null
-        _userId.value = null
-        _challenge.value = null
-        _promptKind.value = PromptKind.None
-        _opPackageName.value = null
+    override fun unsetPrompt(requestId: Long) {
+        if (requestId == _requestId.value) {
+            _promptInfo.value = null
+            _userId.value = null
+            _requestId.value = null
+            _challenge.value = null
+            _promptKind.value = PromptKind.None
+            _opPackageName.value = null
+        } else {
+            Log.w(TAG, "Ignoring unsetPrompt - requestId mismatch")
+        }
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index 4ba780f..dc338d0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -86,6 +86,7 @@
     fun setPrompt(
         promptInfo: PromptInfo,
         effectiveUserId: Int,
+        requestId: Long,
         modalities: BiometricModalities,
         challenge: Long,
         opPackageName: String,
@@ -93,7 +94,7 @@
     )
 
     /** Unset the current authentication request. */
-    fun resetPrompt()
+    fun resetPrompt(requestId: Long)
 }
 
 @SysUISingleton
@@ -161,6 +162,7 @@
         setPrompt(
             promptRepository.promptInfo.value!!,
             promptRepository.userId.value!!,
+            promptRepository.requestId.value!!,
             modalities,
             promptRepository.challenge.value!!,
             promptRepository.opPackageName.value!!,
@@ -171,6 +173,7 @@
     override fun setPrompt(
         promptInfo: PromptInfo,
         effectiveUserId: Int,
+        requestId: Long,
         modalities: BiometricModalities,
         challenge: Long,
         opPackageName: String,
@@ -198,13 +201,14 @@
         promptRepository.setPrompt(
             promptInfo = promptInfo,
             userId = effectiveUserId,
+            requestId = requestId,
             gatekeeperChallenge = challenge,
             kind = kind,
             opPackageName = opPackageName,
         )
     }
 
-    override fun resetPrompt() {
-        promptRepository.unsetPrompt()
+    override fun resetPrompt(requestId: Long) {
+        promptRepository.unsetPrompt(requestId)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 06c8396..9599a88 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -61,7 +61,6 @@
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.data.repository.SmartspaceRepository
 import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
-import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
 import com.android.systemui.util.kotlin.BooleanFlowOperators.not
 import com.android.systemui.util.kotlin.emitOnStart
 import javax.inject.Inject
@@ -130,7 +129,7 @@
         allOf(
                 communalSettingsInteractor.isCommunalEnabled,
                 not(keyguardInteractor.isEncryptedOrLockdown),
-                anyOf(keyguardInteractor.isKeyguardShowing, keyguardInteractor.isDreaming)
+                keyguardInteractor.isKeyguardShowing
             )
             .distinctUntilChanged()
             .onEach { available ->
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index f6122ad..650852c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -35,7 +35,6 @@
 import com.android.systemui.log.dagger.CommunalLog
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dagger.MediaModule
-import com.android.systemui.res.R
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.CoroutineDispatcher
@@ -96,6 +95,8 @@
         uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
     }
 
+    val isIdleOnCommunal: StateFlow<Boolean> = communalInteractor.isIdleOnCommunal
+
     /** Launch the widget picker activity using the given {@link ActivityResultLauncher}. */
     suspend fun onOpenWidgetPicker(
         resources: Resources,
@@ -136,14 +137,6 @@
         return Intent(Intent.ACTION_PICK).apply {
             setPackage(packageName)
             putExtra(
-                EXTRA_DESIRED_WIDGET_WIDTH,
-                resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width)
-            )
-            putExtra(
-                EXTRA_DESIRED_WIDGET_HEIGHT,
-                resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height)
-            )
-            putExtra(
                 AppWidgetManager.EXTRA_CATEGORY_FILTER,
                 communalSettingsInteractor.communalWidgetCategories.value
             )
@@ -168,8 +161,6 @@
     companion object {
         private const val TAG = "CommunalEditModeViewModel"
 
-        private const val EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width"
-        private const val EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height"
         private const val EXTRA_UI_SURFACE_KEY = "ui_surface"
         private const val EXTRA_UI_SURFACE_VALUE = "widgets_hub"
         const val EXTRA_ADDED_APP_WIDGETS_KEY = "added_app_widgets"
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index f20fafc..426f484 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -44,6 +44,7 @@
 import com.android.systemui.log.core.Logger
 import com.android.systemui.log.dagger.CommunalLog
 import javax.inject.Inject
+import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.launch
 
 /** An Activity for editing the widgets that appear in hub mode. */
@@ -69,6 +70,8 @@
 
     private var shouldOpenWidgetPickerOnStart = false
 
+    private var lockOnDestroy = false
+
     private val addWidgetActivityLauncher: ActivityResultLauncher<Intent> =
         registerForActivityResult(StartActivityForResult()) { result ->
             when (result.resultCode) {
@@ -149,15 +152,18 @@
     }
 
     private fun onEditDone() {
-        try {
+        lifecycleScope.launch {
             communalViewModel.changeScene(
                 CommunalScenes.Communal,
                 CommunalTransitionKeys.SimpleFade
             )
-            checkNotNull(windowManagerService).lockNow(/* options */ null)
+
+            // Wait for the current scene to be idle on communal.
+            communalViewModel.isIdleOnCommunal.first { it }
+            // Then finish the activity (this helps to avoid a flash of lockscreen when locking
+            // in onDestroy()).
+            lockOnDestroy = true
             finish()
-        } catch (e: RemoteException) {
-            Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
         }
     }
 
@@ -190,5 +196,15 @@
     override fun onDestroy() {
         super.onDestroy()
         communalViewModel.setEditModeOpen(false)
+
+        if (lockOnDestroy) lockNow()
+    }
+
+    private fun lockNow() {
+        try {
+            checkNotNull(windowManagerService).lockNow(/* options */ null)
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
index ee3706a..a0b25b9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndication.java
@@ -32,6 +32,8 @@
 public class KeyguardIndication {
     @Nullable
     private final CharSequence mMessage;
+    @Nullable
+    private final boolean mForceAccessibilityLiveRegionAssertive;
     @NonNull
     private final ColorStateList mTextColor;
     @Nullable
@@ -49,13 +51,15 @@
             Drawable icon,
             View.OnClickListener onClickListener,
             Drawable background,
-            Long minVisibilityMillis) {
+            Long minVisibilityMillis,
+            Boolean foceAssertive) {
         mMessage = message;
         mTextColor = textColor;
         mIcon = icon;
         mOnClickListener = onClickListener;
         mBackground = background;
         mMinVisibilityMillis = minVisibilityMillis;
+        mForceAccessibilityLiveRegionAssertive = foceAssertive;
     }
 
     /**
@@ -101,6 +105,15 @@
         return mMinVisibilityMillis;
     }
 
+
+    /**
+     * Whether to force the accessibility live region to be assertive.
+     */
+    public boolean getForceAssertiveAccessibilityLiveRegion() {
+        return mForceAccessibilityLiveRegionAssertive;
+    }
+
+
     @Override
     public String toString() {
         String str = "KeyguardIndication{";
@@ -109,6 +122,7 @@
         if (mOnClickListener != null) str += " mOnClickListener=" + mOnClickListener;
         if (mBackground != null) str += " mBackground=" + mBackground;
         if (mMinVisibilityMillis != null) str += " mMinVisibilityMillis=" + mMinVisibilityMillis;
+        if (mForceAccessibilityLiveRegionAssertive) str += "mForceAccessibilityLiveRegionAssertive";
         str += "}";
         return str;
     }
@@ -123,6 +137,7 @@
         private ColorStateList mTextColor;
         private Drawable mBackground;
         private Long mMinVisibilityMillis;
+        private boolean mForceAccessibilityLiveRegionAssertive;
 
         public Builder() { }
 
@@ -178,6 +193,14 @@
         }
 
         /**
+         * Optional. Can force the accessibility live region to be assertive for this message.
+         */
+        public Builder setForceAccessibilityLiveRegionAssertive() {
+            this.mForceAccessibilityLiveRegionAssertive = true;
+            return this;
+        }
+
+        /**
          * Build the KeyguardIndication.
          */
         public KeyguardIndication build() {
@@ -190,7 +213,7 @@
 
             return new KeyguardIndication(
                     mMessage, mTextColor, mIcon, mOnClickListener, mBackground,
-                    mMinVisibilityMillis);
+                    mMinVisibilityMillis, mForceAccessibilityLiveRegionAssertive);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 674c128..f9adc47 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -84,20 +84,25 @@
 import com.android.systemui.keyguard.ui.viewmodel.WindowManagerLockscreenVisibilityViewModel;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.power.shared.model.ScreenPowerState;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.shared.model.Scenes;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.wm.shell.shared.CounterRotator;
 import com.android.wm.shell.shared.ShellTransitions;
 import com.android.wm.shell.shared.TransitionUtil;
 import com.android.wm.shell.transition.Transitions;
 
+import dagger.Lazy;
+
+import kotlinx.coroutines.CoroutineScope;
+
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.WeakHashMap;
 
 import javax.inject.Inject;
 
-import kotlinx.coroutines.CoroutineScope;
-
 public class KeyguardService extends Service {
     static final String TAG = "KeyguardService";
     static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
@@ -109,6 +114,7 @@
     private final ShellTransitions mShellTransitions;
     private final DisplayTracker mDisplayTracker;
     private final PowerInteractor mPowerInteractor;
+    private final Lazy<SceneInteractor> mSceneInteractorLazy;
 
     private static RemoteAnimationTarget[] wrap(TransitionInfo info, boolean wallpapers,
             SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap,
@@ -316,7 +322,8 @@
             @Application CoroutineScope scope,
             FeatureFlags featureFlags,
             PowerInteractor powerInteractor,
-            WindowManagerOcclusionManager windowManagerOcclusionManager) {
+            WindowManagerOcclusionManager windowManagerOcclusionManager,
+            Lazy<SceneInteractor> sceneInteractorLazy) {
         super();
         mKeyguardViewMediator = keyguardViewMediator;
         mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
@@ -325,6 +332,7 @@
         mDisplayTracker = displayTracker;
         mFlags = featureFlags;
         mPowerInteractor = powerInteractor;
+        mSceneInteractorLazy = sceneInteractorLazy;
 
         if (KeyguardWmStateRefactor.isEnabled()) {
             WindowManagerLockscreenVisibilityViewBinder.bind(
@@ -601,6 +609,10 @@
             trace("showDismissibleKeyguard");
             checkPermission();
             mKeyguardViewMediator.showDismissibleKeyguard();
+            if (SceneContainerFlag.isEnabled()) {
+                mSceneInteractorLazy.get().changeScene(
+                        Scenes.Lockscreen, "KeyguardService.showDismissibleKeyguard");
+            }
         }
 
         @Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
index 956125c..a1e4af5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardSmartspaceRepository.kt
@@ -51,10 +51,6 @@
 ) : KeyguardSmartspaceRepository {
     private val _bcSmartspaceVisibility: MutableStateFlow<Int> = MutableStateFlow(View.GONE)
     override val bcSmartspaceVisibility: StateFlow<Int> = _bcSmartspaceVisibility.asStateFlow()
-    val defaultValue =
-        context.resources.getBoolean(
-            com.android.internal.R.bool.config_lockscreenWeatherEnabledByDefault
-        )
     override val isWeatherEnabled: StateFlow<Boolean> =
         secureSettings
             .observerFlow(
@@ -76,7 +72,7 @@
     private fun getLockscreenWeatherEnabled(): Boolean {
         return secureSettings.getIntForUser(
             Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED,
-            if (defaultValue) 1 else 0,
+            1,
             userTracker.userId
         ) == 1
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 7655d7a..f488d3b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -34,6 +34,7 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -42,6 +43,7 @@
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.sync.Mutex
 
 /**
  * The source of truth for all keyguard transitions.
@@ -129,6 +131,7 @@
     private var lastStep: TransitionStep = TransitionStep()
     private var lastAnimator: ValueAnimator? = null
 
+    private val _currentTransitionMutex = Mutex()
     private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
         MutableStateFlow(
             TransitionInfo(
@@ -146,6 +149,9 @@
      */
     private var updateTransitionId: UUID? = null
 
+    // Only used in a test environment
+    var forceDelayForRaceConditionTest = false
+
     init {
         // Start with a FINISHED transition in OFF. KeyguardBootInteractor will transition from OFF
         // to either GONE or LOCKSCREEN once we're booted up and can determine which state we should
@@ -162,9 +168,21 @@
 
     override suspend fun startTransition(info: TransitionInfo): UUID? {
         _currentTransitionInfo.value = info
+        Log.d(TAG, "(Internal) Setting current transition info: $info")
+
+        // There is no fairness guarantee with 'withContext', which means that transitions could
+        // be processed out of order. Use a Mutex to guarantee ordering.
+        _currentTransitionMutex.lock()
+
+        // Only used in a test environment
+        if (forceDelayForRaceConditionTest) {
+            delay(50L)
+        }
 
         // Animators must be started on the main thread.
         return withContext("$TAG#startTransition", mainDispatcher) {
+            _currentTransitionMutex.unlock()
+
             if (lastStep.from == info.from && lastStep.to == info.to) {
                 Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
                 return@withContext null
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 75c4d6f..cf6942e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -56,12 +56,6 @@
         }
 
         scope.launch {
-            sharedNotificationContainerViewModel
-                .getMaxNotifications { height, useExtraShelfSpace -> height.toInt() }
-                .collect { logger.log(TAG, VERBOSE, "Notif: max height in px", it) }
-        }
-
-        scope.launch {
             sharedNotificationContainerViewModel.isOnLockscreen.collect {
                 logger.log(TAG, VERBOSE, "Notif: isOnLockscreen", it)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index b2a24ca..323ceef 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -229,6 +229,7 @@
                         startTransitionTo(
                             toState = KeyguardState.OCCLUDED,
                             modeOnCanceled = TransitionModeOnCanceled.RESET,
+                            ownerReason = "keyguardInteractor.onCameraLaunchDetected",
                         )
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 1e2db7c..350527a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.keyguard.domain.interactor
 
-import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.keyguard.shared.model.BiometricUnlockMode
-import com.android.systemui.keyguard.shared.model.Edge
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
-import com.android.systemui.util.kotlin.pairwise
 import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -48,7 +49,8 @@
     fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor,
     fromAlternateBouncerInteractor: FromAlternateBouncerTransitionInteractor,
     notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor,
-    sceneInteractor: SceneInteractor,
+    sceneInteractor: Lazy<SceneInteractor>,
+    deviceEntryInteractor: Lazy<DeviceEntryInteractor>,
 ) {
     private val defaultSurfaceBehindVisibility =
         transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible)
@@ -112,7 +114,7 @@
     val usingKeyguardGoingAwayAnimation: Flow<Boolean> =
         if (SceneContainerFlag.isEnabled) {
             combine(
-                    sceneInteractor.transitionState,
+                    sceneInteractor.get().transitionState,
                     surfaceBehindInteractor.isAnimatingSurface,
                     notificationLaunchAnimationInteractor.isLaunchAnimationRunning,
                 ) { transition, isAnimatingSurface, isLaunchAnimationRunning ->
@@ -156,19 +158,7 @@
      */
     val lockscreenVisibility: Flow<Boolean> =
         if (SceneContainerFlag.isEnabled) {
-            sceneInteractor.transitionState
-                .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen))
-                .map { (prevTransitionState, transitionState) ->
-                    val isReturningToGoneAfterCancellation =
-                        prevTransitionState.isTransitioning(from = Scenes.Gone) &&
-                            transitionState.isTransitioning(to = Scenes.Gone)
-                    val isNotOnGone =
-                        !transitionState.isTransitioning(from = Scenes.Gone) &&
-                            !transitionState.isIdle(Scenes.Gone)
-
-                    isNotOnGone && !isReturningToGoneAfterCancellation
-                }
-                .distinctUntilChanged()
+            deviceEntryInteractor.get().isDeviceEntered.map { !it }
         } else {
             transitionInteractor.currentKeyguardState
                 .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 6a6eba1..1e7bc0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -54,5 +54,6 @@
     fun isSceneContainerEnabled() = SceneContainerFlag.isEnabled
 
     /** Check whether to use media refactor code */
-    fun isMediaControlsRefactorEnabled() = MediaControlsRefactorFlag.isEnabled
+    fun isMediaControlsRefactorEnabled() =
+        MediaControlsRefactorFlag.isEnabled && SceneContainerFlag.isEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 4fd0df4..c6dfdd5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -148,7 +148,8 @@
      */
     protected var showRippleEffect = true
 
-    private lateinit var qsTileBackground: LayerDrawable
+    private lateinit var qsTileBackground: RippleDrawable
+    private lateinit var qsTileFocusBackground: Drawable
     private lateinit var backgroundDrawable: LayerDrawable
     private lateinit var backgroundBaseDrawable: Drawable
     private lateinit var backgroundOverlayDrawable: Drawable
@@ -313,10 +314,11 @@
 
     private fun createTileBackground(): Drawable {
         qsTileBackground = if (Flags.qsTileFocusState()) {
-            mContext.getDrawable(R.drawable.qs_tile_background_flagged) as LayerDrawable
+            mContext.getDrawable(R.drawable.qs_tile_background_flagged) as RippleDrawable
         } else {
             mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
         }
+        qsTileFocusBackground = mContext.getDrawable(R.drawable.qs_tile_focused_background)!!
         backgroundDrawable =
             qsTileBackground.findDrawableByLayerId(R.id.background) as LayerDrawable
         backgroundBaseDrawable =
@@ -332,6 +334,17 @@
         updateHeight()
     }
 
+    override fun onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect)
+        if (Flags.qsTileFocusState()) {
+            if (gainFocus) {
+                qsTileFocusBackground.setBounds(0, 0, width, height)
+                overlay.add(qsTileFocusBackground)
+            } else {
+                overlay.clear()
+            }
+        }
+    }
     private fun updateHeight() {
         // TODO(b/332900989): Find a more robust way of resetting the tile if not reset by the
         //  launch animation.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index 63acbb0..fb872d5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -127,28 +127,28 @@
 
         val isVisible: Boolean
         val expansion: Float
-        val squishiness: Float
+        val squishiness: () -> Float
 
         data object CLOSED : State {
             override val isVisible = false
             override val expansion = 0f
-            override val squishiness = 1f
+            override val squishiness = { 1f }
         }
 
         /** State for expanding between QQS and QS */
         data class Expanding(override val expansion: Float) : State {
             override val isVisible = true
-            override val squishiness = 1f
+            override val squishiness = { 1f }
         }
 
         /** State for appearing QQS from Lockscreen or Gone */
-        data class UnsquishingQQS(override val squishiness: Float) : State {
+        data class UnsquishingQQS(override val squishiness: () -> Float) : State {
             override val isVisible = true
             override val expansion = 0f
         }
 
         /** State for appearing QS from Lockscreen or Gone, used in Split shade */
-        data class UnsquishingQS(override val squishiness: Float) : State {
+        data class UnsquishingQS(override val squishiness: () -> Float) : State {
             override val isVisible = true
             override val expansion = 1f
         }
@@ -370,7 +370,7 @@
         setQsVisible(state.isVisible)
         setExpanded(state.isVisible && state.expansion > 0f)
         setListening(state.isVisible)
-        setQsExpansion(state.expansion, 1f, 0f, state.squishiness)
+        setQsExpansion(state.expansion, 1f, 0f, state.squishiness())
     }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 32e383a..3826b50 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -4218,7 +4218,7 @@
     }
 
     private void registerAnimatorForTest(Animator animator) {
-        if (mTestSetOfAnimatorsUsed != null) {
+        if (mTestSetOfAnimatorsUsed != null && animator != null) {
             mTestSetOfAnimatorsUsed.add(animator);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 2446473..3d4b421 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -633,6 +633,7 @@
                     INDICATION_TYPE_BIOMETRIC_MESSAGE,
                     new KeyguardIndication.Builder()
                             .setMessage(mBiometricMessage)
+                            .setForceAccessibilityLiveRegionAssertive()
                             .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
                             .setTextColor(mInitialTextColorState)
                             .build(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 446a0d7..455c964 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -310,11 +310,9 @@
 
     fun isWeatherEnabled(): Boolean {
        execution.assertIsMainThread()
-       val defaultValue = context.getResources().getBoolean(
-               com.android.internal.R.bool.config_lockscreenWeatherEnabledByDefault)
        val showWeather = secureSettings.getIntForUser(
            LOCK_SCREEN_WEATHER_ENABLED,
-           if (defaultValue) 1 else 0,
+           1,
            userTracker.userId) == 1
        return showWeather
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index bd9383d..2f293e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -22,11 +22,13 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
 import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
 import com.android.systemui.statusbar.notification.stack.BUCKET_FOREGROUND_SERVICE
 import com.android.systemui.statusbar.notification.stack.BUCKET_HEADS_UP
 import com.android.systemui.statusbar.notification.stack.BUCKET_MEDIA_CONTROLS
 import com.android.systemui.statusbar.notification.stack.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.BUCKET_PRIORITY_PEOPLE
 import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
 import com.android.systemui.util.DeviceConfigProxy
 import com.android.systemui.util.Utils
@@ -53,6 +55,18 @@
     }
 
     fun getNotificationBuckets(): IntArray {
+        if (PriorityPeopleSection.isEnabled) {
+            // We don't need this list to be adaptive, it can be the superset of all features.
+            return intArrayOf(
+                    BUCKET_MEDIA_CONTROLS,
+                    BUCKET_HEADS_UP,
+                    BUCKET_FOREGROUND_SERVICE,
+                    BUCKET_PRIORITY_PEOPLE,
+                    BUCKET_PEOPLE,
+                    BUCKET_ALERTING,
+                    BUCKET_SILENT,
+                )
+        }
         return when {
             isFilteringEnabled() && isMediaControlsEnabled() ->
                 intArrayOf(BUCKET_HEADS_UP, BUCKET_FOREGROUND_SERVICE, BUCKET_MEDIA_CONTROLS,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index a901c5f..87f11f13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.interruption
 
+import android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST
 import android.app.Notification
 import android.app.Notification.BubbleMetadata
 import android.app.Notification.CATEGORY_EVENT
@@ -23,6 +24,8 @@
 import android.app.Notification.VISIBILITY_PRIVATE
 import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.database.ContentObserver
 import android.hardware.display.AmbientDisplayConfiguration
 import android.os.Handler
@@ -234,6 +237,7 @@
     private val avalancheProvider: AvalancheProvider,
     private val systemClock: SystemClock,
     private val systemSettings: SystemSettings,
+    private val packageManager: PackageManager,
 ) :
     VisualInterruptionFilter(
         types = setOf(PEEK, PULSE),
@@ -249,6 +253,7 @@
         ALLOW_CATEGORY_EVENT,
         ALLOW_FSI_WITH_PERMISSION_ON,
         ALLOW_COLORIZED,
+        ALLOW_EMERGENCY,
         SUPPRESS
     }
 
@@ -299,13 +304,20 @@
         if (entry.sbn.notification.isColorized) {
             return State.ALLOW_COLORIZED
         }
+        if (entry.sbn.notification.isColorized) {
+            return State.ALLOW_COLORIZED
+        }
+        if (
+            packageManager.checkPermission(RECEIVE_EMERGENCY_BROADCAST, entry.sbn.packageName) ==
+                PERMISSION_GRANTED
+        ) {
+            return State.ALLOW_EMERGENCY
+        }
         return State.SUPPRESS
     }
 
     private fun isCooldownEnabled(): Boolean {
-        return systemSettings.getInt(
-            Settings.System.NOTIFICATION_COOLDOWN_ENABLED,
-            /* def */ 1
-        ) == 1
+        return systemSettings.getInt(Settings.System.NOTIFICATION_COOLDOWN_ENABLED, /* def */ 1) ==
+            1
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index e6d97c2..f68e194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.statusbar.notification.interruption
 
+import android.content.pm.PackageManager
 import android.hardware.display.AmbientDisplayConfiguration
 import android.os.Handler
 import android.os.PowerManager
@@ -63,7 +64,8 @@
     private val uiEventLogger: UiEventLogger,
     private val userTracker: UserTracker,
     private val avalancheProvider: AvalancheProvider,
-    private val systemSettings: SystemSettings
+    private val systemSettings: SystemSettings,
+    private val packageManager: PackageManager
 ) : VisualInterruptionDecisionProvider {
 
     init {
@@ -172,7 +174,9 @@
         addFilter(AlertKeyguardVisibilitySuppressor(keyguardNotificationVisibilityProvider))
 
         if (NotificationAvalancheSuppression.isEnabled) {
-            addFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings))
+            addFilter(
+                AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+            )
             avalancheProvider.register()
         }
         started = true
@@ -232,14 +236,17 @@
 
     private fun makeLoggablePeekDecision(entry: NotificationEntry): LoggableDecision =
         checkConditions(PEEK)
-            ?: checkFilters(PEEK, entry) ?: checkSuppressInterruptions(entry)
-                ?: checkSuppressAwakeInterruptions(entry) ?: checkSuppressAwakeHeadsUp(entry)
-                ?: LoggableDecision.unsuppressed
+            ?: checkFilters(PEEK, entry)
+            ?: checkSuppressInterruptions(entry)
+            ?: checkSuppressAwakeInterruptions(entry)
+            ?: checkSuppressAwakeHeadsUp(entry)
+            ?: LoggableDecision.unsuppressed
 
     private fun makeLoggablePulseDecision(entry: NotificationEntry): LoggableDecision =
         checkConditions(PULSE)
-            ?: checkFilters(PULSE, entry) ?: checkSuppressInterruptions(entry)
-                ?: LoggableDecision.unsuppressed
+            ?: checkFilters(PULSE, entry)
+            ?: checkSuppressInterruptions(entry)
+            ?: LoggableDecision.unsuppressed
 
     override fun makeAndLogBubbleDecision(entry: NotificationEntry): Decision =
         traceSection("VisualInterruptionDecisionProviderImpl#makeAndLogBubbleDecision") {
@@ -252,8 +259,10 @@
 
     private fun makeLoggableBubbleDecision(entry: NotificationEntry): LoggableDecision =
         checkConditions(BUBBLE)
-            ?: checkFilters(BUBBLE, entry) ?: checkSuppressInterruptions(entry)
-                ?: checkSuppressAwakeInterruptions(entry) ?: LoggableDecision.unsuppressed
+            ?: checkFilters(BUBBLE, entry)
+            ?: checkSuppressInterruptions(entry)
+            ?: checkSuppressAwakeInterruptions(entry)
+            ?: LoggableDecision.unsuppressed
 
     private fun logDecision(
         type: VisualInterruptionType,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
index d4f8ea3..d6c73a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationHeadsUpCycling.kt
@@ -23,8 +23,8 @@
 /** Helper for reading or using the heads-up cycling flag state. */
 @Suppress("NOTHING_TO_INLINE")
 object NotificationHeadsUpCycling {
-    /** The aconfig flag name */
-    const val FLAG_NAME = Flags.FLAG_NOTIFICATION_HEADS_UP_CYCLING
+    /** The aconfig flag name - enable this feature when FLAG_NOTIFICATION_THROTTLE_HUN is on. */
+    const val FLAG_NAME = Flags.FLAG_NOTIFICATION_THROTTLE_HUN
 
     /** A token used for dependency declaration */
     val token: FlagToken
@@ -33,7 +33,7 @@
     /** Is the heads-up cycling animation enabled */
     @JvmStatic
     inline val isEnabled
-        get() = Flags.notificationHeadsUpCycling()
+        get() = Flags.notificationThrottleHun()
 
     /** Whether to animate the bottom line when transiting from a tall HUN to a short HUN */
     @JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 2d0395a..5a433a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -16,17 +16,6 @@
 
 package com.android.systemui.statusbar.notification.stack;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.graphics.Rect;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.android.app.animation.Interpolators;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
 /**
@@ -35,165 +24,18 @@
  */
 public class NotificationSection {
     private @PriorityBucket final int mBucket;
-    private final View mOwningView;
-    private final Rect mBounds = new Rect();
-    private final Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
-    private final Rect mStartAnimationRect = new Rect();
-    private final Rect mEndAnimationRect = new Rect();
-    private ObjectAnimator mTopAnimator = null;
-    private ObjectAnimator mBottomAnimator = null;
     private ExpandableView mFirstVisibleChild;
     private ExpandableView mLastVisibleChild;
 
-    NotificationSection(View owningView, @PriorityBucket int bucket) {
-        mOwningView = owningView;
+    NotificationSection(@PriorityBucket int bucket) {
         mBucket = bucket;
     }
 
-    public void cancelAnimators() {
-        if (mBottomAnimator != null) {
-            mBottomAnimator.cancel();
-        }
-        if (mTopAnimator != null) {
-            mTopAnimator.cancel();
-        }
-    }
-
-    public Rect getCurrentBounds() {
-        return mCurrentBounds;
-    }
-
-    public Rect getBounds() {
-        return mBounds;
-    }
-
-    public boolean didBoundsChange() {
-        return !mCurrentBounds.equals(mBounds);
-    }
-
-    public boolean areBoundsAnimating() {
-        return mBottomAnimator != null || mTopAnimator != null;
-    }
-
     @PriorityBucket
     public int getBucket() {
         return mBucket;
     }
 
-    public void startBackgroundAnimation(boolean animateTop, boolean animateBottom) {
-        // Left and right bounds are always applied immediately.
-        mCurrentBounds.left = mBounds.left;
-        mCurrentBounds.right = mBounds.right;
-        startBottomAnimation(animateBottom);
-        startTopAnimation(animateTop);
-    }
-
-
-    private void startTopAnimation(boolean animate) {
-        int previousEndValue = mEndAnimationRect.top;
-        int newEndValue = mBounds.top;
-        ObjectAnimator previousAnimator = mTopAnimator;
-        if (previousAnimator != null && previousEndValue == newEndValue) {
-            return;
-        }
-        if (!animate) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                int previousStartValue = mStartAnimationRect.top;
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                values[0].setIntValues(previousStartValue, newEndValue);
-                mStartAnimationRect.top = previousStartValue;
-                mEndAnimationRect.top = newEndValue;
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                setBackgroundTop(newEndValue);
-                return;
-            }
-        }
-        if (previousAnimator != null) {
-            previousAnimator.cancel();
-        }
-        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop",
-                mCurrentBounds.top, newEndValue);
-        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
-        animator.setInterpolator(interpolator);
-        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mStartAnimationRect.top = -1;
-                mEndAnimationRect.top = -1;
-                mTopAnimator = null;
-            }
-        });
-        animator.start();
-        mStartAnimationRect.top = mCurrentBounds.top;
-        mEndAnimationRect.top = newEndValue;
-        mTopAnimator = animator;
-    }
-
-    private void startBottomAnimation(boolean animate) {
-        int previousStartValue = mStartAnimationRect.bottom;
-        int previousEndValue = mEndAnimationRect.bottom;
-        int newEndValue = mBounds.bottom;
-        ObjectAnimator previousAnimator = mBottomAnimator;
-        if (previousAnimator != null && previousEndValue == newEndValue) {
-            return;
-        }
-        if (!animate) {
-            // just a local update was performed
-            if (previousAnimator != null) {
-                // we need to increase all animation keyframes of the previous animator by the
-                // relative change to the end value
-                PropertyValuesHolder[] values = previousAnimator.getValues();
-                values[0].setIntValues(previousStartValue, newEndValue);
-                mStartAnimationRect.bottom = previousStartValue;
-                mEndAnimationRect.bottom = newEndValue;
-                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
-                return;
-            } else {
-                // no new animation needed, let's just apply the value
-                setBackgroundBottom(newEndValue);
-                return;
-            }
-        }
-        if (previousAnimator != null) {
-            previousAnimator.cancel();
-        }
-        ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom",
-                mCurrentBounds.bottom, newEndValue);
-        Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
-        animator.setInterpolator(interpolator);
-        animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mStartAnimationRect.bottom = -1;
-                mEndAnimationRect.bottom = -1;
-                mBottomAnimator = null;
-            }
-        });
-        animator.start();
-        mStartAnimationRect.bottom = mCurrentBounds.bottom;
-        mEndAnimationRect.bottom = newEndValue;
-        mBottomAnimator = animator;
-    }
-
-    private void setBackgroundTop(int top) {
-        mCurrentBounds.top = top;
-        mOwningView.invalidate();
-    }
-
-    private void setBackgroundBottom(int bottom) {
-        mCurrentBounds.bottom = bottom;
-        mOwningView.invalidate();
-    }
 
     public ExpandableView getFirstVisibleChild() {
         return mFirstVisibleChild;
@@ -215,91 +57,4 @@
         return changed;
     }
 
-    public void resetCurrentBounds() {
-        mCurrentBounds.set(mBounds);
-    }
-
-    /**
-     * Returns true if {@code top} is equal to the top of this section (if not currently animating)
-     * or where the top of this section will be when animation completes.
-     */
-    public boolean isTargetTop(int top) {
-        return (mTopAnimator == null && mCurrentBounds.top == top)
-                || (mTopAnimator != null && mEndAnimationRect.top == top);
-    }
-
-    /**
-     * Returns true if {@code bottom} is equal to the bottom of this section (if not currently
-     * animating) or where the bottom of this section will be when animation completes.
-     */
-    public boolean isTargetBottom(int bottom) {
-        return (mBottomAnimator == null && mCurrentBounds.bottom == bottom)
-                || (mBottomAnimator != null && mEndAnimationRect.bottom == bottom);
-    }
-
-    /**
-     * Update the bounds of this section based on it's views
-     *
-     * @param minTopPosition the minimum position that the top needs to have
-     * @param minBottomPosition the minimum position that the bottom needs to have
-     * @return the position of the new bottom
-     */
-    public int updateBounds(int minTopPosition, int minBottomPosition,
-            boolean shiftBackgroundWithFirst) {
-        int top = minTopPosition;
-        int bottom = minTopPosition;
-        ExpandableView firstView = getFirstVisibleChild();
-        if (firstView != null) {
-            // Round Y up to avoid seeing the background during animation
-            int finalTranslationY = (int) Math.ceil(ViewState.getFinalTranslationY(firstView));
-            // TODO: look into the already animating part
-            int newTop;
-            if (isTargetTop(finalTranslationY)) {
-                // we're ending up at the same location as we are now, let's just skip the
-                // animation
-                newTop = finalTranslationY;
-            } else {
-                newTop = (int) Math.ceil(firstView.getTranslationY());
-            }
-            top = Math.max(newTop, top);
-            if (firstView.showingPulsing()) {
-                // If we're pulsing, the notification can actually go below!
-                bottom = Math.max(bottom, finalTranslationY
-                        + ExpandableViewState.getFinalActualHeight(firstView));
-                if (shiftBackgroundWithFirst) {
-                    mBounds.left += Math.max(firstView.getTranslation(), 0);
-                    mBounds.right += Math.min(firstView.getTranslation(), 0);
-                }
-            }
-        }
-        ExpandableView lastView = getLastVisibleChild();
-        if (lastView != null) {
-            float finalTranslationY = ViewState.getFinalTranslationY(lastView);
-            int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
-            // Round Y down to avoid seeing the background during animation
-            int finalBottom = (int) Math.floor(
-                    finalTranslationY + finalHeight - lastView.getClipBottomAmount());
-            int newBottom;
-            if (isTargetBottom(finalBottom)) {
-                // we're ending up at the same location as we are now, lets just skip the animation
-                newBottom = finalBottom;
-            } else {
-                newBottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
-                        - lastView.getClipBottomAmount());
-                // The background can never be lower than the end of the last view
-                minBottomPosition = (int) Math.min(
-                        lastView.getTranslationY() + lastView.getActualHeight(),
-                        minBottomPosition);
-            }
-            bottom = Math.max(bottom, Math.max(newBottom, minBottomPosition));
-        }
-        bottom = Math.max(top, bottom);
-        mBounds.top = top;
-        mBounds.bottom = bottom;
-        return bottom;
-    }
-
-    public boolean needsBackground() {
-        return mFirstVisibleChild != null && mBucket != BUCKET_MEDIA_CONTROLS;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index d269eda..3400ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -40,7 +40,9 @@
  *
  * TODO: Move remaining sections logic from NSSL into this class.
  */
-class NotificationSectionsManager @Inject internal constructor(
+class NotificationSectionsManager
+@Inject
+internal constructor(
     private val configurationController: ConfigurationController,
     private val keyguardMediaController: KeyguardMediaController,
     private val sectionsFeatureManager: NotificationSectionsFeatureManager,
@@ -52,11 +54,12 @@
     @SilentHeader private val silentHeaderController: SectionHeaderController
 ) : SectionProvider {
 
-    private val configurationListener = object : ConfigurationController.ConfigurationListener {
-        override fun onLocaleListChanged() {
-            reinflateViews()
+    private val configurationListener =
+        object : ConfigurationController.ConfigurationListener {
+            override fun onLocaleListChanged() {
+                reinflateViews()
+            }
         }
-    }
 
     private lateinit var parent: NotificationStackScrollLayout
     private var initialized = false
@@ -81,7 +84,7 @@
     val mediaControlsView: MediaContainerView?
         get() = mediaContainerController.mediaContainerView
 
-    /** Must be called before use.  */
+    /** Must be called before use. */
     fun initialize(parent: NotificationStackScrollLayout) {
         check(!initialized) { "NotificationSectionsManager already initialized" }
         initialized = true
@@ -91,13 +94,12 @@
     }
 
     fun createSectionsForBuckets(): Array<NotificationSection> =
-            sectionsFeatureManager.getNotificationBuckets()
-                    .map { NotificationSection(parent, it) }
-                    .toTypedArray()
+        sectionsFeatureManager
+            .getNotificationBuckets()
+            .map { NotificationSection(it) }
+            .toTypedArray()
 
-    /**
-     * Reinflates the entire notification header, including all decoration views.
-     */
+    /** Reinflates the entire notification header, including all decoration views. */
     fun reinflateViews() {
         silentHeaderController.reinflateView(parent)
         alertingHeaderController.reinflateView(parent)
@@ -108,44 +110,44 @@
     }
 
     override fun beginsSection(view: View, previous: View?): Boolean =
-            view === silentHeaderView ||
+        view === silentHeaderView ||
             view === mediaControlsView ||
             view === peopleHeaderView ||
             view === alertingHeaderView ||
             view === incomingHeaderView ||
             getBucket(view) != getBucket(previous)
 
-    private fun getBucket(view: View?): Int? = when {
-        view === silentHeaderView -> BUCKET_SILENT
-        view === incomingHeaderView -> BUCKET_HEADS_UP
-        view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
-        view === peopleHeaderView -> BUCKET_PEOPLE
-        view === alertingHeaderView -> BUCKET_ALERTING
-        view is ExpandableNotificationRow -> view.entry.bucket
-        else -> null
-    }
+    private fun getBucket(view: View?): Int? =
+        when {
+            view === silentHeaderView -> BUCKET_SILENT
+            view === incomingHeaderView -> BUCKET_HEADS_UP
+            view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
+            view === peopleHeaderView -> BUCKET_PEOPLE
+            view === alertingHeaderView -> BUCKET_ALERTING
+            view is ExpandableNotificationRow -> view.entry.bucket
+            else -> null
+        }
 
     private sealed class SectionBounds {
 
-        data class Many(
-            val first: ExpandableView,
-            val last: ExpandableView
-        ) : SectionBounds()
+        data class Many(val first: ExpandableView, val last: ExpandableView) : SectionBounds()
 
         data class One(val lone: ExpandableView) : SectionBounds()
         object None : SectionBounds()
 
-        fun addNotif(notif: ExpandableView): SectionBounds = when (this) {
-            is None -> One(notif)
-            is One -> Many(lone, notif)
-            is Many -> copy(last = notif)
-        }
+        fun addNotif(notif: ExpandableView): SectionBounds =
+            when (this) {
+                is None -> One(notif)
+                is One -> Many(lone, notif)
+                is Many -> copy(last = notif)
+            }
 
-        fun updateSection(section: NotificationSection): Boolean = when (this) {
-            is None -> section.setFirstAndLastVisibleChildren(null, null)
-            is One -> section.setFirstAndLastVisibleChildren(lone, lone)
-            is Many -> section.setFirstAndLastVisibleChildren(first, last)
-        }
+        fun updateSection(section: NotificationSection): Boolean =
+            when (this) {
+                is None -> section.setFirstAndLastVisibleChildren(null, null)
+                is One -> section.setFirstAndLastVisibleChildren(lone, lone)
+                is Many -> section.setFirstAndLastVisibleChildren(first, last)
+            }
 
         private fun NotificationSection.setFirstAndLastVisibleChildren(
             first: ExpandableView?,
@@ -167,17 +169,19 @@
         children: List<ExpandableView>
     ): Boolean {
         // Create mapping of bucket to section
-        val sectionBounds = children.asSequence()
+        val sectionBounds =
+            children
+                .asSequence()
                 // Group children by bucket
                 .groupingBy {
                     getBucket(it)
-                            ?: throw IllegalArgumentException("Cannot find section bucket for view")
+                        ?: throw IllegalArgumentException("Cannot find section bucket for view")
                 }
                 // Combine each bucket into a SectionBoundary
                 .foldToSparseArray(
-                        SectionBounds.None,
-                        size = sections.size,
-                        operation = SectionBounds::addNotif
+                    SectionBounds.None,
+                    size = sections.size,
+                    operation = SectionBounds::addNotif
                 )
 
         // Build a set of the old first/last Views of the sections
@@ -185,11 +189,12 @@
         val oldLastChildren = sections.mapNotNull { it.lastVisibleChild }.toSet().toMutableSet()
 
         // Update each section with the associated boundary, tracking if there was a change
-        val changed = sections.fold(false) { changed, section ->
-            val bounds = sectionBounds[section.bucket] ?: SectionBounds.None
-            val isSectionChanged = bounds.updateSection(section)
-            isSectionChanged || changed
-        }
+        val changed =
+            sections.fold(false) { changed, section ->
+                val bounds = sectionBounds[section.bucket] ?: SectionBounds.None
+                val isSectionChanged = bounds.updateSection(section)
+                isSectionChanged || changed
+            }
 
         val newFirstChildren = sections.mapNotNull { it.firstVisibleChild }
         val newLastChildren = sections.mapNotNull { it.lastVisibleChild }
@@ -229,16 +234,18 @@
     private fun logSections(sections: Array<NotificationSection>) {
         for (i in sections.indices) {
             val s = sections[i]
-            val fs = when (val first = s.firstVisibleChild) {
-                null -> "(null)"
-                is ExpandableNotificationRow -> first.entry.key
-                else -> Integer.toHexString(System.identityHashCode(first))
-            }
-            val ls = when (val last = s.lastVisibleChild) {
-                null -> "(null)"
-                is ExpandableNotificationRow -> last.entry.key
-                else -> Integer.toHexString(System.identityHashCode(last))
-            }
+            val fs =
+                when (val first = s.firstVisibleChild) {
+                    null -> "(null)"
+                    is ExpandableNotificationRow -> first.entry.key
+                    else -> Integer.toHexString(System.identityHashCode(first))
+                }
+            val ls =
+                when (val last = s.lastVisibleChild) {
+                    null -> "(null)"
+                    is ExpandableNotificationRow -> last.entry.key
+                    else -> Integer.toHexString(System.identityHashCode(last))
+                }
             Log.d(TAG, "updateSections: f=$fs s=$i")
             Log.d(TAG, "updateSections: l=$ls s=$i")
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 17b54c8..a9d7cc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -2974,7 +2974,7 @@
 
     private void updateFirstAndLastBackgroundViews() {
         ExpandableView lastChild = getLastChildWithBackground();
-        boolean sectionViewsChanged = mSectionsManager.updateFirstAndLastViewsForAllSections(
+        mSectionsManager.updateFirstAndLastViewsForAllSections(
                 mSections, getChildrenWithBackground());
 
         mAmbientState.setLastVisibleBackgroundChild(lastChild);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index c1c63cd..6a3055f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -23,6 +23,7 @@
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING;
 import static com.android.server.notification.Flags.screenshareNotificationHiding;
 import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
+import static com.android.systemui.Flags.confineNotificationTouchToViewWidth;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnOverscrollTopChangedListener;
@@ -597,7 +598,7 @@
                             ev.getY(),
                             true /* requireMinHeight */,
                             false /* ignoreDecors */,
-                            true /* ignoreWidth */);
+                            !confineNotificationTouchToViewWidth() /* ignoreWidth */);
                     if (child instanceof ExpandableNotificationRow row) {
                         ExpandableNotificationRow parent = row.getNotificationParent();
                         if (parent != null && parent.areChildrenExpanded()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index c4e0f31..16e9c71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -219,6 +219,7 @@
     }
 
     private void setNextIndication() {
+        boolean forceAssertiveAccessibilityLiveRegion = false;
         if (mKeyguardIndicationInfo != null) {
             // First, update the style.
             // If a background is set on the text, we don't want shadow on the text
@@ -239,8 +240,16 @@
                 }
             }
             setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
+            forceAssertiveAccessibilityLiveRegion =
+                mKeyguardIndicationInfo.getForceAssertiveAccessibilityLiveRegion();
+        }
+        if (!forceAssertiveAccessibilityLiveRegion) {
+            setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_NONE);
         }
         setText(mMessage);
+        if (forceAssertiveAccessibilityLiveRegion) {
+            setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
+        }
         if (mAlwaysAnnounceText) {
             announceForAccessibility(mMessage);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index fa88be5..d9f88c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -695,11 +695,6 @@
     public void show(Bundle options) {
         Trace.beginSection("StatusBarKeyguardViewManager#show");
         mNotificationShadeWindowController.setKeyguardShowing(true);
-        if (SceneContainerFlag.isEnabled()) {
-            // TODO(b/336581871): add sceneState?
-            mSceneInteractorLazy.get().changeScene(
-                    Scenes.Lockscreen, "StatusBarKeyguardViewManager.show");
-        }
         mKeyguardStateController.notifyKeyguardState(true, mKeyguardStateController.isOccluded());
         reset(true /* hideBouncerWhenShowing */);
         SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_STATE_CHANGED,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
index d4b2dbf..2e54972 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/MobileInputLogger.kt
@@ -53,6 +53,27 @@
         )
     }
 
+    fun logTopLevelServiceStateBroadcastEmergencyOnly(subId: Int, serviceState: ServiceState) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            {
+                int1 = subId
+                bool1 = serviceState.isEmergencyOnly
+            },
+            { "ACTION_SERVICE_STATE for subId=$int1. ServiceState.isEmergencyOnly=$bool1" }
+        )
+    }
+
+    fun logTopLevelServiceStateBroadcastMissingExtras(subId: Int) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { int1 = subId },
+            { "ACTION_SERVICE_STATE for subId=$int1. Intent is missing extras. Ignoring" }
+        )
+    }
+
     fun logOnSignalStrengthsChanged(signalStrength: SignalStrength, subId: Int) {
         buffer.log(
             TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt
new file mode 100644
index 0000000..cce3eb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/ServiceStateModel.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.pipeline.mobile.data.model
+
+import android.telephony.ServiceState
+
+/**
+ * Simplified representation of a [ServiceState] for use in SystemUI. Add any fields that we need to
+ * extract from service state here for consumption downstream
+ */
+data class ServiceStateModel(val isEmergencyOnly: Boolean) {
+    companion object {
+        fun fromServiceState(serviceState: ServiceState): ServiceStateModel {
+            return ServiceStateModel(isEmergencyOnly = serviceState.isEmergencyOnly)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 9471574..5ad8bf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -21,6 +21,7 @@
 import com.android.settingslib.SignalIcon.MobileIconGroup
 import com.android.settingslib.mobile.MobileMappings
 import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.StateFlow
@@ -92,6 +93,19 @@
     val defaultMobileIconGroup: Flow<MobileIconGroup>
 
     /**
+     * [deviceServiceState] is equivalent to the last [Intent.ACTION_SERVICE_STATE] broadcast with a
+     * subscriptionId of -1 (aka [SubscriptionManager.INVALID_SUBSCRIPTION_ID]).
+     *
+     * While each [MobileConnectionsRepository] listens for the service state of each subscription,
+     * there is potentially a service state associated with the device itself. This value can be
+     * used to calculate e.g., the emergency calling capability of the device (as opposed to the
+     * emergency calling capability of an individual mobile connection)
+     *
+     * Note: this is a [StateFlow] using an eager sharing strategy.
+     */
+    val deviceServiceState: StateFlow<ServiceStateModel?>
+
+    /**
      * If any active SIM on the device is in
      * [android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED] or
      * [android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED] or
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 8a8e33e..b068152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.demomode.DemoMode
 import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryImpl
@@ -151,6 +152,15 @@
     override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
         activeRepo.flatMapLatest { it.defaultMobileIconGroup }
 
+    override val deviceServiceState: StateFlow<ServiceStateModel?> =
+        activeRepo
+            .flatMapLatest { it.deviceServiceState }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                realRepository.deviceServiceState.value
+            )
+
     override val isAnySimSecure: Flow<Boolean> = activeRepo.flatMapLatest { it.isAnySimSecure }
     override fun getIsAnySimSecure(): Boolean = activeRepo.value.getIsAnySimSecure()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 2b3c632..a944e91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -136,6 +137,9 @@
 
     override val defaultMobileIconGroup = flowOf(TelephonyIcons.THREE_G)
 
+    // TODO(b/339023069): demo command for device-based connectivity state
+    override val deviceServiceState: StateFlow<ServiceStateModel?> = MutableStateFlow(null)
+
     override val isAnySimSecure: Flow<Boolean> = flowOf(getIsAnySimSecure())
     override fun getIsAnySimSecure(): Boolean = false
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 0073e9c..c32f0e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -18,8 +18,10 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
+import android.content.Intent
 import android.content.IntentFilter
 import android.telephony.CarrierConfigManager
+import android.telephony.ServiceState
 import android.telephony.SubscriptionInfo
 import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
@@ -35,7 +37,6 @@
 import com.android.settingslib.mobile.MobileMappings.Config
 import com.android.systemui.Dumpable
 import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
@@ -47,6 +48,7 @@
 import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -55,6 +57,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
 import com.android.systemui.util.kotlin.pairwise
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
 import java.io.PrintWriter
 import java.lang.ref.WeakReference
 import javax.inject.Inject
@@ -68,6 +71,7 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapLatest
@@ -169,6 +173,35 @@
             }
             .flowOn(bgDispatcher)
 
+    /** Note that this flow is eager, so we don't miss any state */
+    override val deviceServiceState: StateFlow<ServiceStateModel?> =
+        broadcastDispatcher
+            .broadcastFlow(IntentFilter(Intent.ACTION_SERVICE_STATE)) { intent, _ ->
+                val subId =
+                    intent.getIntExtra(
+                        SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+                        INVALID_SUBSCRIPTION_ID
+                    )
+
+                val extras = intent.extras
+                if (extras == null) {
+                    logger.logTopLevelServiceStateBroadcastMissingExtras(subId)
+                    return@broadcastFlow null
+                }
+
+                val serviceState = ServiceState.newFromBundle(extras)
+                logger.logTopLevelServiceStateBroadcastEmergencyOnly(subId, serviceState)
+                if (subId == INVALID_SUBSCRIPTION_ID) {
+                    // Assume that -1 here is the device's service state. We don't care about
+                    // other ones.
+                    ServiceStateModel.fromServiceState(serviceState)
+                } else {
+                    null
+                }
+            }
+            .filterNotNull()
+            .stateIn(scope, SharingStarted.Eagerly, null)
+
     /**
      * State flow that emits the set of mobile data subscriptions, each represented by its own
      * [SubscriptionModel].
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 91d7ca6..cc4d568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -111,6 +111,13 @@
     val isForceHidden: Flow<Boolean>
 
     /**
+     * True if the device-level service state (with -1 subscription id) reports emergency calls
+     * only. This value is only useful when there are no other subscriptions OR all existing
+     * subscriptions report that they are not in service.
+     */
+    val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean>
+
+    /**
      * Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
      * subId.
      */
@@ -377,6 +384,9 @@
             .map { it.contains(ConnectivitySlot.MOBILE) }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
+    override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean> =
+        mobileConnectionsRepo.deviceServiceState.map { it?.isEmergencyOnly ?: false }
+
     /** Vends out new [MobileIconInteractor] for a particular subId */
     override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
         reuseCache[subId]?.get() ?: createMobileConnectionInteractorForSubId(subId)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 51c053e..5b954b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -19,6 +19,9 @@
 import com.android.internal.telephony.flags.Flags
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.statusbar.pipeline.dagger.OemSatelliteInputLog
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.satellite.data.DeviceBasedSatelliteRepository
 import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState
@@ -45,6 +48,7 @@
     deviceProvisioningInteractor: DeviceProvisioningInteractor,
     wifiInteractor: WifiInteractor,
     @Application scope: CoroutineScope,
+    @OemSatelliteInputLog private val logBuffer: LogBuffer,
 ) {
     /** Must be observed by any UI showing Satellite iconography */
     val isSatelliteAllowed =
@@ -79,25 +83,52 @@
     val isWifiActive: Flow<Boolean> =
         wifiInteractor.wifiNetwork.map { it is WifiNetworkModel.Active }
 
+    private val allConnectionsOos =
+        iconsInteractor.icons.aggregateOver(
+            selector = { intr ->
+                combine(intr.isInService, intr.isEmergencyOnly, intr.isNonTerrestrial) {
+                    isInService,
+                    isEmergencyOnly,
+                    isNtn ->
+                    !isInService && !isEmergencyOnly && !isNtn
+                }
+            },
+            defaultValue = true, // no connections == everything is OOS
+        ) { isOosAndNotEmergencyAndNotSatellite ->
+            isOosAndNotEmergencyAndNotSatellite.all { it }
+        }
+
     /** When all connections are considered OOS, satellite connectivity is potentially valid */
     val areAllConnectionsOutOfService =
         if (Flags.oemEnabledSatelliteFlag()) {
-                iconsInteractor.icons.aggregateOver(
-                    selector = { intr ->
-                        combine(intr.isInService, intr.isEmergencyOnly, intr.isNonTerrestrial) {
-                            isInService,
-                            isEmergencyOnly,
-                            isNtn ->
-                            !isInService && !(isEmergencyOnly || isNtn)
-                        }
-                    }
-                ) { isOosAndNotEmergencyOnlyOrSatellite ->
-                    isOosAndNotEmergencyOnlyOrSatellite.all { it }
+                combine(
+                    allConnectionsOos,
+                    iconsInteractor.isDeviceInEmergencyCallsOnlyMode,
+                ) { connectionsOos, deviceEmergencyOnly ->
+                    logBuffer.log(
+                        TAG,
+                        LogLevel.INFO,
+                        {
+                            bool1 = connectionsOos
+                            bool2 = deviceEmergencyOnly
+                        },
+                        {
+                            "Updating OOS status. allConnectionsOOs=$bool1 " +
+                                "deviceEmergencyOnly=$bool2"
+                        },
+                    )
+                    // If no connections exist, or all are OOS, then we look to the device-based
+                    // service state to detect if any calls are possible
+                    connectionsOos && !deviceEmergencyOnly
                 }
             } else {
                 flowOf(false)
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), true)
+
+    companion object {
+        const val TAG = "DeviceBasedSatelliteInteractor"
+    }
 }
 
 /**
@@ -106,12 +137,22 @@
  *
  * Provides a way to connect the reactivity of the top-level flow with the reactivity of an
  * arbitrarily-defined relationship ([selector]) from R to the flow that R exposes.
+ *
+ * [defaultValue] allows for a default value to be used if there are no leaf nodes after applying
+ * [selector]. E.g., if there are no mobile connections, assume that there is no service.
  */
 @OptIn(ExperimentalCoroutinesApi::class)
 private inline fun <R, reified S, T> Flow<List<R>>.aggregateOver(
     crossinline selector: (R) -> Flow<S>,
-    crossinline transform: (Array<S>) -> T
+    defaultValue: T,
+    crossinline transform: (Array<S>) -> T,
 ): Flow<T> {
     return map { list -> list.map { selector(it) } }
-        .flatMapLatest { newFlows -> combine(newFlows) { newVals -> transform(newVals) } }
+        .flatMapLatest { newFlows ->
+            if (newFlows.isEmpty()) {
+                flowOf(defaultValue)
+            } else {
+                combine(newFlows) { newVals -> transform(newVals) }
+            }
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
index ca5ea3b..135edfc 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FullscreenLightRevealAnimation.kt
@@ -32,6 +32,7 @@
 import android.view.SurfaceSession
 import android.view.WindowManager
 import android.view.WindowlessWindowManager
+import androidx.annotation.WorkerThread
 import com.android.app.tracing.traceSection
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -235,8 +236,10 @@
     }
 
     private inner class RotationWatcher : RotationChangeProvider.RotationListener {
+        @WorkerThread
         override fun onRotationChanged(newRotation: Int) {
             traceSection("$TAG#onRotationChanged") {
+                ensureInBackground()
                 if (currentRotation != newRotation) {
                     currentRotation = newRotation
                     scrimView?.revealEffect = lightRevealEffectFactory(currentRotation)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
index 3117abc..e1787e8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/data/repository/AncSliceRepository.kt
@@ -21,22 +21,15 @@
 import androidx.slice.Slice
 import androidx.slice.SliceViewManager
 import com.android.settingslib.bluetooth.BluetoothUtils
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.slice.sliceForUri
-import com.android.systemui.volume.panel.component.mediaoutput.data.repository.LocalMediaRepositoryFactory
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import kotlin.coroutines.CoroutineContext
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
 
 /** Provides ANC slice data */
 interface AncSliceRepository {
@@ -49,35 +42,30 @@
      * - there is no supported device connected;
      * - there is no slice provider for the uri;
      */
-    fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?>
+    fun ancSlice(
+        device: BluetoothDevice,
+        width: Int,
+        isCollapsed: Boolean,
+        hideLabel: Boolean
+    ): Flow<Slice?>
 }
 
-@OptIn(ExperimentalCoroutinesApi::class)
 class AncSliceRepositoryImpl
 @AssistedInject
 constructor(
-    mediaRepositoryFactory: LocalMediaRepositoryFactory,
-    @Background private val backgroundCoroutineContext: CoroutineContext,
     @Main private val mainCoroutineContext: CoroutineContext,
     @Assisted private val sliceViewManager: SliceViewManager,
 ) : AncSliceRepository {
 
-    private val localMediaRepository = mediaRepositoryFactory.create(null)
-
-    override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
-        return localMediaRepository.currentConnectedDevice
-            .map {
-                (it as? BluetoothMediaDevice)
-                    ?.cachedDevice
-                    ?.device
-                    ?.getExtraControlUri(width, isCollapsed, hideLabel)
-            }
-            .distinctUntilChanged()
-            .flatMapLatest { sliceUri ->
-                sliceUri ?: return@flatMapLatest flowOf(null)
-                sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext)
-            }
-            .flowOn(backgroundCoroutineContext)
+    override fun ancSlice(
+        device: BluetoothDevice,
+        width: Int,
+        isCollapsed: Boolean,
+        hideLabel: Boolean
+    ): Flow<Slice?> {
+        val sliceUri =
+            device.getExtraControlUri(width, isCollapsed, hideLabel) ?: return flowOf(null)
+        return sliceViewManager.sliceForUri(sliceUri).flowOn(mainCoroutineContext)
     }
 
     private fun BluetoothDevice.getExtraControlUri(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
index cefa269..cfff457 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/anc/domain/interactor/AncSliceInteractor.kt
@@ -19,6 +19,8 @@
 import android.app.slice.Slice.HINT_ERROR
 import android.app.slice.SliceItem.FORMAT_SLICE
 import androidx.slice.Slice
+import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
+import com.android.systemui.volume.domain.model.AudioOutputDevice
 import com.android.systemui.volume.panel.component.anc.data.repository.AncSliceRepository
 import com.android.systemui.volume.panel.component.anc.domain.model.AncSlices
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
@@ -32,6 +34,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.stateIn
 
 /** Provides a valid slice from [AncSliceRepository]. */
@@ -40,6 +43,7 @@
 class AncSliceInteractor
 @Inject
 constructor(
+    private val audioOutputInteractor: AudioOutputInteractor,
     private val ancSliceRepository: AncSliceRepository,
     scope: CoroutineScope,
 ) {
@@ -70,9 +74,20 @@
      * remove the labels from the [Slice].
      */
     private fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
-        return ancSliceRepository
-            .ancSlice(width = width, isCollapsed = isCollapsed, hideLabel = hideLabel)
-            .filter { it?.isValidSlice() != false }
+        return audioOutputInteractor.currentAudioDevice.flatMapLatest { outputDevice ->
+            if (outputDevice is AudioOutputDevice.Bluetooth) {
+                ancSliceRepository
+                    .ancSlice(
+                        device = outputDevice.cachedBluetoothDevice.device,
+                        width = width,
+                        isCollapsed = isCollapsed,
+                        hideLabel = hideLabel,
+                    )
+                    .filter { it?.isValidSlice() != false }
+            } else {
+                flowOf(null)
+            }
+        }
     }
 
     private fun Slice.isValidSlice(): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
index 298ca67..9ca50d6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
@@ -18,11 +18,9 @@
 
 import android.media.AudioDeviceAttributes
 import android.media.AudioDeviceInfo
-import com.android.settingslib.media.BluetoothMediaDevice
-import com.android.settingslib.media.MediaDevice
-import com.android.settingslib.media.PhoneMediaDevice
 import com.android.settingslib.media.domain.interactor.SpatializerInteractor
-import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.domain.interactor.AudioOutputInteractor
+import com.android.systemui.volume.domain.model.AudioOutputDevice
 import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
 import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
@@ -46,16 +44,20 @@
 class SpatialAudioComponentInteractor
 @Inject
 constructor(
-    mediaOutputInteractor: MediaOutputInteractor,
+    audioOutputInteractor: AudioOutputInteractor,
     private val spatializerInteractor: SpatializerInteractor,
     @VolumePanelScope private val coroutineScope: CoroutineScope,
 ) {
 
     private val changes = MutableSharedFlow<Unit>()
     private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> =
-        mediaOutputInteractor.currentConnectedDevice
-            .map { mediaDevice ->
-                if (mediaDevice == null) builtinSpeaker else mediaDevice.getAudioDeviceAttributes()
+        audioOutputInteractor.currentAudioDevice
+            .map { audioDevice ->
+                if (audioDevice is AudioOutputDevice.Unknown) {
+                    builtinSpeaker
+                } else {
+                    audioDevice.getAudioDeviceAttributes()
+                }
             }
             .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), builtinSpeaker)
 
@@ -135,36 +137,35 @@
         changes.emit(Unit)
     }
 
-    private suspend fun MediaDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
+    private suspend fun AudioOutputDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
         when (this) {
-            is PhoneMediaDevice -> return builtinSpeaker
-            is BluetoothMediaDevice -> {
-                val device = cachedDevice ?: return null
+            is AudioOutputDevice.BuiltIn -> return builtinSpeaker
+            is AudioOutputDevice.Bluetooth -> {
                 return listOf(
                         AudioDeviceAttributes(
                             AudioDeviceAttributes.ROLE_OUTPUT,
                             AudioDeviceInfo.TYPE_BLE_HEADSET,
-                            device.address,
+                            cachedBluetoothDevice.address,
                         ),
                         AudioDeviceAttributes(
                             AudioDeviceAttributes.ROLE_OUTPUT,
                             AudioDeviceInfo.TYPE_BLE_SPEAKER,
-                            device.address,
+                            cachedBluetoothDevice.address,
                         ),
                         AudioDeviceAttributes(
                             AudioDeviceAttributes.ROLE_OUTPUT,
                             AudioDeviceInfo.TYPE_BLE_BROADCAST,
-                            device.address,
+                            cachedBluetoothDevice.address,
                         ),
                         AudioDeviceAttributes(
                             AudioDeviceAttributes.ROLE_OUTPUT,
                             AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
-                            device.address,
+                            cachedBluetoothDevice.address,
                         ),
                         AudioDeviceAttributes(
                             AudioDeviceAttributes.ROLE_OUTPUT,
                             AudioDeviceInfo.TYPE_HEARING_AID,
-                            device.address,
+                            cachedBluetoothDevice.address,
                         )
                     )
                     .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
similarity index 77%
rename from packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
index 516b665..93c0eea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSizePrefsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationFrameSizePrefsTest.java
@@ -39,9 +39,9 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class WindowMagnificationSizePrefsTest extends SysuiTestCase {
+public class WindowMagnificationFrameSizePrefsTest extends SysuiTestCase {
 
-    WindowMagnificationSizePrefs mWindowMagnificationSizePrefs;
+    WindowMagnificationFrameSizePrefs mWindowMagnificationFrameSizePrefs;
     FakeSharedPreferences mSharedPreferences;
 
     @Before
@@ -51,24 +51,24 @@
         when(mContext.getSharedPreferences(
                 eq("window_magnification_preferences"), anyInt()))
                 .thenReturn(mSharedPreferences);
-        mWindowMagnificationSizePrefs = new WindowMagnificationSizePrefs(mContext);
+        mWindowMagnificationFrameSizePrefs = new WindowMagnificationFrameSizePrefs(mContext);
     }
 
     @Test
     public void saveSizeForCurrentDensity_getExpectedSize() {
         Size testSize = new Size(500, 500);
-        mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize);
+        mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(testSize);
 
-        assertThat(mWindowMagnificationSizePrefs.getSizeForCurrentDensity())
+        assertThat(mWindowMagnificationFrameSizePrefs.getSizeForCurrentDensity())
                 .isEqualTo(testSize);
     }
 
     @Test
     public void saveSizeForCurrentDensity_containsPreferenceForCurrentDensity() {
         Size testSize = new Size(500, 500);
-        mWindowMagnificationSizePrefs.saveSizeForCurrentDensity(testSize);
+        mWindowMagnificationFrameSizePrefs.saveSizeForCurrentDensity(testSize);
 
-        assertThat(mWindowMagnificationSizePrefs.isPreferenceSavedForCurrentDensity())
+        assertThat(mWindowMagnificationFrameSizePrefs.isPreferenceSavedForCurrentDensity())
                 .isTrue();
     }
 }
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 e0df1e0..2d5e3a6 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.verifyZeroInteractions;
 
 import android.graphics.PointF;
-import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
@@ -40,7 +39,6 @@
 import androidx.dynamicanimation.animation.SpringForce;
 import androidx.test.filters.SmallTest;
 
-import com.android.systemui.Flags;
 import com.android.systemui.Prefs;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.accessibility.utils.TestUtils;
@@ -230,7 +228,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
     public void tuck_animates() {
         mMenuAnimationController.cancelAnimations();
         mMenuAnimationController.moveToEdgeAndHide();
@@ -239,7 +236,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_FLOATING_MENU_ANIMATED_TUCK)
     public void untuck_animates() {
         mMenuAnimationController.cancelAnimations();
         mMenuAnimationController.moveOutEdgeAndShow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
index 5e4272f..2682633 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt
@@ -44,6 +44,8 @@
 import org.mockito.junit.MockitoJUnit
 
 private const val USER_ID = 9
+private const val REQUEST_ID = 9L
+private const val WRONG_REQUEST_ID = 10L
 private const val CHALLENGE = 90L
 private const val OP_PACKAGE_NAME = "biometric.testapp"
 
@@ -105,6 +107,7 @@
                 repository.setPrompt(
                     PromptInfo().apply { isConfirmationRequested = case },
                     USER_ID,
+                    REQUEST_ID,
                     CHALLENGE,
                     PromptKind.Biometric(),
                     OP_PACKAGE_NAME
@@ -124,6 +127,7 @@
                 repository.setPrompt(
                     PromptInfo().apply { isConfirmationRequested = case },
                     USER_ID,
+                    REQUEST_ID,
                     CHALLENGE,
                     PromptKind.Biometric(),
                     OP_PACKAGE_NAME
@@ -134,12 +138,12 @@
         }
 
     @Test
-    fun setsAndUnsetsPrompt() =
+    fun setsAndUnsetsPrompt_whenRequestIdMatches() =
         testScope.runTest {
             val kind = PromptKind.Pin
             val promptInfo = PromptInfo()
 
-            repository.setPrompt(promptInfo, USER_ID, CHALLENGE, kind, OP_PACKAGE_NAME)
+            repository.setPrompt(promptInfo, USER_ID, REQUEST_ID, CHALLENGE, kind, OP_PACKAGE_NAME)
 
             assertThat(repository.promptKind.value).isEqualTo(kind)
             assertThat(repository.userId.value).isEqualTo(USER_ID)
@@ -147,11 +151,33 @@
             assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo)
             assertThat(repository.opPackageName.value).isEqualTo(OP_PACKAGE_NAME)
 
-            repository.unsetPrompt()
+            repository.unsetPrompt(REQUEST_ID)
 
             assertThat(repository.promptInfo.value).isNull()
             assertThat(repository.userId.value).isNull()
             assertThat(repository.challenge.value).isNull()
             assertThat(repository.opPackageName.value).isNull()
         }
+
+    @Test
+    fun setsAndUnsetsPrompt_whenRequestIdDoesNotMatch() =
+        testScope.runTest {
+            val kind = PromptKind.Pin
+            val promptInfo = PromptInfo()
+
+            repository.setPrompt(promptInfo, USER_ID, REQUEST_ID, CHALLENGE, kind, OP_PACKAGE_NAME)
+
+            assertThat(repository.promptKind.value).isEqualTo(kind)
+            assertThat(repository.userId.value).isEqualTo(USER_ID)
+            assertThat(repository.challenge.value).isEqualTo(CHALLENGE)
+            assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo)
+            assertThat(repository.opPackageName.value).isEqualTo(OP_PACKAGE_NAME)
+
+            repository.unsetPrompt(WRONG_REQUEST_ID)
+
+            assertThat(repository.promptInfo.value).isNotNull()
+            assertThat(repository.userId.value).isNotNull()
+            assertThat(repository.challenge.value).isNotNull()
+            assertThat(repository.opPackageName.value).isNotNull()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
index 8695c01..c4d0d23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
@@ -33,6 +33,7 @@
 import org.mockito.junit.MockitoJUnit
 
 private const val USER_ID = 22
+private const val REQUEST_ID = 22L
 private const val OPERATION_ID = 100L
 private const val OP_PACKAGE_NAME = "biometric.testapp"
 
@@ -112,6 +113,7 @@
                 },
                 kind = PromptKind.Pin,
                 userId = USER_ID,
+                requestId = REQUEST_ID,
                 challenge = OPERATION_ID,
                 opPackageName = OP_PACKAGE_NAME
             )
@@ -137,6 +139,7 @@
                 },
                 kind = PromptKind.Pin,
                 userId = USER_ID,
+                requestId = REQUEST_ID,
                 challenge = OPERATION_ID,
                 opPackageName = OP_PACKAGE_NAME
             )
@@ -165,6 +168,7 @@
                 },
                 kind = PromptKind.Pin,
                 userId = USER_ID,
+                requestId = REQUEST_ID,
                 challenge = OPERATION_ID,
                 opPackageName = OP_PACKAGE_NAME
             )
@@ -198,6 +202,7 @@
                 },
                 kind = kind,
                 userId = USER_ID,
+                requestId = REQUEST_ID,
                 challenge = OPERATION_ID,
                 opPackageName = OP_PACKAGE_NAME
             )
@@ -223,7 +228,7 @@
                 assertThat(pattern.stealthMode).isEqualTo(isStealth)
             }
 
-            interactor.resetPrompt()
+            interactor.resetPrompt(REQUEST_ID)
 
             assertThat(prompt).isNull()
         }
@@ -346,12 +351,14 @@
         promptInfo: PromptInfo,
         kind: PromptKind,
         userId: Int,
+        requestId: Long,
         challenge: Long,
         opPackageName: String,
     ) {
         biometricPromptRepository.setPrompt(
             promptInfo,
             userId,
+            requestId,
             challenge,
             kind,
             opPackageName,
@@ -359,8 +366,8 @@
     }
 
     /** Unset the current authentication request. */
-    private fun PromptCredentialInteractor.resetPrompt() {
-        biometricPromptRepository.unsetPrompt()
+    private fun PromptCredentialInteractor.resetPrompt(requestId: Long) {
+        biometricPromptRepository.unsetPrompt(requestId)
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
index 4068404..3102a84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt
@@ -59,6 +59,7 @@
         private const val NEGATIVE_TEXT = "escape"
 
         private const val USER_ID = 8
+        private const val REQUEST_ID = 8L
         private const val CHALLENGE = 999L
         private const val OP_PACKAGE_NAME = "biometric.testapp"
         private val componentNameOverriddenForConfirmDeviceCredentialActivity =
@@ -150,6 +151,7 @@
         interactor.setPrompt(
             info,
             USER_ID,
+            REQUEST_ID,
             modalities,
             CHALLENGE,
             OP_PACKAGE_NAME,
@@ -179,7 +181,7 @@
         }
         assertThat(isConfirmationRequired).isEqualTo(confirmationRequired)
 
-        interactor.resetPrompt()
+        interactor.resetPrompt(REQUEST_ID)
         verifyUnset()
     }
 
@@ -206,6 +208,7 @@
             interactor.setPrompt(
                 info,
                 USER_ID,
+                REQUEST_ID,
                 modalities,
                 CHALLENGE,
                 OP_PACKAGE_NAME,
@@ -214,7 +217,7 @@
 
             assertThat(promptKind?.isBiometric()).isTrue()
 
-            interactor.resetPrompt()
+            interactor.resetPrompt(REQUEST_ID)
             verifyUnset()
         }
 
@@ -230,6 +233,7 @@
             interactor.setPrompt(
                 info,
                 USER_ID,
+                REQUEST_ID,
                 modalities,
                 CHALLENGE,
                 OP_PACKAGE_NAME,
@@ -238,7 +242,7 @@
 
             assertThat(promptKind).isEqualTo(PromptKind.Password)
 
-            interactor.resetPrompt()
+            interactor.resetPrompt(REQUEST_ID)
             verifyUnset()
         }
 
@@ -258,6 +262,7 @@
             interactor.setPrompt(
                 info,
                 USER_ID,
+                REQUEST_ID,
                 modalities,
                 CHALLENGE,
                 OP_PACKAGE_NAME,
@@ -266,7 +271,7 @@
 
             assertThat(promptKind).isEqualTo(PromptKind.Password)
 
-            interactor.resetPrompt()
+            interactor.resetPrompt(REQUEST_ID)
             verifyUnset()
         }
 
@@ -290,6 +295,7 @@
             interactor.setPrompt(
                 info,
                 USER_ID,
+                REQUEST_ID,
                 modalities,
                 CHALLENGE,
                 OP_PACKAGE_NAME,
@@ -298,7 +304,7 @@
 
             assertThat(promptKind).isEqualTo(PromptKind.Password)
 
-            interactor.resetPrompt()
+            interactor.resetPrompt(REQUEST_ID)
             verifyUnset()
         }
 
@@ -319,6 +325,7 @@
             interactor.setPrompt(
                 info,
                 USER_ID,
+                REQUEST_ID,
                 modalities,
                 CHALLENGE,
                 OP_PACKAGE_NAME,
@@ -327,7 +334,7 @@
 
             assertThat(promptKind?.isBiometric()).isTrue()
 
-            interactor.resetPrompt()
+            interactor.resetPrompt(REQUEST_ID)
             verifyUnset()
         }
 
@@ -355,6 +362,7 @@
         interactor.setPrompt(
             info,
             USER_ID,
+            REQUEST_ID,
             BiometricModalities(),
             CHALLENGE,
             OP_PACKAGE_NAME,
@@ -365,7 +373,7 @@
         assertThat(currentPrompt).isNull()
         assertThat(credentialKind).isEqualTo(PromptKind.None)
 
-        interactor.resetPrompt()
+        interactor.resetPrompt(REQUEST_ID)
         verifyUnset()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
index 3245020..9e804c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModelTest.kt
@@ -22,6 +22,7 @@
 import org.junit.runners.JUnit4
 
 private const val USER_ID = 9
+private const val REQUEST_ID = 9L
 private const val OPERATION_ID = 10L
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -171,7 +172,7 @@
     ) =
         runTest(dispatcher) {
             init()
-            promptRepository.setPrompt(promptInfo(), USER_ID, OPERATION_ID, kind)
+            promptRepository.setPrompt(promptInfo(), USER_ID, REQUEST_ID, OPERATION_ID, kind)
             block()
         }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index fa78f0c..53ccb90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -96,6 +96,7 @@
 import org.mockito.junit.MockitoJUnit
 
 private const val USER_ID = 4
+private const val REQUEST_ID = 4L
 private const val CHALLENGE = 2L
 private const val DELAY = 1000L
 private const val OP_PACKAGE_NAME = "biometric.testapp"
@@ -1457,7 +1458,7 @@
         whenever(activityTaskManager.getTasks(1)).thenReturn(listOf(runningTaskInfo))
         selector =
             PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
-        selector.resetPrompt()
+        selector.resetPrompt(REQUEST_ID)
 
         viewModel =
             PromptViewModel(
@@ -1688,6 +1689,7 @@
     setPrompt(
         info,
         USER_ID,
+        REQUEST_ID,
         BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face),
         CHALLENGE,
         packageName,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 53560d7..48a5df9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -25,16 +25,19 @@
 import androidx.test.filters.SmallTest
 import com.android.app.animation.Interpolators
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
 import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
 import com.android.systemui.keyguard.shared.model.TransitionInfo
 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.util.KeyguardTransitionRunner
+import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -45,6 +48,8 @@
 import kotlinx.coroutines.flow.dropWhile
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.advanceTimeBy
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.After
@@ -372,6 +377,43 @@
             assertThat(wtfHandler.failed).isTrue()
         }
 
+    @Test
+    fun simulateRaceConditionIsProcessedInOrder() =
+        testScope.runTest {
+            val ktr = KeyguardTransitionRepositoryImpl(kosmos.testDispatcher)
+            val steps by collectValues(ktr.transitions.dropWhile { step -> step.from == OFF })
+
+            // Add a delay to the first transition in order to attempt to have the second transition
+            // be processed first
+            val info1 = TransitionInfo(OWNER_NAME, AOD, LOCKSCREEN, animator = null)
+            launch {
+                ktr.forceDelayForRaceConditionTest = true
+                ktr.startTransition(info1)
+            }
+            val info2 = TransitionInfo(OWNER_NAME, LOCKSCREEN, OCCLUDED, animator = null)
+            launch {
+                ktr.forceDelayForRaceConditionTest = false
+                ktr.startTransition(info2)
+            }
+
+            runCurrent()
+            assertThat(steps.isEmpty()).isTrue()
+
+            advanceTimeBy(60L)
+            assertThat(steps[0])
+                .isEqualTo(
+                    TransitionStep(info1.from, info1.to, 0f, TransitionState.STARTED, OWNER_NAME)
+                )
+            assertThat(steps[1])
+                .isEqualTo(
+                    TransitionStep(info1.from, info1.to, 0f, TransitionState.CANCELED, OWNER_NAME)
+                )
+            assertThat(steps[2])
+                .isEqualTo(
+                    TransitionStep(info2.from, info2.to, 0f, TransitionState.STARTED, OWNER_NAME)
+                )
+        }
+
     private fun listWithStep(
         step: BigDecimal,
         start: BigDecimal = BigDecimal.ZERO,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 00f94a5..fa3fe5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -1669,7 +1669,9 @@
             // THEN a transition from DOZING => OCCLUDED should occur
             assertThat(transitionRepository)
                 .startedTransition(
-                    ownerName = "FromDozingTransitionInteractor",
+                    ownerName =
+                        "FromDozingTransitionInteractor" +
+                            "(keyguardInteractor.onCameraLaunchDetected)",
                     from = KeyguardState.DOZING,
                     to = KeyguardState.OCCLUDED,
                     animatorAssertion = { it.isNotNull() },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index a77169e..2b8a644 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -20,8 +20,11 @@
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
@@ -30,6 +33,7 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.mock
@@ -38,6 +42,7 @@
 import junit.framework.Assert.assertEquals
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -727,42 +732,48 @@
 
     @Test
     @EnableSceneContainer
-    fun sceneContainer_lockscreenVisibility_visibleWhenNotGone() =
+    fun lockscreenVisibility() =
         testScope.runTest {
-            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
+            val isDeviceUnlocked by
+                collectLastValue(
+                    kosmos.deviceUnlockedInteractor.deviceUnlockStatus.map { it.isUnlocked }
+                )
+            assertThat(isDeviceUnlocked).isFalse()
 
-            sceneTransitions.value = lsToGone
+            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+
+            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
             assertThat(lockscreenVisibility).isTrue()
 
-            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
-            assertThat(lockscreenVisibility).isFalse()
-
-            sceneTransitions.value = goneToLs
-            assertThat(lockscreenVisibility).isFalse()
-
-            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+            kosmos.sceneInteractor.changeScene(Scenes.Bouncer, "")
+            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
             assertThat(lockscreenVisibility).isTrue()
-        }
 
-    @Test
-    @EnableSceneContainer
-    fun sceneContainer_lockscreenVisibility_notVisibleWhenReturningToGone() =
-        testScope.runTest {
-            val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility)
-
-            sceneTransitions.value = goneToLs
+            kosmos.authenticationInteractor.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)
+            assertThat(isDeviceUnlocked).isTrue()
+            kosmos.sceneInteractor.changeScene(Scenes.Gone, "")
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
             assertThat(lockscreenVisibility).isFalse()
 
-            sceneTransitions.value = lsToGone
+            kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
             assertThat(lockscreenVisibility).isFalse()
 
-            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone)
+            kosmos.sceneInteractor.changeScene(Scenes.QuickSettings, "")
+            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
             assertThat(lockscreenVisibility).isFalse()
 
-            sceneTransitions.value = goneToLs
+            kosmos.sceneInteractor.changeScene(Scenes.Shade, "")
+            assertThat(currentScene).isEqualTo(Scenes.Shade)
             assertThat(lockscreenVisibility).isFalse()
 
-            sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen)
+            kosmos.sceneInteractor.changeScene(Scenes.Gone, "")
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+            assertThat(lockscreenVisibility).isFalse()
+
+            kosmos.sceneInteractor.changeScene(Scenes.Lockscreen, "")
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
             assertThat(lockscreenVisibility).isTrue()
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
index 9ec9b69..05d9495 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/DragDownHelperTest.kt
@@ -17,8 +17,8 @@
 
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.ExpandHelper
 import com.android.systemui.SysuiTestCase
@@ -39,7 +39,7 @@
 
 @SmallTest
 @TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class DragDownHelperTest : SysuiTestCase() {
 
     private lateinit var dragDownHelper: DragDownHelper
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 1504d4c..995b538 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -65,9 +65,9 @@
 import android.hardware.biometrics.BiometricSourceType;
 import android.os.BatteryManager;
 import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
@@ -88,7 +88,7 @@
 import java.util.Set;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
index cdc7520..4a14f88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
 import kotlinx.coroutines.Dispatchers
@@ -28,7 +28,7 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class KeyguardIndicationControllerWithCoroutinesTest : KeyguardIndicationControllerBaseTest() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
index 8cb530c..948a732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
@@ -1,7 +1,7 @@
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
 import android.util.DisplayMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.LogBuffer
@@ -16,7 +16,7 @@
 import org.mockito.Mock
 import org.mockito.junit.MockitoJUnit
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class LSShadeTransitionLoggerTest : SysuiTestCase() {
     lateinit var logger: LSShadeTransitionLogger
@@ -41,4 +41,4 @@
         // log a non-null, non row, ensure no crash
         logger.logDragDownStarted(view)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
index d3befb4..fe2dd6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
@@ -28,7 +28,7 @@
 import org.junit.runner.RunWith
 import java.util.function.Consumer
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class LightRevealScrimTest : SysuiTestCase() {
 
@@ -85,4 +85,4 @@
     private const val DEFAULT_WIDTH = 42
     private const val DEFAULT_HEIGHT = 24
   }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
index 402d9aa..e48242a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeQsTransitionControllerTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -36,7 +36,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class LockscreenShadeQsTransitionControllerTest : SysuiTestCase() {
 
     private val configurationController = FakeConfigurationController()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index a92cf8c..69e8f47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -1,9 +1,9 @@
 package com.android.systemui.statusbar
 
 import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.ExpandHelper
 import com.android.systemui.SysUITestModule
@@ -74,7 +74,7 @@
 
 @SmallTest
 @RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @OptIn(ExperimentalCoroutinesApi::class)
 class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index d3febf5..ef1c927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -32,8 +32,8 @@
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class NotificationListenerTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
     private static final int TEST_UID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index d3850be..c9d910c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -27,9 +27,9 @@
 import android.content.Context;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotificationRemoteInputManagerTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index fc0c85e..9f94cff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -17,11 +17,11 @@
 package com.android.systemui.statusbar
 
 import android.os.IBinder
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.Choreographer
 import android.view.View
 import android.view.ViewRootImpl
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ShadeInterpolation
@@ -59,7 +59,7 @@
 import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 @SmallTest
 class NotificationShadeDepthControllerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
index 49e5c45..9907740 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt
@@ -17,8 +17,8 @@
 
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -43,7 +43,7 @@
 
 @SmallTest
 @TestableLooper.RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class PulseExpansionHandlerTest : SysuiTestCase() {
 
     private lateinit var pulseExpansionHandler: PulseExpansionHandler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
index ce11d6a..58943ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RemoteInputNotificationRebuilderTest.java
@@ -27,9 +27,9 @@
 import android.net.Uri;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -44,7 +44,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class RemoteInputNotificationRebuilderTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
index 2606be5..6b9a19a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
@@ -1,7 +1,7 @@
 package com.android.systemui.statusbar
 
 import org.mockito.Mockito.`when` as whenever
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
@@ -14,7 +14,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class SingleShadeLockScreenOverScrollerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 775dc3c..3346e19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -29,9 +29,9 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -52,7 +52,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 @SmallTest
 public class SmartReplyControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
index 700fb1e..58473c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
@@ -1,7 +1,7 @@
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -23,7 +23,7 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 @TestableLooper.RunWithLooper
 class SplitShadeLockScreenOverScrollerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
index 79a2008..26692c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import org.junit.Assert.assertEquals
@@ -24,7 +24,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class StatusBarStateEventTest : SysuiTestCase() {
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
index b905825..78c1887 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
@@ -5,9 +5,9 @@
 import android.os.VibrationAttributes
 import android.os.VibrationEffect
 import android.os.Vibrator
-import android.testing.AndroidTestingRunner
 import android.view.HapticFeedbackConstants
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.eq
@@ -26,7 +26,7 @@
 import org.mockito.junit.MockitoJUnit
 import java.util.concurrent.Executor
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class VibratorHelperTest : SysuiTestCase() {
 
@@ -120,4 +120,4 @@
 
         return verify(vibrator)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
index 7e88ae0..643acdb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.connectivity
 
 import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.lifecycle.Lifecycle
 import com.android.systemui.SysuiTestCase
@@ -42,7 +42,7 @@
 import java.util.concurrent.Executor
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 class AccessPointControllerImplTest : SysuiTestCase() {
 
@@ -244,4 +244,4 @@
         verify(wifiEntryOther).connect(any())
         verify(callback, never()).onSettingsActivityTriggered(any())
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt
index 7aed4f7..40f81e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/MobileStateTest.kt
@@ -15,7 +15,7 @@
  */
 package com.android.systemui.statusbar.connectivity
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.SysuiTestCase
@@ -26,7 +26,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class MobileStateTest : SysuiTestCase() {
 
     private val state = MobileState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
index 461d804..4241254 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerDataTest.java
@@ -39,10 +39,10 @@
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.SignalIcon.MobileIconGroup;
@@ -60,7 +60,7 @@
 import java.util.HashMap;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class NetworkControllerDataTest extends NetworkControllerBaseTest {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
index 3bbf06d..521cb4f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerEthernetTest.java
@@ -19,9 +19,9 @@
 import static junit.framework.Assert.assertEquals;
 
 import android.net.NetworkCapabilities;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -30,7 +30,7 @@
 import org.mockito.Mockito;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class NetworkControllerEthernetTest extends NetworkControllerBaseTest {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
index 35609a5..22f0e9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerSignalTest.java
@@ -33,10 +33,10 @@
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.graph.SignalDrawable;
@@ -59,7 +59,7 @@
 import java.util.List;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class NetworkControllerSignalTest extends NetworkControllerBaseTest {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
index 44a1c50..6c80a97 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkControllerWifiTest.java
@@ -34,9 +34,9 @@
 import android.net.vcn.VcnTransportInfo;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.mobile.TelephonyIcons;
@@ -50,7 +50,7 @@
 import java.util.Collections;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
     // These match the constants in WifiManager and need to be kept up to date.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
index 5bf0a94..3eeed73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/NetworkTypeResIdCacheTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.connectivity
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.SignalIcon.MobileIconGroup
 import com.android.systemui.SysuiTestCase
@@ -26,7 +26,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NetworkTypeResIdCacheTest : SysuiTestCase() {
     private lateinit var cache: NetworkTypeResIdCache
     private var overrides = MobileIconCarrierIdOverridesFake()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
index 452302d..984bda1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
@@ -19,11 +19,11 @@
 import android.content.Context
 import android.graphics.Insets
 import android.graphics.Rect
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.Gravity
 import android.view.View
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
@@ -46,7 +46,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class SystemEventChipAnimationControllerTest : SysuiTestCase() {
     private lateinit var controller: SystemEventChipAnimationController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
index ae84df5..742494b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.events
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
@@ -40,7 +40,7 @@
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
index cacfa8d..376873d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemStatusAnimationSchedulerImplTest.kt
@@ -19,10 +19,10 @@
 import android.graphics.Insets
 import android.graphics.Rect
 import android.os.Process
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.View
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
@@ -54,7 +54,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
index d3f5ade..0f58990 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
@@ -1,9 +1,9 @@
 package com.android.systemui.statusbar.gesture
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.InputEvent
 import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.settings.FakeDisplayTracker
@@ -13,7 +13,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class GenericGestureDetectorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
index 6b2ee76..01a0fd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java
@@ -19,11 +19,11 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.widget.FrameLayout;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class AboveShelfObserverTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
index fc4702c..d66b010 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java
@@ -42,9 +42,9 @@
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -58,7 +58,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class AssistantFeedbackControllerTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
index 0103564..77fd067 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java
@@ -25,12 +25,12 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
 import android.view.LayoutInflater;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -56,7 +56,7 @@
 import java.util.Map;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class DynamicChildBindControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 5b72ca0..d879fce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -25,9 +25,9 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -38,9 +38,10 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
-@org.junit.runner.RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class DynamicPrivacyControllerTest extends SysuiTestCase {
 
@@ -127,4 +128,4 @@
         mDynamicPrivacyController.onUnlockedChanged();
         verifyNoMoreInteractions(mListener);
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
index 1cce3b5..9e733be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
@@ -16,15 +16,17 @@
 
 package com.android.systemui.statusbar.notification
 
+import android.platform.test.annotations.DisableFlags
 import android.provider.DeviceConfig
 import android.provider.Settings
-import android.testing.AndroidTestingRunner
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.dx.mockito.inline.extended.ExtendedMockito
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
 import com.android.systemui.util.DeviceConfigProxyFake
 import com.android.systemui.util.Utils
 import com.android.systemui.util.mockito.any
@@ -39,8 +41,9 @@
 import org.mockito.MockitoSession
 import org.mockito.quality.Strictness
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
+@DisableFlags(PriorityPeopleSection.FLAG_NAME)  // this class has no logic with the flag enabled
 class NotificationSectionsFeatureManagerTest : SysuiTestCase() {
     var manager: NotificationSectionsFeatureManager? = null
     val proxyFake = DeviceConfigProxyFake()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
index 3b3f05d..3abdf62 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationTransitionAnimatorControllerTest.kt
@@ -1,9 +1,9 @@
 package com.android.systemui.statusbar.notification
 
 import android.app.Notification.GROUP_ALERT_SUMMARY
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -35,7 +35,7 @@
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotificationTransitionAnimatorControllerTest : SysuiTestCase() {
     @Mock lateinit var notificationListContainer: NotificationListContainer
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
index 1aac515..a5206f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLoggerTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.notification
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.LogBuffer
@@ -28,7 +28,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class NotificationWakeUpCoordinatorLoggerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index 67b540c..0906d8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.notification
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
@@ -60,7 +60,7 @@
 import org.mockito.Mockito.verifyNoMoreInteractions
 
 @OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class NotificationWakeUpCoordinatorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
index 7d8cf36..382b307 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
@@ -2,6 +2,7 @@
 
 import android.platform.test.annotations.EnableFlags
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.shared.NotificationsImprovedHunAnimation
@@ -10,13 +11,12 @@
 import org.junit.Assert.assertEquals
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class RoundableTest : SysuiTestCase() {
     private val targetView: View = mock()
     private val roundable = FakeRoundable(targetView = targetView)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 2d044fe..8e95ac5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -30,8 +30,8 @@
 
 import android.app.Notification;
 import android.app.NotificationChannel;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -51,7 +51,7 @@
 import java.util.List;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class HighPriorityProviderTest extends SysuiTestCase {
     @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
     @Mock private GroupMembershipManager mGroupMembershipManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
index 892575a..2a58751 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.systemui.statusbar.notification.collection
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.lifecycle.Observer
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -34,7 +34,7 @@
 import org.mockito.Mockito.verifyNoMoreInteractions
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotifLiveDataImplTest : SysuiTestCase() {
 
@@ -164,4 +164,4 @@
         assertThat(executor.runAllReady()).isEqualTo(2)
         verifyNoMoreInteractions(syncObserver, asyncObserver)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
index 9c8ac5c..d87f827 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.notification.collection
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -30,7 +30,7 @@
 import java.lang.UnsupportedOperationException
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotifLiveDataStoreImplTest : SysuiTestCase() {
 
@@ -102,4 +102,4 @@
         liveDataStoreImpl.setActiveNotifList(mutableListOf(entry1, entry2))
         executor.runAllReady()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
index 3b908b4..f1da22f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.notification.collection
 
-import android.testing.AndroidTestingRunner
 import android.view.Choreographer
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dagger.SysUISingleton
@@ -36,7 +36,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotifPipelineChoreographerTest : SysuiTestCase() {
 
     val viewChoreographer: Choreographer = mock()
@@ -118,4 +118,4 @@
             @BindsInstance @Main executor: DelayableExecutor
         ): NotifPipelineChoreographerTestComponent
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 8a48fe1..72d1db3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -46,8 +46,8 @@
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -64,7 +64,7 @@
 import java.util.ArrayList;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class NotificationEntryTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
     private static final int TEST_UID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
index ab55a7d..1fd6b04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/SectionStyleProviderTest.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
@@ -47,7 +47,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class SectionStyleProviderTest : SysuiTestCase() {
 
     @Rule @JvmField public val setFlagsRule = SetFlagsRule()
@@ -118,4 +118,4 @@
             override fun getSection(): NotifSection? = NotifSection(inputSectioner, 1)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
index 4708350..2ad3c9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
@@ -25,7 +25,7 @@
 import android.os.UserHandle
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -48,7 +48,7 @@
 private const val USER_ID = -1
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class TargetSdkResolverTest : SysuiTestCase() {
     private val packageManager: PackageManager = mock()
     private val applicationInfo = ApplicationInfo().apply { targetSdkVersion = SDK_VERSION }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
index b1180ae..f029a2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java
@@ -30,8 +30,8 @@
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -57,7 +57,7 @@
 import java.util.Collections;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class GroupCoalescerTest extends SysuiTestCase {
 
     private GroupCoalescer mCoalescer;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
index f2207af..1f29255 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.java
@@ -30,9 +30,9 @@
 import android.content.Intent;
 import android.graphics.Color;
 import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class ColorizedFgsCoordinatorTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
index 59fc591..e72109d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -39,7 +39,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class DataStoreCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: DataStoreCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
index f91e5a8..543f0c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinatorTest.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.notification.collection.coordinator
 
 import android.app.Notification
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -38,7 +38,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class DismissibilityCoordinatorTest : SysuiTestCase() {
 
     private lateinit var coordinator: DismissibilityCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
index a544cad..4d5ea92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DreamCoordinatorTest.kt
@@ -17,7 +17,7 @@
 
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -49,7 +49,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class DreamCoordinatorTest : SysuiTestCase() {
     @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
     @Mock private lateinit var notifPipeline: NotifPipeline
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
index 929c3d4..7b688d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -36,7 +36,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class GroupCountCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: GroupCountCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
index eac0e29..3f14026 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupWhenCoordinatorTest.kt
@@ -16,8 +16,8 @@
 package com.android.systemui.statusbar.notification.collection.coordinator
 
 import android.app.Notification
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.SbnBuilder
@@ -45,7 +45,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class GroupWhenCoordinatorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
index a652ad6..7fe97d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -42,7 +42,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class GutsCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: GutsCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index cd75e08..8e9323f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -17,8 +17,8 @@
 
 import android.app.Notification.GROUP_ALERT_ALL
 import android.app.Notification.GROUP_ALERT_SUMMARY
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.logcatLogBuffer
@@ -70,7 +70,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class HeadsUpCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: HeadsUpCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
index 27542a4..5dcad4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
@@ -24,9 +24,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.util.SparseArray;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -47,7 +47,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase {
 
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 5ff7353..25533d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -20,7 +20,7 @@
 import android.app.Notification
 import android.os.UserHandle
 import android.provider.Settings
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -67,7 +67,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class KeyguardCoordinatorTest : SysuiTestCase() {
 
     private val headsUpManager: HeadsUpManager = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
index e90a3ac8..07c29a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -33,8 +33,8 @@
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.service.notification.NotificationListenerService;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -58,7 +58,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public final class MediaCoordinatorTest extends SysuiTestCase {
 
     private MediaSession mMediaSession;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
index c29ff41..501bca2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/NotificationStatsLoggerCoordinatorTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.EnableFlags
 import android.service.notification.NotificationListenerService.REASON_CANCEL
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -36,7 +36,7 @@
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @EnableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
 class NotificationStatsLoggerCoordinatorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index cceaaea..8012768 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -39,10 +39,10 @@
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -88,7 +88,7 @@
 import java.util.Map;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class PreparationCoordinatorTest extends SysuiTestCase {
     private NotifCollectionListener mCollectionListener;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index 3d1253e..c05b131 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -35,9 +35,9 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
-import android.testing.AndroidTestingRunner;
 
 import androidx.annotation.Nullable;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -67,7 +67,7 @@
 import java.util.Arrays;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class RankingCoordinatorTest extends SysuiTestCase {
 
     @Mock private StatusBarStateController mStatusBarStateController;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
index d3df48e9..deb3fc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
@@ -23,8 +23,8 @@
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -54,7 +54,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class RemoteInputCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: RemoteInputCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
index 7daadb0..1b7ec53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
@@ -37,7 +37,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class RowAlertTimeCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: RowAlertTimeCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
index a66f8ce..5b231e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.AssistantFeedbackController
@@ -41,7 +41,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class RowAppearanceCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: RowAppearanceCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
index 56f16f3..ccf7cdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
@@ -17,8 +17,8 @@
 
 import android.service.notification.NotificationListenerService.REASON_APP_CANCEL
 import android.service.notification.NotificationListenerService.REASON_CANCEL
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.logcatLogBuffer
@@ -40,7 +40,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class ShadeEventCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: ShadeEventCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
index ea4f692..c7513de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
@@ -17,8 +17,8 @@
 
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING
 import com.android.systemui.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING_BUG_FIX
@@ -51,7 +51,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class StackCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: StackCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
index b1d2ea21..c8fbe61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.coordinator
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
@@ -40,7 +40,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class ViewConfigCoordinatorTest : SysuiTestCase() {
     private lateinit var coordinator: ViewConfigCoordinator
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
index 8e6cecc..7943872 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
@@ -20,8 +20,8 @@
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.provider.Settings.Secure.SHOW_NOTIFICATION_SNOOZE
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING
 import com.android.systemui.SysuiTestCase
@@ -54,7 +54,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotifUiAdjustmentProviderTest : SysuiTestCase() {
     private val lockscreenUserManager: NotificationLockscreenUserManager = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
index 1cdd023..d205770 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/SemiStableSortTest.kt
@@ -15,9 +15,9 @@
  */
 package com.android.systemui.statusbar.notification.collection.listbuilder
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import org.junit.Assert.assertFalse
@@ -27,7 +27,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class SemiStableSortTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
index 2036954..49f836f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderHelperTest.kt
@@ -15,8 +15,8 @@
  */
 package com.android.systemui.statusbar.notification.collection.listbuilder
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.listbuilder.ShadeListBuilderHelper.getContiguousSubLists
@@ -25,7 +25,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class ShadeListBuilderHelperTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
index 22f6bdc..341a51e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.notification.collection.notifcollection
 
 import android.service.notification.NotificationListenerService.RankingMap
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.logcatLogBuffer
@@ -34,7 +34,7 @@
 import org.mockito.Mockito.verifyNoMoreInteractions
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotifCollectionInconsistencyTrackerTest : SysuiTestCase() {
     private val logger = spy(NotifCollectionLogger(logcatLogBuffer()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
index a09f3a3..99e55a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
@@ -16,8 +16,8 @@
 package com.android.systemui.statusbar.notification.collection.notifcollection
 
 import android.os.Handler
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -41,7 +41,7 @@
 import java.util.function.Predicate
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class SelfTrackingLifetimeExtenderTest : SysuiTestCase() {
     private lateinit var extender: TestableSelfTrackingLifetimeExtender
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
index b56f8e9..586b947 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
@@ -15,7 +15,7 @@
  */
 package com.android.systemui.statusbar.notification.collection.provider
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.mock
@@ -29,7 +29,7 @@
 import org.mockito.Mockito.verifyNoMoreInteractions
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class VisualStabilityProviderTest : SysuiTestCase() {
     private val visualStabilityProvider = VisualStabilityProvider()
     private val listener: OnReorderingAllowedListener = mock()
@@ -148,4 +148,4 @@
         visualStabilityProvider.isReorderingAllowed = true
         verify(selfAddingListener, times(2)).onReorderingAllowed()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
index eeabc74..9d3e2e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.kt
@@ -16,10 +16,10 @@
 package com.android.systemui.statusbar.notification.collection.render
 
 import android.content.Context
-import android.testing.AndroidTestingRunner
 import android.view.View
 import android.view.ViewGroup
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.logcatLogBuffer
@@ -34,7 +34,7 @@
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class ShadeViewDifferTest : SysuiTestCase() {
     private lateinit var differ: ShadeViewDiffer
     private val rootController = FakeController(mContext, "RootController")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt
index 2a3c1a5..3908529 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/SeenNotificationsInteractorTest.kt
@@ -15,7 +15,7 @@
 
 package com.android.systemui.statusbar.notification.domain.interactor
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -25,7 +25,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class SeenNotificationsInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
index 4ac9dc2..bfa816e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
@@ -30,8 +30,8 @@
 import android.os.Bundle
 import android.os.SystemClock
 import android.os.UserHandle
-import android.testing.AndroidTestingRunner
 import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
@@ -53,7 +53,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class IconManagerTest : SysuiTestCase() {
     companion object {
         private const val TEST_PACKAGE_NAME = "test"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
index b410b33..c9f2add 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -15,7 +15,7 @@
 
 package com.android.systemui.statusbar.notification.icon.domain.interactor
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysUITestComponent
 import com.android.systemui.SysUITestModule
@@ -52,7 +52,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotificationIconsInteractorTest : SysuiTestCase() {
 
     private val bubbles: Bubbles = mock()
@@ -151,7 +151,7 @@
 }
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
 
     private val bubbles: Bubbles = mock()
@@ -256,7 +256,7 @@
 }
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
 
     private val bubbles: Bubbles = mock()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
index 60eea9b..af2789b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderTest.java
@@ -26,9 +26,9 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 
 import androidx.core.os.CancellationSignal;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.NotificationMessagingUtil;
@@ -47,7 +47,7 @@
 
 import java.util.concurrent.atomic.AtomicReference;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class HeadsUpViewBinderTest extends SysuiTestCase {
     private HeadsUpViewBinder mViewBinder;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 8662048..19214fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -42,9 +42,9 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
@@ -86,7 +86,7 @@
 import java.util.function.Consumer;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class KeyguardNotificationVisibilityProviderTest  extends SysuiTestCase {
     private static final int NOTIF_USER_ID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 7ade053..3e8461a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -60,8 +60,8 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.testing.UiEventLoggerFake;
@@ -96,7 +96,7 @@
  * Tests for the interruption state provider which understands whether the system & notification
  * is in a state allowing a particular notification to hun, pulse, or bubble.
  */
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
index 7ed3312..a6177e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapperTest.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.notification.interruption
 
 import android.platform.test.annotations.DisableFlags
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider.FullScreenIntentDecision
@@ -34,7 +34,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @DisableFlags(VisualInterruptionRefactor.FLAG_NAME)
 class NotificationInterruptStateProviderWrapperTest : VisualInterruptionDecisionProviderTestBase() {
     override val provider by lazy {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
index edab9d9..eeb51a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImplTest.kt
@@ -16,11 +16,13 @@
 
 package com.android.systemui.statusbar.notification.interruption
 
+import android.Manifest.permission
 import android.app.Notification.CATEGORY_EVENT
 import android.app.Notification.CATEGORY_REMINDER
 import android.app.NotificationManager
+import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.BUBBLE
@@ -28,9 +30,11 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType.PULSE
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.`when`
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @EnableFlags(VisualInterruptionRefactor.FLAG_NAME)
 class VisualInterruptionDecisionProviderImplTest : VisualInterruptionDecisionProviderTestBase() {
     override val provider by lazy {
@@ -51,7 +55,8 @@
             uiEventLogger,
             userTracker,
             avalancheProvider,
-            systemSettings
+            systemSettings,
+            packageManager
         )
     }
 
@@ -83,14 +88,18 @@
     fun testAvalancheFilter_duringAvalanche_allowConversationFromAfterEvent() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_HIGH
-                isConversation = true
-                isImportantConversation = false
-                whenMs = whenAgo(5)
-            })
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                    isConversation = true
+                    isImportantConversation = false
+                    whenMs = whenAgo(5)
+                }
+            )
         }
     }
 
@@ -98,14 +107,18 @@
     fun testAvalancheFilter_duringAvalanche_suppressConversationFromBeforeEvent() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldNotHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_DEFAULT
-                isConversation = true
-                isImportantConversation = false
-                whenMs = whenAgo(15)
-            })
+            assertShouldNotHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_DEFAULT
+                    isConversation = true
+                    isImportantConversation = false
+                    whenMs = whenAgo(15)
+                }
+            )
         }
     }
 
@@ -113,12 +126,16 @@
     fun testAvalancheFilter_duringAvalanche_allowHighPriorityConversation() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_HIGH
-                isImportantConversation = true
-            })
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                    isImportantConversation = true
+                }
+            )
         }
     }
 
@@ -126,12 +143,16 @@
     fun testAvalancheFilter_duringAvalanche_allowCall() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_HIGH
-                isCall = true
-            })
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                    isCall = true
+                }
+            )
         }
     }
 
@@ -139,12 +160,16 @@
     fun testAvalancheFilter_duringAvalanche_allowCategoryReminder() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_HIGH
-                category = CATEGORY_REMINDER
-            })
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                    category = CATEGORY_REMINDER
+                }
+            )
         }
     }
 
@@ -152,12 +177,16 @@
     fun testAvalancheFilter_duringAvalanche_allowCategoryEvent() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_HIGH
-                category = CATEGORY_EVENT
-            })
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                    category = CATEGORY_EVENT
+                }
+            )
         }
     }
 
@@ -165,7 +194,9 @@
     fun testAvalancheFilter_duringAvalanche_allowFsi() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             assertFsiNotSuppressed()
         }
     }
@@ -174,16 +205,44 @@
     fun testAvalancheFilter_duringAvalanche_allowColorized() {
         avalancheProvider.startTime = whenAgo(10)
 
-        withFilter(AvalancheSuppressor(avalancheProvider, systemClock, systemSettings)) {
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
             ensurePeekState()
-            assertShouldHeadsUp(buildEntry {
-                importance = NotificationManager.IMPORTANCE_HIGH
-                isColorized = true
-            })
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                    isColorized = true
+                }
+            )
         }
     }
 
     @Test
+    fun testAvalancheFilter_duringAvalanche_allowEmergency() {
+        avalancheProvider.startTime = whenAgo(10)
+
+        `when`(
+            packageManager.checkPermission(
+                org.mockito.Mockito.eq(permission.RECEIVE_EMERGENCY_BROADCAST),
+                anyString()
+            )
+        ).thenReturn(PERMISSION_GRANTED)
+
+        withFilter(
+            AvalancheSuppressor(avalancheProvider, systemClock, systemSettings, packageManager)
+        ) {
+            ensurePeekState()
+            assertShouldHeadsUp(
+                buildEntry {
+                    importance = NotificationManager.IMPORTANCE_HIGH
+                }
+            )
+        }
+    }
+
+
+    @Test
     fun testPeekCondition_suppressesOnlyPeek() {
         withCondition(TestCondition(types = setOf(PEEK)) { true }) {
             assertPeekSuppressed()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
index 3b979a7..71e7dc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestBase.kt
@@ -42,6 +42,7 @@
 import android.app.PendingIntent.FLAG_MUTABLE
 import android.content.Context
 import android.content.Intent
+import android.content.pm.PackageManager
 import android.content.pm.UserInfo
 import android.graphics.drawable.Icon
 import android.hardware.display.FakeAmbientDisplayConfiguration
@@ -129,6 +130,7 @@
     protected val userTracker = FakeUserTracker()
     protected val avalancheProvider: AvalancheProvider = mock()
     lateinit var systemSettings: SystemSettings
+    protected val packageManager: PackageManager = mock()
 
     protected abstract val provider: VisualInterruptionDecisionProvider
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
index 60aaa64..61c008b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderTestUtil.kt
@@ -15,11 +15,11 @@
  */
 package com.android.systemui.statusbar.notification.interruption
 
+import android.content.pm.PackageManager
 import android.hardware.display.AmbientDisplayConfiguration
 import android.os.Handler
 import android.os.PowerManager
 import com.android.internal.logging.UiEventLogger
-import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.settings.UserTracker
@@ -53,7 +53,8 @@
         uiEventLogger: UiEventLogger,
         userTracker: UserTracker,
         avalancheProvider: AvalancheProvider,
-        systemSettings: SystemSettings
+        systemSettings: SystemSettings,
+        packageManager: PackageManager,
     ): VisualInterruptionDecisionProvider {
         return if (VisualInterruptionRefactor.isEnabled) {
             VisualInterruptionDecisionProviderImpl(
@@ -73,7 +74,8 @@
                 uiEventLogger,
                 userTracker,
                 avalancheProvider,
-                systemSettings
+                systemSettings,
+                packageManager
             )
         } else {
             NotificationInterruptStateProviderWrapper(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
index 2662c80..5974171 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
@@ -22,9 +22,9 @@
 import static org.mockito.Mockito.verify;
 
 import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -44,7 +44,7 @@
 import java.util.Collections;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class ExpansionStateLoggerTest extends SysuiTestCase {
     private static final String NOTIFICATION_KEY = "notin_key";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 1113091..a8929a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -35,9 +35,9 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.InstanceId;
@@ -87,7 +87,7 @@
 import java.util.concurrent.Executor;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 @DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
 public class NotificationLoggerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt
index 4b0b4b8..3ea7732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryLoggerTest.kt
@@ -21,8 +21,8 @@
 import android.graphics.Bitmap
 import android.graphics.drawable.Icon
 import android.stats.sysui.NotificationEnums
-import android.testing.AndroidTestingRunner
 import android.util.StatsEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.assertLogsWtf
@@ -46,7 +46,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotificationMemoryLoggerTest : SysuiTestCase() {
 
     @Rule @JvmField val expect = Expect.create()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt
index 072a497..f10a52a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMeterTest.kt
@@ -24,8 +24,8 @@
 import android.graphics.Bitmap
 import android.graphics.drawable.Icon
 import android.stats.sysui.NotificationEnums
-import android.testing.AndroidTestingRunner
 import android.widget.RemoteViews
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.NotificationUtils
@@ -36,7 +36,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotificationMemoryMeterTest : SysuiTestCase() {
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt
index 4bb28ae..d7dde96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryViewWalkerTest.kt
@@ -3,9 +3,9 @@
 import android.app.Notification
 import android.graphics.Bitmap
 import android.graphics.drawable.Icon
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.widget.RemoteViews
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder
@@ -17,7 +17,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class NotificationMemoryViewWalkerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
index 9b9cb82..9f98fd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
@@ -17,9 +17,9 @@
 
 import android.annotation.ColorInt
 import android.graphics.Color
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.settingslib.Utils
 import com.android.systemui.res.R
@@ -34,7 +34,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class ActivatableNotificationViewTest : SysuiTestCase() {
     private val mContentView: View = mock()
@@ -98,4 +98,4 @@
         assertThat(mView.topRoundness).isEqualTo(1f)
         assertThat(mView.roundableState.hashCode()).isEqualTo(roundableState.hashCode())
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
index 0eae5fc..fda5cd2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/BigPictureIconManagerTest.kt
@@ -20,8 +20,8 @@
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Icon
 import android.net.Uri
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.NotificationDrawableConsumer
 import com.android.systemui.SysuiTestCase
@@ -50,7 +50,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWithLooper
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class BigPictureIconManagerTest : SysuiTestCase() {
 
     private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
index 7dcbd80..c5b19ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
@@ -25,8 +25,8 @@
 import android.graphics.Color
 import android.graphics.drawable.ColorDrawable
 import android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.View
 
@@ -47,7 +47,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class ChannelEditorDialogControllerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index 210b1a7..e738b61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -21,8 +21,8 @@
 import android.net.Uri
 import android.os.UserHandle
 import android.os.UserHandle.USER_ALL
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.statusbar.IStatusBarService
@@ -71,7 +71,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class ExpandableNotificationRowControllerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index 9d2f32d..1c5f37c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -31,10 +31,10 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class ExpandableNotificationRowDragControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index aa79c23..7304bd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -46,13 +46,13 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.DisplayMetrics;
 import android.view.View;
 import android.widget.ImageView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
@@ -87,7 +87,7 @@
 import java.util.function.Consumer;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class ExpandableNotificationRowTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index ffb8646..d04d6fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -45,13 +45,13 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.UiThreadTest;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -72,7 +72,7 @@
 import java.util.Locale;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @UiThreadTest
 public class FeedbackInfoTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
index 5e50af3..c325791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/HeadsUpStyleProviderImplTest.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
@@ -31,7 +31,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class HeadsUpStyleProviderImplTest : SysuiTestCase() {
 
     @Rule @JvmField val setFlagsRule = SetFlagsRule()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
index 25172de..18fd42d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineTest.java
@@ -22,11 +22,11 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.annotation.NonNull;
 import androidx.core.os.CancellationSignal;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -48,7 +48,7 @@
 import java.util.List;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotifBindPipelineTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
index e38adeb..29252b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifInflationErrorManagerTest.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.notification.row
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -33,7 +33,7 @@
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class NotifInflationErrorManagerTest : SysuiTestCase() {
     private lateinit var manager: NotifInflationErrorManager
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
index 20cc01a..8b1c95b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewCacheImplTest.java
@@ -26,9 +26,9 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 import android.widget.RemoteViews;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -45,7 +45,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class NotifRemoteViewCacheImplTest extends SysuiTestCase {
 
     private NotifRemoteViewCacheImpl mNotifRemoteViewCache;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 03a8403..a355cd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -40,7 +40,6 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.TypedValue;
@@ -49,6 +48,7 @@
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 import androidx.test.filters.Suppress;
 
@@ -79,7 +79,7 @@
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 @Suppress
 public class NotificationContentInflaterTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
index 7332bc3..2bb610a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt
@@ -20,7 +20,6 @@
 import android.content.res.Resources
 import android.os.UserHandle
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.ViewUtils
 import android.view.NotificationHeaderView
@@ -29,6 +28,7 @@
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.internal.widget.NotificationActionListLayout
@@ -60,7 +60,7 @@
 import org.mockito.MockitoAnnotations.initMocks
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class NotificationContentViewTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 97cb11e2..be89ab8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -65,13 +65,13 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -103,7 +103,7 @@
 import java.util.concurrent.CountDownLatch;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotificationConversationInfoTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 907649b..625963f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -57,12 +57,12 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArraySet;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -115,7 +115,7 @@
  * Tests for {@link NotificationGutsManager}.
  */
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotificationGutsManagerTest extends SysuiTestCase {
     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
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 1b85dfa..0b5f8d5 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
@@ -31,11 +31,11 @@
 import android.os.userManager
 import android.provider.Settings
 import android.service.notification.NotificationListenerService.Ranking
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.util.ArraySet
 import android.view.View
 import android.view.accessibility.accessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.internal.logging.MetricsLogger
@@ -91,7 +91,7 @@
 
 /** Tests for [NotificationGutsManager] with the scene container enabled. */
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 @EnableSceneContainer
 class NotificationGutsManagerWithScenesTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
index 7f9471e..350f90d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.notification.row
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.testing.ViewUtils
 import android.view.LayoutInflater
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
@@ -34,7 +34,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotificationGutsTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 13ced92..245a6a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -55,13 +55,13 @@
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.telecom.TelecomManager;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -85,7 +85,7 @@
 import java.util.concurrent.CountDownLatch;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotificationInfoTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
index e929028..027e899 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java
@@ -29,13 +29,13 @@
 import static org.mockito.Mockito.when;
 
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.testing.ViewUtils;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -49,7 +49,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @SmallTest
 public class NotificationMenuRowTest extends LeakCheckedTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
index 8261c1c..352b79f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSettingsControllerTest.kt
@@ -22,8 +22,8 @@
 import android.net.Uri
 import android.os.Handler
 import android.provider.Settings.Secure
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -54,7 +54,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class NotificationSettingsControllerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
index 4a91cd2..22f1e46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationSnoozeTest.java
@@ -23,11 +23,11 @@
 import static org.mockito.Mockito.mock;
 
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableResources;
 import android.testing.UiThreadTest;
 import android.util.KeyValueListParser;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -41,7 +41,7 @@
 import java.util.ArrayList;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @UiThreadTest
 public class NotificationSnoozeTest extends SysuiTestCase {
     private static final int RES_DEFAULT = 2;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 51665d9..57b0f3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -41,7 +41,6 @@
 import android.graphics.drawable.Icon;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.text.SpannableString;
 import android.view.LayoutInflater;
@@ -49,6 +48,7 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -69,7 +69,7 @@
 import java.util.concurrent.CountDownLatch;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class PartialConversationInfoTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test_package";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
index 1534c84..841cb4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowContentBindStageTest.java
@@ -34,10 +34,10 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.Log;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class RowContentBindStageTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
index 1c959af..53a1198 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineConversationViewBinderTest.kt
@@ -18,8 +18,8 @@
 import android.app.Notification
 import android.app.Person
 import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.systemui.SysuiTestCase
@@ -34,7 +34,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class SingleLineConversationViewBinderTest : SysuiTestCase() {
     private lateinit var notificationBuilder: Notification.Builder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
index f0fc349..ee819c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
@@ -17,8 +17,8 @@
 
 import android.app.Notification
 import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.systemui.SysuiTestCase
@@ -33,7 +33,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class SingleLineViewBinderTest : SysuiTestCase() {
     private lateinit var notificationBuilder: Notification.Builder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
index b67153a..e025d3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflaterTest.kt
@@ -27,9 +27,9 @@
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Icon
 import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.core.graphics.drawable.toBitmap
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
@@ -48,7 +48,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 @EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
 class SingleLineViewInflaterTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt
index d46763d..f8533a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/TextPrecomputerTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.notification.row
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.text.PrecomputedText
 import android.text.TextPaint
 import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
@@ -29,7 +29,7 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class TextPrecomputerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
index c960230..0dc871a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/ActivatableNotificationViewModelTest.kt
@@ -18,7 +18,7 @@
 
 package com.android.systemui.statusbar.notification.row.ui.viewmodel
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.accessibility.data.repository.FakeAccessibilityRepository
@@ -31,7 +31,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class ActivatableNotificationViewModelTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
index a15b4cd..ec280a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
@@ -24,10 +24,10 @@
 import android.graphics.drawable.AnimatedImageDrawable;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
-import android.testing.AndroidTestingRunner;
 import android.view.LayoutInflater;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
@@ -40,7 +40,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
index fe2971c..9d990b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapperTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.notification.row.wrapper
 
 import android.graphics.drawable.AnimatedImageDrawable
-import android.testing.AndroidTestingRunner
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.internal.widget.CachingIconView
@@ -38,7 +38,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotificationConversationTemplateViewWrapperTest : SysuiTestCase() {
 
     private lateinit var mRow: ExpandableNotificationRow
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
index 2d72c7e..f9a9704 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java
@@ -16,10 +16,10 @@
 
 package com.android.systemui.statusbar.notification.row.wrapper;
 
-import android.testing.AndroidTestingRunner;
 import android.view.View;
 import android.widget.RemoteViews;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -33,7 +33,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class NotificationCustomViewWrapperTest extends SysuiTestCase {
 
     private ExpandableNotificationRow mRow;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
index f26c18b..fc829d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMessagingTemplateViewWrapperTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.notification.row.wrapper
 
 import android.graphics.drawable.AnimatedImageDrawable
-import android.testing.AndroidTestingRunner
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.MessagingGroup
 import com.android.internal.widget.MessagingImageMessage
@@ -36,7 +36,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotificationMessagingTemplateViewWrapperTest : SysuiTestCase() {
 
     private lateinit var mRow: ExpandableNotificationRow
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
index 54eed26..1ce3bad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapperTest.kt
@@ -19,7 +19,6 @@
 import android.app.PendingIntent
 import android.app.PendingIntent.CancelListener
 import android.content.Intent
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.testing.ViewUtils
@@ -27,6 +26,7 @@
 import android.view.View
 import android.view.ViewGroup
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.systemui.SysuiTestCase
@@ -46,7 +46,7 @@
 import org.mockito.Mockito.verify
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotificationTemplateViewWrapperTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
index fad85f53..d17c8db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
@@ -20,11 +20,11 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.testing.AndroidTestingRunner;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class NotificationViewWrapperTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
index 59d98c2..4c6e25a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
@@ -19,7 +19,7 @@
 package com.android.systemui.statusbar.notification.shelf.domain.interactor
 
 import android.os.PowerManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -41,7 +41,7 @@
 import org.mockito.Mockito.isNull
 import org.mockito.Mockito.verify
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class NotificationShelfInteractorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 917569c..e2fb3ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
 
 import android.os.PowerManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysUITestComponent
 import com.android.systemui.SysUITestModule
@@ -44,7 +44,7 @@
 import org.mockito.Mockito
 import org.mockito.Mockito.verify
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class NotificationShelfViewModelTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
index fb15948..2349c25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -33,7 +33,7 @@
 
 private const val MAX_PULSE_HEIGHT = 100000f
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class AmbientStateTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
index f4e236e..3a77d82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
@@ -1,8 +1,8 @@
 package com.android.systemui.statusbar.notification.stack
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.LayoutInflater
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
@@ -15,7 +15,7 @@
  * Tests for {@link MediaContainView}.
  */
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class MediaContainerViewTest : SysuiTestCase() {
 
@@ -35,4 +35,4 @@
         mediaContainerView.updateClipping()
         assertTrue(mediaContainerView.clipHeight == 10)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 3b16f14..14bbd38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -21,13 +21,13 @@
 import android.app.Notification;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.NotificationHeaderView;
 import android.view.View;
 import android.widget.RemoteViews;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -45,7 +45,7 @@
 import java.util.List;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 //@DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
 public class NotificationChildrenContainerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 1eed420..48e8f88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -2,10 +2,10 @@
 
 import android.platform.test.annotations.DisableFlags
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.LayoutInflater
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.systemui.SysuiTestCase
@@ -35,7 +35,7 @@
 
 /** Tests for {@link NotificationShelf}. */
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 open class NotificationShelfTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index f262df1..ce2491b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -42,12 +42,12 @@
 import android.metrics.LogMaker;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewTreeObserver;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -126,7 +126,7 @@
  */
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class NotificationStackScrollLayoutControllerTest extends SysuiTestCase {
 
     protected KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 0c0a2a5..f461e2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -54,7 +54,6 @@
 import android.os.SystemClock;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableResources;
 import android.util.MathUtils;
@@ -65,6 +64,7 @@
 import android.view.WindowInsetsAnimation;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.BouncerPanelExpansionCalculator;
@@ -114,7 +114,7 @@
  * Tests for {@link NotificationStackScrollLayout}.
  */
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class NotificationStackScrollLayoutTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
index 6fec9ad..dae5542 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -18,8 +18,8 @@
 
 import android.annotation.DimenRes
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
 import android.view.View.VISIBLE
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
@@ -44,7 +44,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class NotificationStackSizeCalculatorTest : SysuiTestCase() {
 
     @Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 85a2bdd..2d11917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -37,12 +37,12 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.os.Handler;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -70,7 +70,7 @@
  * Tests for {@link NotificationSwipeHelper}.
  */
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper()
 public class NotificationSwipeHelperTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
index e30947c..660eb30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
@@ -1,8 +1,8 @@
 package com.android.systemui.statusbar.notification.stack
 
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FakeFeatureFlags
@@ -15,7 +15,7 @@
 
 /** Tests for {@link NotificationTargetsHelper}. */
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotificationTargetsHelperTest : SysuiTestCase() {
     private val featureFlags = FakeFeatureFlags()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
index 926c35f..798465e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.notification.stack
 
 import android.platform.test.annotations.EnableFlags
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
@@ -48,7 +48,7 @@
 private const val HEADS_UP_ABOVE_SCREEN = 80
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class StackStateAnimatorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
index cd6bb5f..e493420 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.notification.stack
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.assertDoesNotLogWtf
@@ -27,7 +27,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class ViewStateTest : SysuiTestCase() {
     private val viewState = ViewState()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
index e2ac203..e46906f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/HideNotificationsInteractorTest.kt
@@ -17,10 +17,10 @@
 
 import android.content.res.Configuration
 import android.graphics.Rect
-import android.testing.AndroidTestingRunner
 import android.view.Surface
 import android.view.Surface.ROTATION_0
 import android.view.Surface.ROTATION_90
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl
@@ -52,7 +52,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 open class HideNotificationsInteractorTest : SysuiTestCase() {
 
     private val testScope = TestScope()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 84cd518..f0bc655 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -45,10 +45,10 @@
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -89,7 +89,7 @@
 
 import javax.inject.Named;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @SmallTest
 public class AutoTileManagerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index dc7525c..285949a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -37,11 +37,11 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.testing.TestableResources;
 import android.view.ViewRootImpl;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -77,7 +77,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class BiometricsUnlockControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index fe6a88d..5675915 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -30,9 +30,9 @@
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.os.Vibrator;
-import android.testing.AndroidTestingRunner;
 import android.view.HapticFeedbackConstants;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
@@ -71,7 +71,7 @@
 import java.util.Optional;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase {
 
     @Mock private CentralSurfaces mCentralSurfaces;
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 4488799..cde241b 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
@@ -57,6 +57,7 @@
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.devicestate.DeviceState;
@@ -75,7 +76,6 @@
 import android.platform.test.annotations.EnableFlags;
 import android.service.dreams.IDreamManager;
 import android.support.test.metricshelper.MetricsAsserts;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.DisplayMetrics;
@@ -85,6 +85,7 @@
 import android.view.WindowManager;
 import android.view.WindowMetrics;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.compose.animation.scene.ObservableTransitionState;
@@ -223,7 +224,7 @@
 import javax.inject.Provider;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 @EnableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
 public class CentralSurfacesImplTest extends SysuiTestCase {
@@ -339,6 +340,7 @@
     @Mock private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
     @Mock private KeyboardShortcuts mKeyboardShortcuts;
     @Mock private KeyboardShortcutListSearch mKeyboardShortcutListSearch;
+    @Mock private PackageManager mPackageManager;
 
     private ShadeController mShadeController;
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -392,7 +394,8 @@
                         mock(UiEventLogger.class),
                         mUserTracker,
                         mAvalancheProvider,
-                        mSystemSettings);
+                        mSystemSettings,
+                        mPackageManager);
         mVisualInterruptionDecisionProvider.start();
 
         mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
index 56d2397..942ea65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
@@ -21,7 +21,7 @@
 import android.content.res.Configuration.UI_MODE_NIGHT_YES
 import android.content.res.Configuration.UI_MODE_TYPE_CAR
 import android.os.LocaleList
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
@@ -36,7 +36,7 @@
 import org.mockito.Mockito.verify
 import java.util.Locale
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class ConfigurationControllerImplTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
index 34c43ef..3b3ec26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
@@ -20,9 +20,9 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -36,7 +36,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 @SmallTest
 public class DozeScrimControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
index 5d42d51..a3e2d19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
@@ -16,7 +16,7 @@
 package com.android.systemui.statusbar.phone
 
 import android.hardware.devicestate.DeviceState
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.R
 import com.android.systemui.SysuiTestCase
@@ -30,7 +30,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations.initMocks
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class FoldStateListenerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 3e9006e..0d06b64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -26,12 +26,12 @@
 import static org.mockito.Mockito.when;
 
 import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -62,7 +62,7 @@
 import java.util.Optional;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index e834693..cf87afb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -28,8 +28,8 @@
 import android.content.res.Resources;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.Flags;
@@ -50,7 +50,7 @@
 import org.mockito.quality.Strictness;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
     private static final int SCREEN_HEIGHT = 2000;
     private static final int EMPTY_HEIGHT = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
index b0aa2d3..d880bec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardDismissUtilTest.java
@@ -20,8 +20,8 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class KeyguardDismissUtilTest extends SysuiTestCase {
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
index 5cea931..109cd94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
@@ -21,10 +21,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class KeyguardIndicationTextViewTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 5b2526e..71f09a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -42,11 +42,11 @@
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.CarrierTextController;
@@ -99,7 +99,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
index c44f979..0932a0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewTest.java
@@ -18,11 +18,11 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.LayoutInflater;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -33,7 +33,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class KeyguardStatusBarViewTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
index f91064b..782ca91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.when;
 
 import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
 import android.view.View;
@@ -35,6 +34,7 @@
 import android.view.WindowManager;
 
 import androidx.lifecycle.Observer;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -54,7 +54,7 @@
 import java.util.Objects;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @DisableFlags(NotificationsLiveDataStoreRefactor.FLAG_NAME)
 public class LegacyLightsOutNotifControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 9d53b9c..fea0e72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -21,9 +21,9 @@
 import static org.mockito.Mockito.when;
 
 import android.platform.test.annotations.DisableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.Flags;
@@ -49,7 +49,7 @@
 import java.util.Optional;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 @DisableFlags(NotificationIconContainerRefactor.FLAG_NAME)
 public class LegacyNotificationIconAreaControllerImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
index e7b287c..518b327 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
@@ -18,9 +18,9 @@
 
 import android.graphics.Color
 import android.graphics.Rect
-import android.testing.AndroidTestingRunner
 import android.view.WindowInsetsController
 import android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.statusbar.LetterboxDetails
 import com.android.internal.view.AppearanceRegion
@@ -36,7 +36,7 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class LetterboxAppearanceCalculatorTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
index 1cc0bd3..788c2cb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
@@ -21,8 +21,8 @@
 import android.graphics.Color
 import android.os.Handler
 import android.os.Looper
-import android.testing.AndroidTestingRunner
 import android.view.IWindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.concurrency.FakeExecutor
@@ -40,7 +40,7 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class LetterboxBackgroundProviderTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 7271a5e..a27073c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -35,10 +35,10 @@
 
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.annotation.ColorInt;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
@@ -67,7 +67,7 @@
 import java.util.List;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class LightBarControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
index f71114d..43c19b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
@@ -28,9 +28,9 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.policy.GestureNavigationSettingsObserver;
@@ -48,7 +48,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class LightBarTransitionsControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index 9f4e1dd..9d97e5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -16,8 +16,8 @@
 package com.android.systemui.statusbar.phone
 
 import android.service.notification.StatusBarNotification
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.StatusBarIconView
@@ -34,7 +34,7 @@
 
 /** Tests for {@link NotificationIconContainer}. */
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 class NotificationIconContainerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
index ccd1a8c..9522e1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationTapHelperTest.java
@@ -22,11 +22,11 @@
 import static org.mockito.Mockito.when;
 
 import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -42,7 +42,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 public class NotificationTapHelperTest extends SysuiTestCase {
 
     private NotificationTapHelper mNotificationTapHelper;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
index 8d2c158..f2f336c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -22,9 +22,9 @@
 import android.content.SharedPreferences
 import android.os.UserManager
 import android.telecom.TelecomManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
@@ -79,7 +79,7 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 1000329..416a869 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -49,12 +49,12 @@
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.ViewUtils;
 import android.util.MathUtils;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
@@ -107,7 +107,7 @@
 import java.util.HashSet;
 import java.util.Map;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class ScrimControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt
index 61da701..b9cfe21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarBoundsProviderTest.kt
@@ -17,10 +17,10 @@
 package com.android.systemui.statusbar.phone
 
 import android.graphics.Rect
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.View
 import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.phone.StatusBarBoundsProvider.BoundsChangeListener
@@ -37,7 +37,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class StatusBarBoundsProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 6b3c005..3ca4c59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -41,7 +41,6 @@
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.service.trust.TrustAgentService;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
 import android.view.View;
@@ -55,6 +54,7 @@
 import android.window.OnBackInvokedDispatcher;
 import android.window.WindowOnBackInvokedDispatcher;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.LatencyTracker;
@@ -119,7 +119,7 @@
 import java.util.Optional;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 269510e..9fa392f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -51,9 +51,9 @@
 import android.os.UserHandle;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.jank.InteractionJankMonitor;
@@ -119,7 +119,7 @@
 import java.util.Optional;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index a8c5fc3..95472cad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -34,10 +34,10 @@
 import android.app.StatusBarManager;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.InitController;
@@ -85,7 +85,7 @@
 import java.util.Set;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper()
 public class StatusBarNotificationPresenterTest extends SysuiTestCase {
     private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 929099a..35888a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -24,10 +24,10 @@
 import static org.mockito.internal.verification.VerificationModeFactory.times;
 
 import android.content.Intent;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -52,7 +52,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -103,4 +103,4 @@
 
         verify(mStatusBarKeyguardViewManager).showBouncer(true);
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
index 1455693..11dd587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListenerTest.kt
@@ -21,7 +21,6 @@
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.PaintDrawable
 import android.os.SystemClock
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.testing.ViewUtils
@@ -30,6 +29,7 @@
 import android.view.ViewGroupOverlay
 import android.widget.LinearLayout
 import androidx.annotation.ColorInt
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
@@ -45,7 +45,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mockito.verify
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class StatusOverlayHoverListenerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
index dedd0af..b560c59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIBottomSheetDialogTest.kt
@@ -15,9 +15,9 @@
 
 import android.app.Dialog
 import android.content.res.Configuration
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.WindowManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.kosmos.testScope
@@ -39,7 +39,7 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 class SystemUIBottomSheetDialogTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index c8ff20b..624c070 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -18,9 +18,9 @@
 
 import android.os.Handler
 import android.os.PowerManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
@@ -51,7 +51,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 class UnlockedScreenOffAnimationControllerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 598b12c..eb2538e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -20,6 +20,7 @@
 import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
 import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.demomode.DemoMode
@@ -60,7 +61,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -73,7 +73,7 @@
 @Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class MobileRepositorySwitcherTest : SysuiTestCase() {
     private lateinit var underTest: MobileRepositorySwitcher
     private lateinit var realRepo: MobileConnectionsRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
index 2654401..237aabc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryTest.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
 
 import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
@@ -44,7 +44,7 @@
 
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class CarrierMergedConnectionRepositoryTest : SysuiTestCase() {
 
     private lateinit var underTest: CarrierMergedConnectionRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index 36df61d..96e599f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
 
+import android.annotation.SuppressLint
 import android.content.Intent
 import android.net.ConnectivityManager
 import android.net.Network
@@ -27,8 +28,10 @@
 import android.net.vcn.VcnTransportInfo
 import android.net.wifi.WifiInfo
 import android.net.wifi.WifiManager
+import android.os.Bundle
 import android.os.ParcelUuid
 import android.telephony.CarrierConfigManager
+import android.telephony.ServiceState
 import android.telephony.SubscriptionInfo
 import android.telephony.SubscriptionManager
 import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
@@ -53,6 +56,7 @@
 import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
@@ -595,6 +599,51 @@
             assertThat(mobileRepo.getIsCarrierMerged()).isFalse()
         }
 
+    @SuppressLint("UnspecifiedRegisterReceiverFlag")
+    @Test
+    fun testDeviceServiceStateFromBroadcast_eagerlyWatchesBroadcast() =
+        testScope.runTest {
+            // Value starts out empty (null)
+            assertThat(underTest.deviceServiceState.value).isNull()
+
+            // WHEN an appropriate intent gets sent out
+            val intent = serviceStateIntent(subId = -1, emergencyOnly = false)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                intent,
+            )
+            runCurrent()
+
+            // THEN the repo's state is updated
+            val expected = ServiceStateModel(isEmergencyOnly = false)
+            assertThat(underTest.deviceServiceState.value).isEqualTo(expected)
+        }
+
+    @Test
+    fun testDeviceServiceStateFromBroadcast_followsSubIdNegativeOne() =
+        testScope.runTest {
+            // device based state tracks -1
+            val intent = serviceStateIntent(subId = -1, emergencyOnly = false)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                intent,
+            )
+            runCurrent()
+
+            val deviceBasedState = ServiceStateModel(isEmergencyOnly = false)
+            assertThat(underTest.deviceServiceState.value).isEqualTo(deviceBasedState)
+
+            // ... and ignores any other subId
+            val intent2 = serviceStateIntent(subId = 1, emergencyOnly = true)
+            fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+                context,
+                intent2,
+            )
+            runCurrent()
+
+            assertThat(underTest.deviceServiceState.value).isEqualTo(deviceBasedState)
+        }
+
     @Test
     @Ignore("b/333912012")
     fun testConnectionCache_clearsInvalidSubscriptions() =
@@ -1491,5 +1540,24 @@
                 whenever(it.transportInfo).thenReturn(WIFI_INFO_ACTIVE)
                 whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(true)
             }
+
+        /**
+         * To properly mimic telephony manager, create a service state, and then turn it into an
+         * intent
+         */
+        private fun serviceStateIntent(
+            subId: Int,
+            emergencyOnly: Boolean = false,
+        ): Intent {
+            val serviceState = ServiceState().apply { isEmergencyOnly = emergencyOnly }
+
+            val bundle = Bundle()
+            serviceState.fillInNotifierBundle(bundle)
+
+            return Intent(Intent.ACTION_SERVICE_STATE).apply {
+                putExtras(bundle)
+                putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId)
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 0f9cbfa..58d9ee3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -888,6 +889,22 @@
             assertThat(interactor1).isSameInstanceAs(interactor2)
         }
 
+    @Test
+    fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
+
+            connectionsRepository.deviceServiceState.value =
+                ServiceStateModel(isEmergencyOnly = true)
+
+            assertThat(latest).isTrue()
+
+            connectionsRepository.deviceServiceState.value =
+                ServiceStateModel(isEmergencyOnly = false)
+
+            assertThat(latest).isFalse()
+        }
+
     /**
      * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions
      * flow.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index 405e3ed..d303976 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -22,6 +22,7 @@
 import com.android.internal.telephony.flags.Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.log.core.FakeLogBuffer
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.satellite.data.prod.FakeDeviceBasedSatelliteRepository
@@ -71,6 +72,7 @@
                 deviceProvisioningInteractor,
                 wifiInteractor,
                 testScope.backgroundScope,
+                FakeLogBuffer.Factory.create(),
             )
     }
 
@@ -114,6 +116,7 @@
                     deviceProvisioningInteractor,
                     wifiInteractor,
                     testScope.backgroundScope,
+                    FakeLogBuffer.Factory.create(),
                 )
 
             val latest by collectLastValue(underTest.isSatelliteAllowed)
@@ -162,6 +165,7 @@
                     deviceProvisioningInteractor,
                     wifiInteractor,
                     testScope.backgroundScope,
+                    FakeLogBuffer.Factory.create(),
                 )
 
             val latest by collectLastValue(underTest.connectionState)
@@ -218,6 +222,7 @@
                     deviceProvisioningInteractor,
                     wifiInteractor,
                     testScope.backgroundScope,
+                    FakeLogBuffer.Factory.create(),
                 )
 
             val latest by collectLastValue(underTest.signalStrength)
@@ -238,25 +243,97 @@
 
     @Test
     @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    fun areAllConnectionsOutOfService_noConnections_yes() =
+    fun areAllConnectionsOutOfService_noConnections_noDeviceEmergencyCalls_yes() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
 
             // GIVEN, 0 connections
 
+            // GIVEN, device is not in emergency calls only mode
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
+
             // THEN the value is propagated to this interactor
             assertThat(latest).isTrue()
         }
 
     @Test
     @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_yes() =
+    fun areAllConnectionsOutOfService_noConnections_deviceEmergencyCalls_yes() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+            // GIVEN, 0 connections
+
+            // GIVEN, device is in emergency calls only mode
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+            // THEN the value is propagated to this interactor
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+    fun areAllConnectionsOutOfService_oneConnectionInService_thenLost_noDeviceEmergencyCalls_yes() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+            // GIVEN, 1 connections
+            val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+            // GIVEN, no device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
+
+            // WHEN connection is in service
+            i1.isInService.value = true
+            i1.isEmergencyOnly.value = false
+            i1.isNonTerrestrial.value = false
+
+            // THEN we are considered NOT to be OOS
+            assertThat(latest).isFalse()
+
+            // WHEN the connection disappears
+            iconsInteractor.icons.value = listOf()
+
+            // THEN we are back to OOS
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+    fun areAllConnectionsOutOfService_oneConnectionInService_thenLost_deviceEmergencyCalls_no() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+            // GIVEN, 1 connections
+            val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+            // GIVEN, device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+            // WHEN one connection is in service
+            i1.isInService.value = true
+            i1.isEmergencyOnly.value = false
+            i1.isNonTerrestrial.value = false
+
+            // THEN we are considered NOT to be OOS
+            assertThat(latest).isFalse()
+
+            // WHEN the connection disappears
+            iconsInteractor.icons.value = listOf()
+
+            // THEN we are still NOT in OOS, due to device-based emergency calls
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+    fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_noDeviceEmergencyCalls_yes() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
 
             // GIVEN, 2 connections
             val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
             val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+            // GIVEN, no device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
 
             // WHEN all of the connections are OOS and none are NTN
             i1.isInService.value = false
@@ -272,13 +349,39 @@
 
     @Test
     @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    fun areAllConnectionsOutOfService_twoConnectionsOos_oneNtn_no() =
+    fun areAllConnectionsOutOfService_twoConnectionsOos_nonNtn_deviceEmergencyCalls_no() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
 
             // GIVEN, 2 connections
             val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
             val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+            // GIVEN, device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+            // WHEN all of the connections are OOS and none are NTN
+            i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
+            i1.isNonTerrestrial.value = false
+            i2.isInService.value = false
+            i2.isEmergencyOnly.value = false
+            i2.isNonTerrestrial.value = false
+
+            // THEN we are not considered OOS due to device based emergency calling
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+    fun areAllConnectionsOutOfService_twoConnectionsOos_noDeviceEmergencyCalls_oneNtn_no() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+            // GIVEN, 2 connections
+            val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+            val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2)
+            // GIVEN, no device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
 
             // WHEN all of the connections are OOS and one is NTN
             i1.isInService.value = false
@@ -296,12 +399,14 @@
 
     @Test
     @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    fun areAllConnectionsOutOfService_oneConnectionOos_nonNtn_yes() =
+    fun areAllConnectionsOutOfService_oneConnectionOos_noDeviceEmergencyCalls_nonNtn_yes() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
 
             // GIVEN, 1 connection
             val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+            // GIVEN, no device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = false
 
             // WHEN all of the connections are OOS
             i1.isInService.value = false
@@ -314,7 +419,27 @@
 
     @Test
     @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-    fun areAllConnectionsOutOfService_oneConnectionOos_ntn_yes() =
+    fun areAllConnectionsOutOfService_oneConnectionOos_nonNtn_no() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+            // GIVEN, 1 connection
+            val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1)
+            // GIVEN, device-based emergency calls
+            iconsInteractor.isDeviceInEmergencyCallsOnlyMode.value = true
+
+            // WHEN all of the connections are OOS
+            i1.isInService.value = false
+            i1.isEmergencyOnly.value = false
+            i1.isNonTerrestrial.value = false
+
+            // THEN the value is propagated to this interactor
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+    fun areAllConnectionsOutOfService_oneConnectionOos_ntn_no() =
         testScope.runTest {
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
 
@@ -416,6 +541,7 @@
                     deviceProvisioningInteractor,
                     wifiInteractor,
                     testScope.backgroundScope,
+                    FakeLogBuffer.Factory.create(),
                 )
 
             val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index ceaae9e..43b9568 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -75,6 +75,7 @@
                 deviceProvisioningInteractor,
                 wifiInteractor,
                 testScope.backgroundScope,
+                FakeLogBuffer.Factory.create(),
             )
 
         underTest =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
index d1c38f6..0a5e630 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BaseUserSwitcherAdapterTest.kt
@@ -22,6 +22,7 @@
 import android.os.UserHandle
 import android.view.View
 import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.user.UserSwitchDialogController
@@ -33,14 +34,13 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(JUnit4::class)
+@RunWith(AndroidJUnit4::class)
 class BaseUserSwitcherAdapterTest : SysuiTestCase() {
 
     @Mock private lateinit var controller: UserSwitcherController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
index fb4ccb5..c22c628 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
@@ -20,8 +20,8 @@
 import android.content.Context
 import android.content.pm.ServiceInfo
 import android.provider.Settings
-import android.testing.AndroidTestingRunner
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 
 import com.android.systemui.res.R
@@ -60,7 +60,7 @@
 import org.mockito.ArgumentMatchers.anyObject
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class DeviceControlsControllerImplTest : SysuiTestCase() {
 
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
index 2955162..f6e07d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingControllerTest.java
@@ -29,10 +29,10 @@
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableContentResolver;
 import android.testing.TestableResources;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
@@ -51,7 +51,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DeviceStateRotationLockSettingControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
index 1c54263..80cc6ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
@@ -20,8 +20,8 @@
 import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraManager
 import android.hardware.camera2.impl.CameraMetadataNative
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import android.testing.AndroidTestingRunner
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastSender
 import com.android.systemui.dump.DumpManager
@@ -46,7 +46,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class FlashlightControllerImplTest : SysuiTestCase() {
 
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
index 0bd6a68..9f74915 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
@@ -19,10 +19,10 @@
 import android.content.Context
 import android.content.pm.UserInfo
 import android.graphics.Bitmap
-import android.testing.AndroidTestingRunner
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.util.UserIcons
 import com.android.systemui.res.R
@@ -44,7 +44,7 @@
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 class KeyguardUserSwitcherAdapterTest : SysuiTestCase() {
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
index b03edaf..4b14e64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
@@ -23,7 +23,7 @@
 import android.net.Uri
 import android.os.Handler
 import android.safetycenter.SafetyCenterManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.any
@@ -44,7 +44,7 @@
 import org.mockito.Mockito.`when`
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class SafetyControllerTest : SysuiTestCase() {
 
     private val TEST_PC_PKG = "testPermissionControllerPackageName"
@@ -188,4 +188,4 @@
 
         assertThat(called).isTrue()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
index 3e20f68..81f0950 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
@@ -22,7 +22,7 @@
 import android.os.Handler
 import android.platform.test.annotations.DisableFlags
 import android.telephony.TelephonyManager
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.server.notification.Flags
 import com.android.systemui.SysuiTestCase
@@ -38,7 +38,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @DisableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
 class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase() {
     private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
index dbc2e347..0249ab8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.statusbar.policy
 
 import android.service.quickaccesswallet.QuickAccessWalletClient
-import android.testing.AndroidTestingRunner
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 
 import com.android.systemui.SysuiTestCase
@@ -35,7 +35,7 @@
 import org.mockito.Mockito.`when`
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class WalletControllerImplTest : SysuiTestCase() {
 
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
index fd368eb..eaef007 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/RotationChangeProviderTest.kt
@@ -18,8 +18,11 @@
 
 import android.content.Context
 import android.hardware.display.DisplayManager
+import android.os.HandlerThread
 import android.os.Looper
+import android.os.Process
 import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
 import android.view.Display
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -40,6 +43,7 @@
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
+@RunWithLooper
 class RotationChangeProviderTest : SysuiTestCase() {
 
     private lateinit var rotationChangeProvider: RotationChangeProvider
@@ -48,7 +52,10 @@
     @Mock lateinit var listener: RotationListener
     @Mock lateinit var display: Display
     @Captor lateinit var displayListener: ArgumentCaptor<DisplayManager.DisplayListener>
-    private val fakeHandler = FakeHandler(Looper.getMainLooper())
+    private val bgThread =
+        HandlerThread("UnfoldBgTest", Process.THREAD_PRIORITY_FOREGROUND).apply { start() }
+    private val bgHandler = FakeHandler(bgThread.looper)
+    private val callbackHandler = FakeHandler(Looper.getMainLooper())
 
     private lateinit var spyContext: Context
 
@@ -57,9 +64,10 @@
         MockitoAnnotations.initMocks(this)
         spyContext = spy(context)
         whenever(spyContext.display).thenReturn(display)
-        rotationChangeProvider = RotationChangeProvider(displayManager, spyContext, fakeHandler)
+        rotationChangeProvider =
+            RotationChangeProvider(displayManager, spyContext, bgHandler, callbackHandler)
         rotationChangeProvider.addCallback(listener)
-        fakeHandler.dispatchQueuedMessages()
+        bgHandler.dispatchQueuedMessages()
         verify(displayManager).registerDisplayListener(displayListener.capture(), any())
     }
 
@@ -76,7 +84,7 @@
         verify(listener).onRotationChanged(42)
 
         rotationChangeProvider.removeCallback(listener)
-        fakeHandler.dispatchQueuedMessages()
+        bgHandler.dispatchQueuedMessages()
         sendRotationUpdate(43)
 
         verify(displayManager).unregisterDisplayListener(any())
@@ -86,6 +94,6 @@
     private fun sendRotationUpdate(newRotation: Int) {
         whenever(display.rotation).thenReturn(newRotation)
         displayListener.allValues.forEach { it.onDisplayChanged(display.displayId) }
-        fakeHandler.dispatchQueuedMessages()
+        callbackHandler.dispatchQueuedMessages()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index df78110..7b0a556 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -467,7 +467,8 @@
                         mock(UiEventLogger.class),
                         mock(UserTracker.class),
                         mock(AvalancheProvider.class),
-                        mock(SystemSettings.class)
+                        mock(SystemSettings.class),
+                        mock(PackageManager.class)
                         );
         interruptionDecisionProvider.start();
 
@@ -2132,8 +2133,7 @@
 
         FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
         mBubbleController.registerBubbleStateListener(bubbleStateListener);
-        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(),
-                new Rect(500, 1000, 600, 1100));
+        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 1000);
 
         assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
 
@@ -2157,7 +2157,7 @@
         mBubbleController.updateBubble(mBubbleEntry2);
 
         // Select first bubble
-        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
         assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
         assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
 
@@ -2166,7 +2166,7 @@
         assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
 
         // Stop dragging, first bubble should be expanded
-        mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT);
+        mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT, 0);
         assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
         assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
     }
@@ -2186,7 +2186,7 @@
         mBubbleController.updateBubble(mBubbleEntry2);
 
         // Select first bubble
-        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
         assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
         assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
 
@@ -2195,7 +2195,7 @@
         assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
 
         // Stop dragging, first bubble should be expanded
-        mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT);
+        mBubbleController.stopBubbleDrag(BubbleBarLocation.LEFT, 0);
         assertThat(mBubbleData.getSelectedBubbleKey()).isEqualTo(mBubbleEntry.getKey());
         assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
     }
@@ -2215,7 +2215,7 @@
         mBubbleController.updateBubble(mBubbleEntry2);
 
         // Select first bubble
-        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
         // Drag first bubble to dismiss
         mBubbleController.startBubbleDrag(mBubbleEntry.getKey());
         mBubbleController.dragBubbleToDismiss(mBubbleEntry.getKey());
@@ -2239,7 +2239,7 @@
         mBubbleController.updateBubble(mBubbleEntry2);
 
         // Select first bubble
-        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), new Rect());
+        mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 0);
         // Drag second bubble to dismiss
         mBubbleController.startBubbleDrag(mBubbleEntry2.getKey());
         mBubbleController.dragBubbleToDismiss(mBubbleEntry2.getKey());
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
index e37bdc1..2809967 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt
@@ -17,6 +17,9 @@
     private val _userId = MutableStateFlow<Int?>(null)
     override val userId = _userId.asStateFlow()
 
+    private val _requestId = MutableStateFlow<Long?>(null)
+    override val requestId = _requestId.asStateFlow()
+
     private var _challenge = MutableStateFlow<Long?>(null)
     override val challenge = _challenge.asStateFlow()
 
@@ -32,6 +35,7 @@
     override fun setPrompt(
         promptInfo: PromptInfo,
         userId: Int,
+        requestId: Long,
         gatekeeperChallenge: Long?,
         kind: PromptKind,
         opPackageName: String,
@@ -39,6 +43,7 @@
         setPrompt(
             promptInfo,
             userId,
+            requestId,
             gatekeeperChallenge,
             kind,
             forceConfirmation = false,
@@ -48,6 +53,7 @@
     fun setPrompt(
         promptInfo: PromptInfo,
         userId: Int,
+        requestId: Long,
         gatekeeperChallenge: Long?,
         kind: PromptKind,
         forceConfirmation: Boolean = false,
@@ -55,15 +61,17 @@
     ) {
         _promptInfo.value = promptInfo
         _userId.value = userId
+        _requestId.value = requestId
         _challenge.value = gatekeeperChallenge
         _promptKind.value = kind
         _isConfirmationRequired.value = promptInfo.isConfirmationRequested || forceConfirmation
         _opPackageName.value = opPackageName
     }
 
-    override fun unsetPrompt() {
+    override fun unsetPrompt(requestId: Long) {
         _promptInfo.value = null
         _userId.value = null
+        _requestId.value = null
         _challenge.value = null
         _promptKind.value = PromptKind.None
         _opPackageName.value = null
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
index b38acc8..bd9c0be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
@@ -30,6 +31,7 @@
             fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor,
             fromAlternateBouncerInteractor = fromAlternateBouncerTransitionInteractor,
             notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor,
-            sceneInteractor = sceneInteractor,
+            sceneInteractor = { sceneInteractor },
+            deviceEntryInteractor = { deviceEntryInteractor },
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index cce038f..8229575 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -23,6 +23,7 @@
 import com.android.settingslib.mobile.MobileMappings
 import com.android.settingslib.mobile.TelephonyIcons
 import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ServiceStateModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -93,6 +94,8 @@
     private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
     override val defaultMobileIconGroup = _defaultMobileIconGroup
 
+    override val deviceServiceState = MutableStateFlow<ServiceStateModel?>(null)
+
     override val isAnySimSecure = MutableStateFlow(false)
     override fun getIsAnySimSecure(): Boolean = isAnySimSecure.value
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index de6c87c2..3a4bf8e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -81,6 +81,8 @@
 
     override val isForceHidden = MutableStateFlow(false)
 
+    override val isDeviceInEmergencyCallsOnlyMode = MutableStateFlow(false)
+
     /** Always returns a new fake interactor */
     override fun getMobileConnectionInteractorForSubId(subId: Int): FakeMobileIconInteractor {
         return FakeMobileIconInteractor(tableLogBuffer).also {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt
index f9b7e69..2b5d1b9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/VolumePanelAncKosmos.kt
@@ -20,10 +20,13 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.volume.domain.interactor.audioOutputInteractor
 import com.android.systemui.volume.panel.component.anc.data.repository.FakeAncSliceRepository
 import com.android.systemui.volume.panel.component.anc.domain.interactor.AncSliceInteractor
 
 var Kosmos.sliceViewManager: SliceViewManager by Kosmos.Fixture { mock {} }
 val Kosmos.ancSliceRepository by Kosmos.Fixture { FakeAncSliceRepository() }
 val Kosmos.ancSliceInteractor by
-    Kosmos.Fixture { AncSliceInteractor(ancSliceRepository, testScope.backgroundScope) }
+    Kosmos.Fixture {
+        AncSliceInteractor(audioOutputInteractor, ancSliceRepository, testScope.backgroundScope)
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
index d4a72b4..ebe6850 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/anc/data/repository/FakeAncSliceRepository.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.panel.component.anc.data.repository
 
+import android.bluetooth.BluetoothDevice
 import androidx.slice.Slice
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -24,7 +25,12 @@
 
     private val sliceByWidth = mutableMapOf<Int, MutableStateFlow<Slice?>>()
 
-    override fun ancSlice(width: Int, isCollapsed: Boolean, hideLabel: Boolean): Flow<Slice?> {
+    override fun ancSlice(
+        device: BluetoothDevice,
+        width: Int,
+        isCollapsed: Boolean,
+        hideLabel: Boolean
+    ): Flow<Slice?> {
         return sliceByWidth.getOrPut(width) { MutableStateFlow(null) }
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
new file mode 100644
index 0000000..4029609
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/domain/interactor/TestMediaDevicesFactory.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.volume.panel.component.mediaoutput.domain.interactor
+
+import android.annotation.SuppressLint
+import android.bluetooth.BluetoothDevice
+import android.graphics.drawable.TestStubDrawable
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.settingslib.media.MediaDevice
+import com.android.settingslib.media.PhoneMediaDevice
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+@SuppressLint("StaticFieldLeak") // These are mocks
+object TestMediaDevicesFactory {
+
+    fun builtInMediaDevice(): MediaDevice = mock {
+        whenever(name).thenReturn("built_in_media")
+        whenever(icon).thenReturn(TestStubDrawable())
+    }
+
+    fun wiredMediaDevice(): MediaDevice =
+        mock<PhoneMediaDevice> {
+            whenever(deviceType)
+                .thenReturn(MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE)
+            whenever(name).thenReturn("wired_media")
+            whenever(icon).thenReturn(TestStubDrawable())
+        }
+
+    fun bluetoothMediaDevice(): MediaDevice {
+        val bluetoothDevice = mock<BluetoothDevice>()
+        val cachedBluetoothDevice: CachedBluetoothDevice = mock {
+            whenever(isHearingAidDevice).thenReturn(true)
+            whenever(address).thenReturn("bt_media_device")
+            whenever(device).thenReturn(bluetoothDevice)
+        }
+        return mock<BluetoothMediaDevice> {
+            whenever(name).thenReturn("bt_media")
+            whenever(icon).thenReturn(TestStubDrawable())
+            whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+        }
+    }
+}
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt
index 2bc2db3..fe10244 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldRemoteModule.kt
@@ -53,8 +53,8 @@
     @UnfoldMain
     fun provideMainRotationChangeProvider(
         rotationChangeProviderFactory: RotationChangeProvider.Factory,
-        @UnfoldMain mainHandler: Handler,
+        @UnfoldMain callbackHandler: Handler,
     ): RotationChangeProvider {
-        return rotationChangeProviderFactory.create(mainHandler)
+        return rotationChangeProviderFactory.create(callbackHandler)
     }
 }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
index 31b7ccc..f382070 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedComponent.kt
@@ -87,6 +87,7 @@
             @BindsInstance @UnfoldMain executor: Executor,
             @BindsInstance @UnfoldMain handler: Handler,
             @BindsInstance @UnfoldSingleThreadBg singleThreadBgExecutor: Executor,
+            @BindsInstance @UnfoldBg bgHandler: Handler,
             @BindsInstance displayManager: DisplayManager,
             @BindsInstance @UnfoldTransitionATracePrefix tracingTagPrefix: String,
         ): RemoteUnfoldSharedComponent
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
index 1b7e71a..f83ea84 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
@@ -270,9 +270,9 @@
     @UnfoldMain
     fun provideRotationChangeProvider(
         rotationChangeProviderFactory: RotationChangeProvider.Factory,
-        @UnfoldMain mainHandler: Handler,
+        @UnfoldMain callbackHandler: Handler,
     ): RotationChangeProvider {
-        return rotationChangeProviderFactory.create(mainHandler)
+        return rotationChangeProviderFactory.create(callbackHandler)
     }
 
     @Provides
@@ -280,8 +280,9 @@
     @UnfoldBg
     fun provideBgRotationChangeProvider(
         rotationChangeProviderFactory: RotationChangeProvider.Factory,
-        @UnfoldBg bgHandler: Handler,
+        @UnfoldBg callbackHandler: Handler,
     ): RotationChangeProvider {
-        return rotationChangeProviderFactory.create(bgHandler)
+        // For UnfoldBg RotationChangeProvider we use bgHandler as callbackHandler
+        return rotationChangeProviderFactory.create(callbackHandler)
     }
 }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 1cbaf31..8a4f985 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -77,6 +77,7 @@
         mainExecutor: Executor,
         mainHandler: Handler,
         singleThreadBgExecutor: Executor,
+        bgHandler: Handler,
         tracingTagPrefix: String,
         displayManager: DisplayManager,
         ): RemoteUnfoldSharedComponent =
@@ -87,6 +88,7 @@
                         mainExecutor,
                         mainHandler,
                         singleThreadBgExecutor,
+                        bgHandler,
                         displayManager,
                         tracingTagPrefix,
                 )
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 77f637b..a100974 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -20,6 +20,7 @@
 import android.util.Log
 import androidx.annotation.FloatRange
 import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
 import androidx.core.util.Consumer
 import com.android.systemui.unfold.compat.INNER_SCREEN_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
@@ -215,6 +216,7 @@
     }
 
     private inner class FoldRotationListener : RotationChangeProvider.RotationListener {
+        @WorkerThread
         override fun onRotationChanged(newRotation: Int) {
             assertInProgressThread()
             if (isTransitionInProgress) cancelAnimation()
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
index bb91f9b..4f3aee9 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/RotationChangeProvider.kt
@@ -21,6 +21,8 @@
 import android.os.Handler
 import android.os.RemoteException
 import android.os.Trace
+import androidx.annotation.AnyThread
+import com.android.systemui.unfold.dagger.UnfoldBg
 import com.android.systemui.unfold.util.CallbackController
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
@@ -35,7 +37,8 @@
 constructor(
     private val displayManager: DisplayManager,
     private val context: Context,
-    @Assisted private val handler: Handler,
+    @UnfoldBg private val bgHandler: Handler,
+    @Assisted private val callbackHandler: Handler,
 ) : CallbackController<RotationChangeProvider.RotationListener> {
 
     private val listeners = mutableListOf<RotationListener>()
@@ -44,7 +47,7 @@
     private var lastRotation: Int? = null
 
     override fun addCallback(listener: RotationListener) {
-        handler.post {
+        bgHandler.post {
             if (listeners.isEmpty()) {
                 subscribeToRotation()
             }
@@ -53,7 +56,7 @@
     }
 
     override fun removeCallback(listener: RotationListener) {
-        handler.post {
+        bgHandler.post {
             listeners -= listener
             if (listeners.isEmpty()) {
                 unsubscribeToRotation()
@@ -64,7 +67,7 @@
 
     private fun subscribeToRotation() {
         try {
-            displayManager.registerDisplayListener(displayListener, handler)
+            displayManager.registerDisplayListener(displayListener, callbackHandler)
         } catch (e: RemoteException) {
             throw e.rethrowFromSystemServer()
         }
@@ -80,8 +83,11 @@
 
     /** Gets notified of rotation changes. */
     fun interface RotationListener {
-        /** Called once rotation changes. */
-        fun onRotationChanged(newRotation: Int)
+        /**
+         * Called once rotation changes. This callback is called on the handler provided to
+         * [RotationChangeProvider.Factory.create].
+         */
+        @AnyThread fun onRotationChanged(newRotation: Int)
     }
 
     private inner class RotationDisplayListener : DisplayManager.DisplayListener {
@@ -110,7 +116,7 @@
 
     @AssistedFactory
     interface Factory {
-        /** Creates a new [RotationChangeProvider] that provides updated using [handler]. */
-        fun create(handler: Handler): RotationChangeProvider
+        /** Creates a new [RotationChangeProvider] that provides updated using [callbackHandler]. */
+        fun create(callbackHandler: Handler): RotationChangeProvider
     }
 }
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 3f30b0a..a50fb9a 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -138,6 +138,16 @@
 }
 
 flag {
+    name: "manager_package_monitor_logic_fix"
+    namespace: "accessibility"
+    description: "Corrects the return values of the HandleForceStop function"
+    bug: "337392123"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "pinch_zoom_zero_min_span"
     namespace: "accessibility"
     description: "Whether to set min span of ScaleGestureDetector to zero."
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index c70b641..a15d2ca 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -697,7 +697,7 @@
 
     /**
      * Returns the lock object for any synchronized test blocks.
-     * Should not be used outside of testing.
+     * External classes should only use for testing.
      * @return lock object.
      */
     @VisibleForTesting
@@ -801,7 +801,7 @@
      *
      * @param packages list of packages that have stopped.
      * @param userState user state to be read & modified.
-     * @return {@code true} if a service was enabled or a button target was removed,
+     * @return {@code true} if the lists of enabled services or buttons were changed,
      * {@code false} otherwise.
      */
     @VisibleForTesting
@@ -824,6 +824,7 @@
                     userState.getBindingServicesLocked().remove(comp);
                     userState.getCrashedServicesLocked().remove(comp);
                     enabledServicesChanged = true;
+                    break;
                 }
             }
         }
@@ -851,132 +852,14 @@
         return mPackageMonitor;
     }
 
+    @VisibleForTesting
+    void setPackageMonitor(PackageMonitor monitor) {
+        mPackageMonitor = monitor;
+    }
+
     private void registerBroadcastReceivers() {
-        mPackageMonitor = new PackageMonitor(true) {
-            @Override
-            public void onSomePackagesChanged() {
-                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
-                    mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged",
-                            FLAGS_PACKAGE_BROADCAST_RECEIVER);
-                }
-
-                final int userId = getChangingUserId();
-                List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = null;
-                List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = null;
-                parsedAccessibilityServiceInfos = parseAccessibilityServiceInfos(userId);
-                parsedAccessibilityShortcutInfos = parseAccessibilityShortcutInfos(userId);
-                synchronized (mLock) {
-                    // Only the profile parent can install accessibility services.
-                    // Therefore we ignore packages from linked profiles.
-                    if (userId != mCurrentUserId) {
-                        return;
-                    }
-                    onSomePackagesChangedLocked(parsedAccessibilityServiceInfos,
-                            parsedAccessibilityShortcutInfos);
-                }
-            }
-
-            @Override
-            public void onPackageUpdateFinished(String packageName, int uid) {
-                // The package should already be removed from mBoundServices, and added into
-                // mBindingServices in binderDied() during updating. Remove services from  this
-                // package from mBindingServices, and then update the user state to re-bind new
-                // versions of them.
-                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
-                    mTraceManager.logTrace(LOG_TAG + ".PM.onPackageUpdateFinished",
-                            FLAGS_PACKAGE_BROADCAST_RECEIVER,
-                            "packageName=" + packageName + ";uid=" + uid);
-                }
-                final int userId = getChangingUserId();
-                List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = null;
-                List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = null;
-                parsedAccessibilityServiceInfos = parseAccessibilityServiceInfos(userId);
-                parsedAccessibilityShortcutInfos = parseAccessibilityShortcutInfos(userId);
-                synchronized (mLock) {
-                    if (userId != mCurrentUserId) {
-                        return;
-                    }
-                    final AccessibilityUserState userState = getUserStateLocked(userId);
-                    final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
-                            component -> component != null
-                                    && component.getPackageName().equals(packageName))
-                            || userState.mCrashedServices.removeIf(component -> component != null
-                                    && component.getPackageName().equals(packageName));
-                    // Reloads the installed services info to make sure the rebound service could
-                    // get a new one.
-                    userState.mInstalledServices.clear();
-                    final boolean configurationChanged;
-                    configurationChanged = readConfigurationForUserStateLocked(userState,
-                            parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos);
-                    if (reboundAService || configurationChanged) {
-                        onUserStateChangedLocked(userState);
-                    }
-                    // Passing 0 for restoreFromSdkInt to have this migration check execute each
-                    // time. It can make sure a11y button settings are correctly if there's an a11y
-                    // service updated and modifies the a11y button configuration.
-                    migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName,
-                            /* restoreFromSdkInt = */0);
-                }
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
-                    mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
-                            FLAGS_PACKAGE_BROADCAST_RECEIVER,
-                            "packageName=" + packageName + ";uid=" + uid);
-                }
-
-                synchronized (mLock) {
-                    final int userId = getChangingUserId();
-                    // Only the profile parent can install accessibility services.
-                    // Therefore we ignore packages from linked profiles.
-                    if (userId != mCurrentUserId) {
-                        return;
-                    }
-                    onPackageRemovedLocked(packageName);
-                }
-            }
-
-            /**
-             * Handles instances in which a package or packages have forcibly stopped.
-             *
-             * @param intent intent containing package event information.
-             * @param uid linux process user id (different from Android user id).
-             * @param packages array of package names that have stopped.
-             * @param doit whether to try and handle the stop or just log the trace.
-             *
-             * @return {@code true} if package should be restarted, {@code false} otherwise.
-             */
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] packages,
-                    int uid, boolean doit) {
-                if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
-                    mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
-                            FLAGS_PACKAGE_BROADCAST_RECEIVER,
-                            "intent=" + intent + ";packages=" + Arrays.toString(packages)
-                            + ";uid=" + uid + ";doit=" + doit);
-                }
-                synchronized (mLock) {
-                    final int userId = getChangingUserId();
-                    // Only the profile parent can install accessibility services.
-                    // Therefore we ignore packages from linked profiles.
-                    if (userId != mCurrentUserId) {
-                        return false;
-                    }
-                    final AccessibilityUserState userState = getUserStateLocked(userId);
-
-                    if (doit && onPackagesForceStoppedLocked(packages, userState)) {
-                        onUserStateChangedLocked(userState);
-                        return false;
-                    } else {
-                        return true;
-                    }
-                }
-            }
-        };
-
         // package changes
+        mPackageMonitor = new ManagerPackageMonitor(this);
         mPackageMonitor.register(mContext, null,  UserHandle.ALL, true);
 
         // user change and unlock
@@ -992,7 +875,9 @@
             @Override
             public void onReceive(Context context, Intent intent) {
                 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_USER_BROADCAST_RECEIVER)) {
-                    mTraceManager.logTrace(LOG_TAG + ".BR.onReceive", FLAGS_USER_BROADCAST_RECEIVER,
+                    mTraceManager.logTrace(
+                            LOG_TAG + ".BR.onReceive",
+                            FLAGS_USER_BROADCAST_RECEIVER,
                             "context=" + context + ";intent=" + intent);
                 }
 
@@ -1045,7 +930,8 @@
                 setNonA11yToolNotificationToMatchSafetyCenter();
             }
         };
-        mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, mMainHandler,
+        mContext.registerReceiverAsUser(
+                receiver, UserHandle.ALL, filter, null, mMainHandler,
                 Context.RECEIVER_EXPORTED);
 
         if (!android.companion.virtual.flags.Flags.vdmPublicApis()) {
@@ -4371,7 +4257,7 @@
                 );
 
         if (!targetWithNoTile.isEmpty()) {
-            throw new IllegalArgumentException(
+            Slog.e(LOG_TAG,
                     "Unable to add/remove Tiles for a11y features: " + targetWithNoTile
                             + "as the Tiles aren't provided");
         }
@@ -6223,6 +6109,162 @@
         }
     }
 
+    @VisibleForTesting
+    public static class ManagerPackageMonitor extends PackageMonitor {
+        private final AccessibilityManagerService mManagerService;
+        public ManagerPackageMonitor(AccessibilityManagerService managerService) {
+            super(/* supportsPackageRestartQuery = */ true);
+            mManagerService = managerService;
+        }
+
+        @Override
+        public void onSomePackagesChanged() {
+            if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+                    FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+                mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged",
+                        FLAGS_PACKAGE_BROADCAST_RECEIVER);
+            }
+
+            final int userId = getChangingUserId();
+            List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService
+                    .parseAccessibilityServiceInfos(userId);
+            List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = mManagerService
+                    .parseAccessibilityShortcutInfos(userId);
+            synchronized (mManagerService.getLock()) {
+                // Only the profile parent can install accessibility services.
+                // Therefore we ignore packages from linked profiles.
+                if (userId != mManagerService.getCurrentUserIdLocked()) {
+                    return;
+                }
+                mManagerService.onSomePackagesChangedLocked(parsedAccessibilityServiceInfos,
+                        parsedAccessibilityShortcutInfos);
+            }
+        }
+
+        @Override
+        public void onPackageUpdateFinished(String packageName, int uid) {
+            // The package should already be removed from mBoundServices, and added into
+            // mBindingServices in binderDied() during updating. Remove services from  this
+            // package from mBindingServices, and then update the user state to re-bind new
+            // versions of them.
+            if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+                    FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+                mManagerService.mTraceManager.logTrace(
+                        LOG_TAG + ".PM.onPackageUpdateFinished",
+                        FLAGS_PACKAGE_BROADCAST_RECEIVER,
+                        "packageName=" + packageName + ";uid=" + uid);
+            }
+            final int userId = getChangingUserId();
+            List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService
+                    .parseAccessibilityServiceInfos(userId);
+            List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos =
+                    mManagerService.parseAccessibilityShortcutInfos(userId);
+            synchronized (mManagerService.getLock()) {
+                if (userId != mManagerService.getCurrentUserIdLocked()) {
+                    return;
+                }
+                final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
+                final boolean reboundAService = userState.getBindingServicesLocked().removeIf(
+                        component -> component != null
+                                && component.getPackageName().equals(packageName))
+                        || userState.mCrashedServices.removeIf(component -> component != null
+                        && component.getPackageName().equals(packageName));
+                // Reloads the installed services info to make sure the rebound service could
+                // get a new one.
+                userState.mInstalledServices.clear();
+                final boolean configurationChanged;
+                configurationChanged = mManagerService.readConfigurationForUserStateLocked(
+                        userState, parsedAccessibilityServiceInfos,
+                        parsedAccessibilityShortcutInfos);
+                if (reboundAService || configurationChanged) {
+                    mManagerService.onUserStateChangedLocked(userState);
+                }
+                // Passing 0 for restoreFromSdkInt to have this migration check execute each
+                // time. It can make sure a11y button settings are correctly if there's an a11y
+                // service updated and modifies the a11y button configuration.
+                mManagerService.migrateAccessibilityButtonSettingsIfNecessaryLocked(
+                        userState, packageName, /* restoreFromSdkInt = */0);
+            }
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+                    FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+                mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved",
+                        FLAGS_PACKAGE_BROADCAST_RECEIVER,
+                        "packageName=" + packageName + ";uid=" + uid);
+            }
+
+            synchronized (mManagerService.getLock()) {
+                final int userId = getChangingUserId();
+                // Only the profile parent can install accessibility services.
+                // Therefore we ignore packages from linked profiles.
+                if (userId != mManagerService.getCurrentUserIdLocked()) {
+                    return;
+                }
+                mManagerService.onPackageRemovedLocked(packageName);
+            }
+        }
+
+        /**
+         * Handles instances in which a package or packages have forcibly stopped.
+         *
+         * @param intent intent containing package event information.
+         * @param uid linux process user id (different from Android user id).
+         * @param packages array of package names that have stopped.
+         * @param doit whether to try and handle the stop or just log the trace.
+         *
+         * @return {@code true} if doit == {@code false}
+         * and at least one of the provided packages is enabled.
+         * In any other case, returns {@code false}.
+         * This is to indicate whether further action is necessary.
+         */
+        @Override
+        public boolean onHandleForceStop(Intent intent, String[] packages,
+                int uid, boolean doit) {
+            if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes(
+                    FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
+                mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
+                        FLAGS_PACKAGE_BROADCAST_RECEIVER,
+                        "intent=" + intent + ";packages=" + Arrays.toString(packages)
+                                + ";uid=" + uid + ";doit=" + doit);
+            }
+            synchronized (mManagerService.getLock()) {
+                final int userId = getChangingUserId();
+                // Only the profile parent can install accessibility services.
+                // Therefore we ignore packages from linked profiles.
+                if (userId != mManagerService.getCurrentUserIdLocked()) {
+                    return false;
+                }
+                final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId);
+
+                if (Flags.managerPackageMonitorLogicFix()) {
+                    if (!doit) {
+                        // if we're not handling the stop here, then we only need to know
+                        // if any of the force-stopped packages are currently enabled.
+                        return userState.mEnabledServices.stream().anyMatch(
+                                (comp) -> Arrays.stream(packages).anyMatch(
+                                        (pkg) -> pkg.equals(comp.getPackageName()))
+                        );
+                    } else if (mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
+                        mManagerService.onUserStateChangedLocked(userState);
+                    }
+                    return false;
+                } else {
+                    // this old logic did not properly indicate when base packageMonitor's routine
+                    // should handle stopping the package.
+                    if (doit && mManagerService.onPackagesForceStoppedLocked(packages, userState)) {
+                        mManagerService.onUserStateChangedLocked(userState);
+                        return false;
+                    } else {
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+
     void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) {
         final int eventSize =  mSendWindowStateChangedEventRunnables.size();
         for (int i = eventSize - 1; i >= 0; i--) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 71b16c3..5567707 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -521,9 +521,13 @@
                         false);
                 final boolean packageRemovedPermanently =
                         (extras == null || !isReplacing || (isReplacing && isArchival));
-
                 if (packageRemovedPermanently) {
                     for (String pkgName : pkgList) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "calling removeHostsAndProvidersForPackageLocked() "
+                                    + "because package removed permanently. extras=" + extras
+                                    + " isReplacing=" + isReplacing + " isArchival=" + isArchival);
+                        }
                         componentsModified |= removeHostsAndProvidersForPackageLocked(
                                 pkgName, userId);
                     }
@@ -2053,6 +2057,9 @@
     }
 
     private void deleteHostLocked(Host host) {
+        if (DEBUG) {
+            Slog.i(TAG, "deleteHostLocked() " + host);
+        }
         final int N = host.widgets.size();
         for (int i = N - 1; i >= 0; i--) {
             Widget widget = host.widgets.remove(i);
@@ -2065,6 +2072,9 @@
     }
 
     private void deleteAppWidgetLocked(Widget widget) {
+        if (DEBUG) {
+            Slog.i(TAG, "deleteAppWidgetLocked() " + widget);
+        }
         // We first unbind all services that are bound to this id
         // Check if we need to destroy any services (if no other app widgets are
         // referencing the same service)
@@ -2532,6 +2542,10 @@
                 return widget;
             }
         }
+        if (DEBUG) {
+            Slog.i(TAG, "cannot find widget for appWidgetId=" + appWidgetId + " uid=" + uid
+                    + " packageName=" + packageName);
+        }
         return null;
     }
 
@@ -2649,6 +2663,9 @@
 
     // Remove widgets for provider that are hosted in userId.
     private void deleteWidgetsLocked(Provider provider, int userId) {
+        if (DEBUG) {
+            Slog.i(TAG, "deleteWidgetsLocked() provider=" + provider + " userId=" + userId);
+        }
         final int N = provider.widgets.size();
         for (int i = N - 1; i >= 0; i--) {
             Widget widget = provider.widgets.get(i);
@@ -3326,6 +3343,9 @@
      * Adds the widget to mWidgets and tracks the package name in mWidgetPackages.
      */
     void addWidgetLocked(Widget widget) {
+        if (DEBUG) {
+            Slog.i(TAG, "addWidgetLocked() " + widget);
+        }
         mWidgets.add(widget);
 
         onWidgetProviderAddedOrChangedLocked(widget);
@@ -3362,6 +3382,9 @@
      * removes the associated package from the cache.
      */
     void removeWidgetLocked(Widget widget) {
+        if (DEBUG) {
+            Slog.i(TAG, "removeWidgetLocked() " + widget);
+        }
         mWidgets.remove(widget);
         onWidgetRemovedLocked(widget);
         scheduleNotifyAppWidgetRemovedLocked(widget);
@@ -3396,6 +3419,9 @@
      * Clears all widgets and associated cache of packages with bound widgets.
      */
     void clearWidgetsLocked() {
+        if (DEBUG) {
+            Slog.i(TAG, "clearWidgetsLocked()");
+        }
         mWidgets.clear();
 
         onWidgetsClearedLocked();
@@ -3757,6 +3783,9 @@
     }
 
     void onUserStopped(int userId) {
+        if (DEBUG) {
+            Slog.i(TAG, "onUserStopped() " + userId);
+        }
         synchronized (mLock) {
             boolean crossProfileWidgetsChanged = false;
 
@@ -3994,6 +4023,10 @@
     }
 
     private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
+        if (DEBUG) {
+            Slog.i(TAG, "removeHostsAndProvidersForPackageLocked() pkg=" + pkgName
+                    + " userId=" + userId);
+        }
         boolean removed = removeProvidersForPackageLocked(pkgName, userId);
 
         // Delete the hosts for this package too
@@ -4552,6 +4585,10 @@
                 // have the bind widget permission have access to the widget.
                 return true;
             }
+            if (DEBUG) {
+                Slog.i(TAG, "canAccessAppWidget() failed. packageName=" + packageName
+                        + " uid=" + uid + " userId=" + userId + " widget=" + widget);
+            }
             return false;
         }
 
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 9f279b1..f69a521 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -34,6 +34,7 @@
 import android.provider.Downloads;
 import android.system.ErrnoException;
 import android.system.Os;
+import android.system.OsConstants;
 import android.text.TextUtils;
 import android.util.AtomicFile;
 import android.util.EventLog;
@@ -230,16 +231,23 @@
     }
 
     private static String getCurrentBootHeaders() throws IOException {
-        return new StringBuilder(512)
-            .append("Build: ").append(Build.FINGERPRINT).append("\n")
-            .append("Hardware: ").append(Build.BOARD).append("\n")
-            .append("Revision: ")
-            .append(SystemProperties.get("ro.revision", "")).append("\n")
-            .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
-            .append("Radio: ").append(Build.getRadioVersion()).append("\n")
-            .append("Kernel: ")
-            .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
-            .append("\n").toString();
+        StringBuilder builder =  new StringBuilder(512)
+                .append("Build: ").append(Build.FINGERPRINT).append("\n")
+                .append("Hardware: ").append(Build.BOARD).append("\n")
+                .append("Revision: ")
+                .append(SystemProperties.get("ro.revision", "")).append("\n")
+                .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
+                .append("Radio: ").append(Build.getRadioVersion()).append("\n")
+                .append("Kernel: ")
+                .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"));
+
+        // If device is not using 4KB pages, add the PageSize
+        long pageSize = Os.sysconf(OsConstants._SC_PAGESIZE);
+        if (pageSize != 4096) {
+            builder.append("PageSize: ").append(pageSize).append("\n");
+        }
+        builder.append("\n");
+        return builder.toString();
     }
 
 
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index d9e6186..ef03888 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -21,6 +21,7 @@
 import static android.os.Process.SYSTEM_UID;
 
 import static com.android.server.flags.Flags.pinWebview;
+import static com.android.server.flags.Flags.skipHomeArtPins;
 
 import android.annotation.EnforcePermission;
 import android.annotation.IntDef;
@@ -851,6 +852,9 @@
         }
 
         int apkPinSizeLimit = pinSizeLimit;
+
+        boolean shouldSkipArtPins = key == KEY_HOME && skipHomeArtPins();
+
         for (String apk: apks) {
             if (apkPinSizeLimit <= 0) {
                 Slog.w(TAG, "Reached to the pin size limit. Skipping: " + apk);
@@ -874,8 +878,8 @@
             }
 
             apkPinSizeLimit -= pf.bytesPinned;
-            if (apk.equals(appInfo.sourceDir)) {
-                pinOptimizedDexDependencies(pf, apkPinSizeLimit, appInfo);
+            if (apk.equals(appInfo.sourceDir) && !shouldSkipArtPins) {
+                pinOptimizedDexDependencies(pf, Integer.MAX_VALUE, appInfo);
             }
         }
     }
@@ -921,8 +925,8 @@
         }
         pf.groupName = groupName != null ? groupName : "";
 
-        maxBytesToPin -= bytesPinned;
         bytesPinned += pf.bytesPinned;
+        maxBytesToPin -= bytesPinned;
 
         synchronized (this) {
             mPinnedFiles.put(pf.fileName, pf);
@@ -970,7 +974,7 @@
                 // Unpin if it was already pinned prior to re-pinning.
                 unpinFile(file);
 
-                PinnedFile df = mInjector.pinFileInternal(file, Integer.MAX_VALUE,
+                PinnedFile df = mInjector.pinFileInternal(file, maxBytesToPin,
                         /*attemptPinIntrospection=*/false);
                 if (df == null) {
                     Slog.i(TAG, "Failed to pin ART file = " + file);
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 04e85c7..a3b6d80 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -134,6 +134,13 @@
         },
         {
             "name": "CtsSuspendAppsTestCases"
+        },
+        {
+            "name": "CtsWindowManagerBackgroundActivityTestCases",
+            "file_patterns": [
+                "Background.*\\.java",
+                "Activity.*\\.java"
+            ]
         }
     ],
     "presubmit-large": [
@@ -189,18 +196,16 @@
             "name": "SelinuxFrameworksTests"
         },
         {
-            "name": "CtsWindowManagerBackgroundActivityTestCases",
-            "file_patterns": [
-                "Background.*\\.java",
-                "Activity.*\\.java"
-            ]
-        },
-        {
             "name": "WmTests",
             "file_patterns": [
                 "Background.*\\.java",
                 "Activity.*\\.java"
+            ],
+            "options": [
+                {
+                    "include-filter": "com.android.server.wm.BackgroundActivityStart*"
+                }
             ]
         }
-    ]
+   ]
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 00d8efa..58855ea 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -372,6 +372,8 @@
 import android.provider.Settings;
 import android.server.ServerProtoEnums;
 import android.sysprop.InitProperties;
+import android.system.Os;
+import android.system.OsConstants;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.text.style.SuggestionSpan;
@@ -9911,6 +9913,13 @@
             sb.append("ErrorId: ").append(errorId.toString()).append("\n");
         }
         sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+
+        // If device is not using 4KB pages, add the PageSize
+        long pageSize = Os.sysconf(OsConstants._SC_PAGESIZE);
+        if (pageSize != 4096) {
+            sb.append("PageSize: ").append(pageSize).append("\n");
+        }
+
         if (Debug.isDebuggerConnected()) {
             sb.append("Debugger: Connected\n");
         }
@@ -19975,6 +19984,26 @@
 
             addStartInfoTimestampInternal(key, timestampNs, userId, uid);
         }
+
+        @Override
+        public void killApplicationSync(String pkgName, int appId, int userId,
+                String reason, int exitInfoReason) {
+            if (pkgName == null) {
+                return;
+            }
+            // Make sure the uid is valid.
+            if (appId < 0) {
+                Slog.w(TAG, "Invalid appid specified for pkg : " + pkgName);
+                return;
+            }
+            synchronized (ActivityManagerService.this) {
+                ActivityManagerService.this.forceStopPackageLocked(pkgName, appId,
+                        /* callerWillRestart= */ false, /*purgeCache= */ false,
+                        /* doit= */ true, /* evenPersistent= */ false,
+                        /* uninstalling= */ false, /* packageStateStopped= */ false,
+                        userId, reason, exitInfoReason);
+            }
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, TimeoutRecord timeoutRecord) {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 8d7a1c9..da45a77 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -18,10 +18,6 @@
 
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManager.START_SUCCESS;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_COMPAT;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -393,20 +389,13 @@
 
     private static BackgroundStartPrivileges getBackgroundStartPrivilegesAllowedByCaller(
             @Nullable Bundle options, int callingUid, @Nullable String callingPackage) {
-        if (options == null) {
+        if (options == null || !options.containsKey(
+                        ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED)) {
             return getDefaultBackgroundStartPrivileges(callingUid, callingPackage);
         }
-        switch (options.getInt(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED,
-                MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED)) {
-            case MODE_BACKGROUND_ACTIVITY_START_DENIED:
-                return BackgroundStartPrivileges.NONE;
-            case MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED:
-                return getDefaultBackgroundStartPrivileges(callingUid, callingPackage);
-            case MODE_BACKGROUND_ACTIVITY_START_ALLOWED:
-            case MODE_BACKGROUND_ACTIVITY_START_COMPAT:
-            default:
-                return BackgroundStartPrivileges.ALLOW_BAL;
-        }
+        return options.getBoolean(ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED)
+                ? BackgroundStartPrivileges.ALLOW_BAL
+                : BackgroundStartPrivileges.NONE;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 5793758..9bf5c21 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -157,6 +157,7 @@
         "car_telemetry",
         "codec_fwk",
         "companion",
+        "com_android_adbd",
         "content_protection",
         "context_hub",
         "core_experiments_team_internal",
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
index eaa5e2a..53e6bdb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricNotificationUtils.java
@@ -238,7 +238,7 @@
 
         showNotificationHelper(context, name, title, content, setupPendingIntent, setupAction,
                 notNowAction, Notification.CATEGORY_SYSTEM, channel, tag,
-                Notification.VISIBILITY_SECRET, false);
+                Notification.VISIBILITY_SECRET, false, Notification.FLAG_NO_CLEAR);
     }
 
     private static String getFingerprintDanglingContentString(Context context,
@@ -296,13 +296,13 @@
             String notificationTag, int visibility, boolean listenToDismissEvent) {
         showNotificationHelper(context, name, title, content, pendingIntent,
                 null /* positiveAction */, null /* negativeAction */, category, channelName,
-                notificationTag, visibility, listenToDismissEvent);
+                notificationTag, visibility, listenToDismissEvent, 0);
     }
 
     private static void showNotificationHelper(Context context, String name, String title,
             String content, PendingIntent pendingIntent, Notification.Action positiveAction,
             Notification.Action negativeAction, String category, String channelName,
-            String notificationTag, int visibility, boolean listenToDismissEvent) {
+            String notificationTag, int visibility, boolean listenToDismissEvent, int flags) {
         Slog.v(TAG," listenToDismissEvent = " + listenToDismissEvent);
         final PendingIntent dismissIntent = PendingIntent.getActivityAsUser(context,
                 0 /* requestCode */, DISMISS_FRR_INTENT, PendingIntent.FLAG_IMMUTABLE /* flags */,
@@ -324,6 +324,9 @@
                 .setContentIntent(pendingIntent)
                 .setVisibility(visibility);
 
+        if (flags > 0) {
+            builder.setFlag(flags, true);
+        }
         if (positiveAction != null) {
             builder.addAction(positiveAction);
         }
diff --git a/services/core/java/com/android/server/flags/pinner.aconfig b/services/core/java/com/android/server/flags/pinner.aconfig
index 16a45cd..2f817db 100644
--- a/services/core/java/com/android/server/flags/pinner.aconfig
+++ b/services/core/java/com/android/server/flags/pinner.aconfig
@@ -6,4 +6,11 @@
     namespace: "system_performance"
     description: "This flag controls if webview should be pinned in memory."
     bug: "307594624"
+}
+
+flag {
+    name: "skip_home_art_pins"
+    namespace: "system_performance"
+    description: "Ablation study flag that controls if home app odex/vdex files should be pinned in memory."
+    bug: "340935152"
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index e862c7e..ad99950 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -39,6 +39,7 @@
 import android.provider.Settings;
 import android.util.EventLog;
 import android.util.Slog;
+import android.view.Display;
 import android.view.WindowManager;
 import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodInfo;
@@ -78,6 +79,7 @@
     @GuardedBy("ImfLock.class") @Nullable private IInputMethodInvoker mCurMethod;
     @GuardedBy("ImfLock.class") private int mCurMethodUid = Process.INVALID_UID;
     @GuardedBy("ImfLock.class") @Nullable private IBinder mCurToken;
+    @GuardedBy("ImfLock.class") private int mCurTokenDisplayId = Display.INVALID_DISPLAY;
     @GuardedBy("ImfLock.class") private int mCurSeq;
     @GuardedBy("ImfLock.class") private boolean mVisibleBound;
     @GuardedBy("ImfLock.class") private boolean mSupportsStylusHw;
@@ -193,6 +195,17 @@
     }
 
     /**
+     * Returns the displayId associated with {@link #getCurToken()}.
+     *
+     * @return the displayId associated with {@link #getCurToken()}. {@link Display#INVALID_DISPLAY}
+     *         while {@link #getCurToken()} returns {@code null}
+     */
+    @GuardedBy("ImfLock.class")
+    int getCurTokenDisplayId() {
+        return mCurTokenDisplayId;
+    }
+
+    /**
      * The Intent used to connect to the current input method.
      */
     @GuardedBy("ImfLock.class")
@@ -412,15 +425,14 @@
 
     @GuardedBy("ImfLock.class")
     private void removeCurrentToken() {
-        int curTokenDisplayId = mService.getCurTokenDisplayIdLocked();
-
         if (DEBUG) {
             Slog.v(TAG,
-                    "Removing window token: " + mCurToken + " for display: " + curTokenDisplayId);
+                    "Removing window token: " + mCurToken + " for display: " + mCurTokenDisplayId);
         }
         mWindowManagerInternal.removeWindowToken(mCurToken, true /* removeWindows */,
-                false /* animateExit */, curTokenDisplayId);
+                false /* animateExit */, mCurTokenDisplayId);
         mCurToken = null;
+        mCurTokenDisplayId = Display.INVALID_DISPLAY;
     }
 
     @GuardedBy("ImfLock.class")
@@ -445,7 +457,7 @@
 
             final int displayIdToShowIme = mService.getDisplayIdToShowImeLocked();
             mCurToken = new Binder();
-            mService.setCurTokenDisplayIdLocked(displayIdToShowIme);
+            mCurTokenDisplayId = displayIdToShowIme;
             if (DEBUG) {
                 Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
                         + displayIdToShowIme);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index f8dda60..54bf1f3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -603,18 +603,10 @@
      */
     @GuardedBy("ImfLock.class")
     int getCurTokenDisplayIdLocked() {
-        return mCurTokenDisplayId;
+        final var userData = mUserDataRepository.getOrCreate(mCurrentUserId);
+        return userData.mBindingController.getCurTokenDisplayId();
     }
 
-    @GuardedBy("ImfLock.class")
-    void setCurTokenDisplayIdLocked(int curTokenDisplayId) {
-        mCurTokenDisplayId = curTokenDisplayId;
-    }
-
-    @GuardedBy("ImfLock.class")
-    @MultiUserUnawareField
-    private int mCurTokenDisplayId = INVALID_DISPLAY;
-
     /**
      * The display ID of the input method indicates the fallback display which returned by
      * {@link #computeImeDisplayIdForTarget}.
@@ -862,37 +854,6 @@
 
     final class MyPackageMonitor extends PackageMonitor {
         /**
-         * Package names that are known to contain {@link InputMethodService}.
-         *
-         * <p>No need to include packages because of direct-boot unaware IMEs since we always rescan
-         * all the packages when the user is unlocked, and direct-boot awareness will not be changed
-         * dynamically unless the entire package is updated, which also always triggers package
-         * rescanning.</p>
-         */
-        @GuardedBy("ImfLock.class")
-        private final ArraySet<String> mKnownImePackageNames = new ArraySet<>();
-
-        /**
-         * Packages that are appeared, disappeared, or modified for whatever reason.
-         *
-         * <p>Note: For now we intentionally use {@link ArrayList} instead of {@link ArraySet}
-         * because 1) the number of elements is almost always 1 or so, and 2) we do not care
-         * duplicate elements for our use case.</p>
-         *
-         * <p>This object must be accessed only from callback methods in {@link PackageMonitor},
-         * which should be bound to {@link #getRegisteredHandler()}.</p>
-         */
-        private final ArrayList<String> mChangedPackages = new ArrayList<>();
-
-        /**
-         * {@code true} if one or more packages that contain {@link InputMethodService} appeared.
-         *
-         * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
-         * which should be bound to {@link #getRegisteredHandler()}.</p>
-         */
-        private boolean mImePackageAppeared = false;
-
-        /**
          * Remembers package names passed to {@link #onPackageDataCleared(String, int)}.
          *
          * <p>This field must be accessed only from callback methods in {@link PackageMonitor},
@@ -905,16 +866,6 @@
         }
 
         @GuardedBy("ImfLock.class")
-        void clearKnownImePackageNamesLocked() {
-            mKnownImePackageNames.clear();
-        }
-
-        @GuardedBy("ImfLock.class")
-        void addKnownImePackageNameLocked(@NonNull String packageName) {
-            mKnownImePackageNames.add(packageName);
-        }
-
-        @GuardedBy("ImfLock.class")
         private boolean isChangingPackagesOfCurrentUserLocked() {
             final int userId = getChangingUserId();
             final boolean retval = userId == mCurrentUserId;
@@ -964,52 +915,7 @@
         }
 
         @Override
-        public void onPackageAppeared(String packageName, int reason) {
-            if (!mImePackageAppeared) {
-                final PackageManager pm = mContext.getPackageManager();
-                final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
-                        new Intent(InputMethod.SERVICE_INTERFACE).setPackage(packageName),
-                        PackageManager.MATCH_DISABLED_COMPONENTS, getChangingUserId());
-                // No need to lock this because we access it only on getRegisteredHandler().
-                if (!services.isEmpty()) {
-                    mImePackageAppeared = true;
-                }
-            }
-            // No need to lock this because we access it only on getRegisteredHandler().
-            mChangedPackages.add(packageName);
-        }
-
-        @Override
-        public void onPackageDisappeared(String packageName, int reason) {
-            // No need to lock this because we access it only on getRegisteredHandler().
-            mChangedPackages.add(packageName);
-        }
-
-        @Override
-        public void onPackageModified(String packageName) {
-            // No need to lock this because we access it only on getRegisteredHandler().
-            mChangedPackages.add(packageName);
-        }
-
-        @Override
-        public void onPackagesSuspended(String[] packages) {
-            // No need to lock this because we access it only on getRegisteredHandler().
-            for (String packageName : packages) {
-                mChangedPackages.add(packageName);
-            }
-        }
-
-        @Override
-        public void onPackagesUnsuspended(String[] packages) {
-            // No need to lock this because we access it only on getRegisteredHandler().
-            for (String packageName : packages) {
-                mChangedPackages.add(packageName);
-            }
-        }
-
-        @Override
         public void onPackageDataCleared(String packageName, int uid) {
-            mChangedPackages.add(packageName);
             mDataClearedPackages.add(packageName);
         }
 
@@ -1021,32 +927,7 @@
 
         private void clearPackageChangeState() {
             // No need to lock them because we access these fields only on getRegisteredHandler().
-            mChangedPackages.clear();
             mDataClearedPackages.clear();
-            mImePackageAppeared = false;
-        }
-
-        @GuardedBy("ImfLock.class")
-        private boolean shouldRebuildInputMethodListLocked() {
-            // This method is guaranteed to be called only by getRegisteredHandler().
-
-            // If there is any new package that contains at least one IME, then rebuilt the list
-            // of IMEs.
-            if (mImePackageAppeared) {
-                return true;
-            }
-
-            // Otherwise, check if mKnownImePackageNames and mChangedPackages have any intersection.
-            // TODO: Consider to create a utility method to do the following test. List.retainAll()
-            // is an option, but it may still do some extra operations that we do not need here.
-            final int numPackages = mChangedPackages.size();
-            for (int i = 0; i < numPackages; ++i) {
-                final String packageName = mChangedPackages.get(i);
-                if (mKnownImePackageNames.contains(packageName)) {
-                    return true;
-                }
-            }
-            return false;
         }
 
         private void onFinishPackageChangesInternal() {
@@ -1107,12 +988,15 @@
                     AdditionalSubtypeMapRepository.putAndSave(userId, newAdditionalSubtypeMap,
                             settings.getMethodMap());
                 }
-                if (isCurrentUser
-                        && !(additionalSubtypeChanged || shouldRebuildInputMethodListLocked())) {
-                    return;
-                }
+
                 final var newMethodMap = newMethodMapWithoutAdditionalSubtypes
                         .applyAdditionalSubtypes(newAdditionalSubtypeMap);
+
+                if (InputMethodMap.areSame(settings.getMethodMap(), newMethodMap)) {
+                    // No update in the actual IME map.
+                    return;
+                }
+
                 final InputMethodSettings newSettings =
                         InputMethodSettings.create(newMethodMap, userId);
                 InputMethodSettingsRepository.put(userId, newSettings);
@@ -1268,9 +1152,15 @@
         @Override
         public void onUserStarting(TargetUser user) {
             // Called on ActivityManager thread.
-            SecureSettingsWrapper.onUserStarting(user.getUserIdentifier());
+            final int userId = user.getUserIdentifier();
+            SecureSettingsWrapper.onUserStarting(userId);
             synchronized (ImfLock.class) {
-                mService.mUserDataRepository.getOrCreate(user.getUserIdentifier());
+                mService.mUserDataRepository.getOrCreate(userId);
+                if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+                    if (mService.mCurrentUserId != userId) {
+                        mService.experimentalInitializeVisibleBackgroundUserLocked(userId);
+                    }
+                }
             }
         }
 
@@ -1291,6 +1181,8 @@
                 // We need to rebuild IMEs.
                 postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */);
                 updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+            } else if (mExperimentalConcurrentMultiUserModeEnabled) {
+                experimentalInitializeVisibleBackgroundUserLocked(userId);
             }
         }
     }
@@ -2505,7 +2397,6 @@
         mImeWindowVis = 0;
         mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
         updateSystemUiLocked(mImeWindowVis, mBackDisposition);
-        mCurTokenDisplayId = INVALID_DISPLAY;
         mAutofillController.onResetSystemUi();
     }
 
@@ -2927,6 +2818,49 @@
         mMenuController.updateKeyboardFromSettingsLocked();
     }
 
+    /**
+     * This is an experimental implementation used when and only when
+     * {@link #mExperimentalConcurrentMultiUserModeEnabled}.
+     *
+     * <p>Never assume what this method is doing is officially supported. For the canonical and
+     * desired behaviors always refer to single-user code paths such as
+     * {@link #updateInputMethodsFromSettingsLocked(boolean)}.</p>
+     *
+     * <p>Here are examples of missing features.</p>
+     * <ul>
+     *     <li>Subtypes are not supported at all!</li>
+     *     <li>Profiles are not supported.</li>
+     *     <li>
+     *         {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED} is not updated.
+     *     </li>
+     *     <li>{@link #mDeviceIdToShowIme} is ignored.</li>
+     *     <li>{@link #mSwitchingController} is ignored.</li>
+     *     <li>{@link #mHardwareKeyboardShortcutController} is ignored.</li>
+     *     <li>{@link #mPreventImeStartupUnlessTextEditor} is ignored.</li>
+     *     <li>and so on.</li>
+     * </ul>
+     */
+    @GuardedBy("ImfLock.class")
+    void experimentalInitializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
+        if (!mUserManagerInternal.isUserVisible(userId)) {
+            return;
+        }
+        final var settings = InputMethodSettingsRepository.get(userId);
+        String id = settings.getSelectedInputMethod();
+        if (TextUtils.isEmpty(id)) {
+            final InputMethodInfo imi = InputMethodInfoUtils.getMostApplicableDefaultIME(
+                    settings.getEnabledInputMethodList());
+            if (imi == null) {
+                return;
+            }
+            id = imi.getId();
+            settings.putSelectedInputMethod(id);
+        }
+        final var userData = mUserDataRepository.getOrCreate(userId);
+        final var bindingController = userData.mBindingController;
+        bindingController.setSelectedMethodId(id);
+    }
+
     @GuardedBy("ImfLock.class")
     void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
         final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
@@ -5077,30 +5011,9 @@
             return;
         }
         mMethodMapUpdateCount++;
-        mMyPackageMonitor.clearKnownImePackageNamesLocked();
 
         final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
 
-        // Construct the set of possible IME packages for onPackageChanged() to avoid false
-        // negatives when the package state remains to be the same but only the component state is
-        // changed.
-        {
-            // Here we intentionally use PackageManager.MATCH_DISABLED_COMPONENTS since the purpose
-            // of this query is to avoid false negatives.  PackageManager.MATCH_ALL could be more
-            // conservative, but it seems we cannot use it for now (Issue 35176630).
-            final List<ResolveInfo> allInputMethodServices =
-                    mContext.getPackageManager().queryIntentServicesAsUser(
-                            new Intent(InputMethod.SERVICE_INTERFACE),
-                            PackageManager.MATCH_DISABLED_COMPONENTS, settings.getUserId());
-            final int numImes = allInputMethodServices.size();
-            for (int i = 0; i < numImes; ++i) {
-                final ServiceInfo si = allInputMethodServices.get(i).serviceInfo;
-                if (android.Manifest.permission.BIND_INPUT_METHOD.equals(si.permission)) {
-                    mMyPackageMonitor.addKnownImePackageNameLocked(si.packageName);
-                }
-            }
-        }
-
         boolean reenableMinimumNonAuxSystemImes = false;
         // TODO: The following code should find better place to live.
         if (!resetDefaultEnabledIme) {
@@ -6456,8 +6369,8 @@
                         continue;
                     }
                     // Skip on headless user
-                    if (USER_TYPE_SYSTEM_HEADLESS.equals(
-                            mUserManagerInternal.getUserInfo(userId).userType)) {
+                    final var userInfo = mUserManagerInternal.getUserInfo(userId);
+                    if (userInfo != null && USER_TYPE_SYSTEM_HEADLESS.equals(userInfo.userType)) {
                         continue;
                     }
                     final String nextIme;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMap.java b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
index f06643df..bab21e8 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMap.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMap.java
@@ -110,7 +110,7 @@
      * @return {@code true} if both {@link InputMethodMap} instances contain exactly the same data
      */
     @AnyThread
-    static boolean equals(@NonNull InputMethodMap map1, @NonNull InputMethodMap map2) {
+    static boolean areSame(@NonNull InputMethodMap map1, @NonNull InputMethodMap map2) {
         if (map1 == map2) {
             return true;
         }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 17f8abe..b3fb147 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -317,9 +317,6 @@
          */
         private static final int MAX_PROBABILITY_PERCENT = 100;
 
-        /**
-         * Random number generator.
-         */
         private Random mRandom = new Random();
 
         /**
@@ -998,50 +995,75 @@
             return;
         }
 
-        if (message.isReliable()) {
-            byte errorCode = ErrorCode.OK;
-            synchronized (mReliableMessageRecordQueue) {
-                Optional<ReliableMessageRecord> record = Optional.empty();
-                for (ReliableMessageRecord r: mReliableMessageRecordQueue) {
-                    if (r.getContextHubId() == contextHubId
-                            && r.getMessageSequenceNumber() == message.getMessageSequenceNumber()) {
-                        record = Optional.of(r);
-                        break;
-                    }
-                }
-
-                if (record.isPresent()) {
-                    errorCode = record.get().getErrorCode();
-                    if (errorCode == ErrorCode.TRANSIENT_ERROR) {
-                        Log.w(TAG, "Found duplicate reliable message with message sequence number: "
-                                + record.get().getMessageSequenceNumber() + ": retrying");
-                        errorCode = mClientManager.onMessageFromNanoApp(
-                                contextHubId, hostEndpointId, message,
-                                nanoappPermissions, messagePermissions);
-                        record.get().setErrorCode(errorCode);
-                    } else {
-                        Log.w(TAG, "Found duplicate reliable message with message sequence number: "
-                                + record.get().getMessageSequenceNumber());
-                    }
-                } else {
-                    errorCode = mClientManager.onMessageFromNanoApp(
-                            contextHubId, hostEndpointId, message,
-                            nanoappPermissions, messagePermissions);
-                    mReliableMessageRecordQueue.add(
-                            new ReliableMessageRecord(contextHubId,
-                                    SystemClock.elapsedRealtimeNanos(),
-                                    message.getMessageSequenceNumber(),
-                                    errorCode));
-                }
-            }
-            sendMessageDeliveryStatusToContextHub(contextHubId,
-                    message.getMessageSequenceNumber(), errorCode);
-        } else {
+        if (!message.isReliable()) {
             mClientManager.onMessageFromNanoApp(
                     contextHubId, hostEndpointId, message,
                     nanoappPermissions, messagePermissions);
+            cleanupReliableMessageRecordQueue();
+            return;
         }
 
+        byte errorCode = ErrorCode.OK;
+        synchronized (mReliableMessageRecordQueue) {
+            Optional<ReliableMessageRecord> record =
+                    findReliableMessageRecord(contextHubId,
+                            message.getMessageSequenceNumber());
+
+            if (record.isPresent()) {
+                errorCode = record.get().getErrorCode();
+                if (errorCode == ErrorCode.TRANSIENT_ERROR) {
+                    Log.w(TAG, "Found duplicate reliable message with message sequence number: "
+                            + record.get().getMessageSequenceNumber() + ": retrying");
+                    errorCode = mClientManager.onMessageFromNanoApp(
+                            contextHubId, hostEndpointId, message,
+                            nanoappPermissions, messagePermissions);
+                    record.get().setErrorCode(errorCode);
+                } else {
+                    Log.w(TAG, "Found duplicate reliable message with message sequence number: "
+                            + record.get().getMessageSequenceNumber());
+                }
+            } else {
+                errorCode = mClientManager.onMessageFromNanoApp(
+                        contextHubId, hostEndpointId, message,
+                        nanoappPermissions, messagePermissions);
+                mReliableMessageRecordQueue.add(
+                        new ReliableMessageRecord(contextHubId,
+                                SystemClock.elapsedRealtimeNanos(),
+                                message.getMessageSequenceNumber(),
+                                errorCode));
+            }
+        }
+
+        sendMessageDeliveryStatusToContextHub(contextHubId,
+                message.getMessageSequenceNumber(), errorCode);
+        cleanupReliableMessageRecordQueue();
+    }
+
+    /**
+     * Finds a reliable message record in the queue that matches the given
+     * context hub ID and message sequence number. This function assumes
+     * the caller is synchronized on mReliableMessageRecordQueue.
+     *
+     * @param contextHubId the ID of the hub
+     * @param messageSequenceNumber the message sequence number
+     *
+     * @return the record if found, or empty if not found
+     */
+    private Optional<ReliableMessageRecord> findReliableMessageRecord(
+            int contextHubId, int messageSequenceNumber) {
+        for (ReliableMessageRecord record: mReliableMessageRecordQueue) {
+            if (record.getContextHubId() == contextHubId
+                && record.getMessageSequenceNumber() == messageSequenceNumber) {
+                return Optional.of(record);
+            }
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Removes old entries from the reliable message record queue.
+     */
+    private void cleanupReliableMessageRecordQueue() {
         synchronized (mReliableMessageRecordQueue) {
             while (mReliableMessageRecordQueue.peek() != null
                    && mReliableMessageRecordQueue.peek().isExpired()) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index a7fd750..386657e 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -81,6 +81,7 @@
 
     MediaRoute2ProviderServiceProxy(
             @NonNull Context context,
+            @NonNull Looper looper,
             @NonNull ComponentName componentName,
             boolean isSelfScanOnlyProvider,
             int userId) {
@@ -88,7 +89,7 @@
         mContext = Objects.requireNonNull(context, "Context must not be null.");
         mIsSelfScanOnlyProvider = isSelfScanOnlyProvider;
         mUserId = userId;
-        mHandler = new Handler(Looper.myLooper());
+        mHandler = new Handler(looper);
     }
 
     public void setManagerScanning(boolean managerScanning) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index 178eb71..7c1a5e1 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -142,6 +142,7 @@
                     MediaRoute2ProviderServiceProxy proxy =
                             new MediaRoute2ProviderServiceProxy(
                                     mContext,
+                                    mHandler.getLooper(),
                                     new ComponentName(serviceInfo.packageName, serviceInfo.name),
                                     isSelfScanOnlyProvider,
                                     mUserId);
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
index b2e861c..dd76037 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.ondeviceintelligence;
 
+import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.DEVICE_CONFIG_UPDATE_BUNDLE_KEY;
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BUNDLE_KEY;
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_UNLOADED_BUNDLE_KEY;
 import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY;
@@ -115,9 +116,10 @@
 
     /** Handler message to {@link #resetTemporaryServices()} */
     private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
-
     /** Handler message to clean up temporary broadcast keys. */
     private static final int MSG_RESET_BROADCAST_KEYS = 1;
+    /** Handler message to clean up temporary config namespace. */
+    private static final int MSG_RESET_CONFIG_NAMESPACE = 2;
 
     /** Default value in absence of {@link DeviceConfig} override. */
     private static final boolean DEFAULT_SERVICE_ENABLED = true;
@@ -129,6 +131,7 @@
     private final Executor resourceClosingExecutor = Executors.newCachedThreadPool();
     private final Executor callbackExecutor = Executors.newCachedThreadPool();
     private final Executor broadcastExecutor = Executors.newCachedThreadPool();
+    private final Executor mConfigExecutor = Executors.newCachedThreadPool();
 
 
     private final Context mContext;
@@ -145,6 +148,12 @@
     private String[] mTemporaryBroadcastKeys;
     @GuardedBy("mLock")
     private String mBroadcastPackageName;
+    @GuardedBy("mLock")
+    private String mTemporaryConfigNamespace;
+
+    private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+            this::sendUpdatedConfig;
+
 
     /**
      * Handler used to reset the temporary service names.
@@ -593,12 +602,14 @@
                                     @NonNull IOnDeviceSandboxedInferenceService service) {
                                 try {
                                     ensureRemoteIntelligenceServiceInitialized();
+                                    service.registerRemoteStorageService(
+                                            getIRemoteStorageService());
                                     mRemoteOnDeviceIntelligenceService.run(
                                             IOnDeviceIntelligenceService::notifyInferenceServiceConnected);
                                     broadcastExecutor.execute(
                                             () -> registerModelLoadingBroadcasts(service));
-                                    service.registerRemoteStorageService(
-                                            getIRemoteStorageService());
+                                    mConfigExecutor.execute(
+                                            () -> registerDeviceConfigChangeListener());
                                 } catch (RemoteException ex) {
                                     Slog.w(TAG, "Failed to send connected event", ex);
                                 }
@@ -658,6 +669,56 @@
         }
     }
 
+    private void registerDeviceConfigChangeListener() {
+        Log.d(TAG, "registerDeviceConfigChangeListener");
+        String configNamespace = getConfigNamespace();
+        if (configNamespace.isEmpty()) {
+            Slog.e(TAG, "config_defaultOnDeviceIntelligenceDeviceConfigNamespace is empty");
+            return;
+        }
+        DeviceConfig.addOnPropertiesChangedListener(
+                configNamespace,
+                mConfigExecutor,
+                mOnPropertiesChangedListener);
+    }
+
+    private String getConfigNamespace() {
+        synchronized (mLock) {
+            if (mTemporaryConfigNamespace != null) {
+                return mTemporaryConfigNamespace;
+            }
+
+            return mContext.getResources().getString(
+                    R.string.config_defaultOnDeviceIntelligenceDeviceConfigNamespace);
+        }
+    }
+
+    private void sendUpdatedConfig(
+            DeviceConfig.Properties props) {
+        Log.d(TAG, "sendUpdatedConfig");
+
+        PersistableBundle persistableBundle = new PersistableBundle();
+        for (String key : props.getKeyset()) {
+            persistableBundle.putString(key, props.getString(key, ""));
+        }
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(DEVICE_CONFIG_UPDATE_BUNDLE_KEY, persistableBundle);
+        ensureRemoteInferenceServiceInitialized();
+        mRemoteInferenceService.run(service -> service.updateProcessingState(bundle,
+                new IProcessingUpdateStatusCallback.Stub() {
+                    @Override
+                    public void onSuccess(PersistableBundle result) {
+                        Slog.d(TAG, "Config update successful." + result);
+                    }
+
+                    @Override
+                    public void onFailure(int errorCode, String errorMessage) {
+                        Slog.e(TAG, "Config update failed with code ["
+                                + String.valueOf(errorCode) + "] and message = " + errorMessage);
+                    }
+                }));
+    }
+
     @NonNull
     private IRemoteStorageService.Stub getIRemoteStorageService() {
         return new IRemoteStorageService.Stub() {
@@ -849,8 +910,23 @@
     }
 
     @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
+    public void setTemporaryDeviceConfigNamespace(@NonNull String configNamespace,
+            int durationMs) {
+        Objects.requireNonNull(configNamespace);
+        enforceShellOnly(Binder.getCallingUid(), "setTemporaryDeviceConfigNamespace");
+        mContext.enforceCallingPermission(
+                Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
+        synchronized (mLock) {
+            mTemporaryConfigNamespace = configNamespace;
+            if (durationMs != -1) {
+                getTemporaryHandler().sendEmptyMessageDelayed(MSG_RESET_CONFIG_NAMESPACE,
+                        durationMs);
+            }
+        }
+    }
+
+    @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE)
     public void resetTemporaryServices() {
-        enforceShellOnly(Binder.getCallingUid(), "resetTemporaryServices");
         mContext.enforceCallingPermission(
                 Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG);
         synchronized (mLock) {
@@ -937,17 +1013,17 @@
             mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
                 @Override
                 public void handleMessage(Message msg) {
-                    if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
-                        synchronized (mLock) {
+                    synchronized (mLock) {
+                        if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
                             resetTemporaryServices();
-                        }
-                    } else if (msg.what == MSG_RESET_BROADCAST_KEYS) {
-                        synchronized (mLock) {
+                        } else if (msg.what == MSG_RESET_BROADCAST_KEYS) {
                             mTemporaryBroadcastKeys = null;
                             mBroadcastPackageName = SYSTEM_PACKAGE;
+                        } else if (msg.what == MSG_RESET_CONFIG_NAMESPACE) {
+                            mTemporaryConfigNamespace = null;
+                        } else {
+                            Slog.wtf(TAG, "invalid handler msg: " + msg);
                         }
-                    } else {
-                        Slog.wtf(TAG, "invalid handler msg: " + msg);
                     }
                 }
             };
diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
index 5744b5c..d2c84fa 100644
--- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
+++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java
@@ -17,6 +17,7 @@
 package com.android.server.ondeviceintelligence;
 
 import android.annotation.NonNull;
+import android.os.Binder;
 import android.os.ShellCommand;
 
 import java.io.PrintWriter;
@@ -45,6 +46,8 @@
                 return getConfiguredServices();
             case "set-model-broadcasts":
                 return setBroadcastKeys();
+            case "set-deviceconfig-namespace":
+                return setDeviceConfigNamespace();
             default:
                 return handleDefaultCommands(cmd);
         }
@@ -69,6 +72,10 @@
                         + "[ReceiverPackageName] "
                         + "[DURATION] To set the names of broadcast intent keys that are to be "
                         + "emitted for cts tests.");
+        pw.println(
+                "  set-deviceconfig-namespace [DeviceConfigNamespace] "
+                        + "[DURATION] To set the device config namespace "
+                        + "to use for cts tests.");
     }
 
     private int setTemporaryServices() {
@@ -78,6 +85,8 @@
 
         if (getRemainingArgsCount() == 0 && intelligenceServiceName == null
                 && inferenceServiceName == null) {
+            OnDeviceIntelligenceManagerService.enforceShellOnly(Binder.getCallingUid(),
+                    "resetTemporaryServices");
             mService.resetTemporaryServices();
             out.println("OnDeviceIntelligenceManagerService temporary reset. ");
             return 0;
@@ -120,4 +129,16 @@
         return 0;
     }
 
+    private int setDeviceConfigNamespace() {
+        final PrintWriter out = getOutPrintWriter();
+        final String configNamespace = getNextArg();
+
+        final int duration = Integer.parseInt(getNextArgRequired());
+        mService.setTemporaryDeviceConfigNamespace(configNamespace, duration);
+        out.println("OnDeviceIntelligence DeviceConfig Namespace temporarily set to "
+                + configNamespace
+                + " for " + duration + "ms");
+        return 0;
+    }
+
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/PackageFreezer.java b/services/core/java/com/android/server/pm/PackageFreezer.java
index 7c56157..0afda45 100644
--- a/services/core/java/com/android/server/pm/PackageFreezer.java
+++ b/services/core/java/com/android/server/pm/PackageFreezer.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.Flags;
 import android.content.pm.PackageManager;
 
 import dalvik.system.CloseGuard;
@@ -76,8 +77,13 @@
             ps = mPm.mSettings.getPackageLPr(mPackageName);
         }
         if (ps != null) {
-            mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason,
-                    exitInfoReason);
+            if (Flags.waitApplicationKilled()) {
+                mPm.killApplicationSync(ps.getPackageName(), ps.getAppId(), userId, killReason,
+                        exitInfoReason);
+            } else {
+                mPm.killApplication(ps.getPackageName(), ps.getAppId(), userId, killReason,
+                        exitInfoReason);
+            }
         }
         mCloseGuard.open("close");
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fda8535..f8fceda 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -53,6 +53,7 @@
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.ApplicationExitInfo;
 import android.app.ApplicationPackageManager;
@@ -3132,6 +3133,20 @@
         }
     }
 
+    void killApplicationSync(String pkgName, @AppIdInt int appId,
+            @UserIdInt int userId, String reason, int exitInfoReason) {
+        ActivityManagerInternal mAmi = LocalServices.getService(ActivityManagerInternal.class);
+        if (mAmi != null) {
+            if (Thread.holdsLock(mLock)) {
+                // holds PM's lock, go back killApplication to avoid it run into watchdog reset.
+                Slog.e(TAG, "Holds PM's locker, unable kill application synchronized");
+                killApplication(pkgName, appId, userId, reason, exitInfoReason);
+            } else {
+                mAmi.killApplicationSync(pkgName, appId, userId, reason, exitInfoReason);
+            }
+        }
+    }
+
     @Override
     public void notifyPackageAdded(String packageName, int uid) {
         mPackageObserverHelper.notifyAdded(packageName, uid);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 5fa8856..11b9e77 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -64,6 +64,7 @@
 import com.android.server.input.InputManagerInternal;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.feature.PowerManagerFlags;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.PrintWriter;
@@ -187,11 +188,16 @@
 
     private final AtomicBoolean mIsPlayingChargingStartedFeedback = new AtomicBoolean(false);
 
+    private final Injector mInjector;
+
+    private final PowerManagerFlags mFlags;
+
     public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
             SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
             FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
-            Executor backgroundExecutor) {
+            Executor backgroundExecutor, PowerManagerFlags powerManagerFlags, Injector injector) {
         mContext = context;
+        mFlags = powerManagerFlags;
         mBatteryStats = batteryStats;
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mSuspendBlocker = suspendBlocker;
@@ -224,8 +230,8 @@
         mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);
 
-        mWakeLockLog = new WakeLockLog(context);
-
+        mInjector = (injector == null) ? new RealInjector() : injector;
+        mWakeLockLog = mInjector.getWakeLockLog(context);
         // Initialize interactive state for battery stats.
         try {
             mBatteryStats.noteInteractive(true);
@@ -267,7 +273,7 @@
                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
                     + ", workSource=" + workSource);
         }
-        notifyWakeLockListener(callback, tag, true);
+        notifyWakeLockListener(callback, tag, true, ownerUid, flags);
         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
         if (monitorType >= 0) {
             try {
@@ -287,8 +293,9 @@
             }
         }
 
-        mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags);
-
+        if (!mFlags.improveWakelockLatency()) {
+            mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1);
+        }
         mWakefulnessSessionObserver.onWakeLockAcquired(flags);
     }
 
@@ -406,7 +413,7 @@
                     + ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
                     + ", workSource=" + workSource);
         }
-        notifyWakeLockListener(callback, tag, false);
+        notifyWakeLockListener(callback, tag, false, ownerUid, flags);
         final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
         if (monitorType >= 0) {
             try {
@@ -422,8 +429,9 @@
                 // Ignore
             }
         }
-        mWakeLockLog.onWakeLockReleased(tag, ownerUid);
-
+        if (!mFlags.improveWakelockLatency()) {
+            mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1);
+        }
         mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason);
     }
 
@@ -1040,10 +1048,19 @@
         return enabled && dndOff;
     }
 
-    private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled) {
+    private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled,
+            int ownerUid, int flags) {
         if (callback != null) {
+            long currentTime = mInjector.currentTimeMillis();
             mHandler.post(() -> {
                 try {
+                    if (mFlags.improveWakelockLatency()) {
+                        if (isEnabled) {
+                            mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
+                        } else {
+                            mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
+                        }
+                    }
                     callback.onStateChanged(isEnabled);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
@@ -1057,6 +1074,7 @@
         public NotifierHandler(Looper looper) {
             super(looper, null, true /*async*/);
         }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -1085,4 +1103,28 @@
             }
         }
     }
+
+    public interface Injector {
+        /**
+         * Gets the current time in millis
+         */
+        long currentTimeMillis();
+
+        /**
+         * Gets the WakeLockLog object
+         */
+        WakeLockLog getWakeLockLog(Context context);
+    }
+
+    static class RealInjector implements Injector {
+        @Override
+        public long currentTimeMillis() {
+            return System.currentTimeMillis();
+        }
+
+        @Override
+        public WakeLockLog getWakeLockLog(Context context) {
+            return new WakeLockLog(context);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 76cedd8..ce0120c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -988,10 +988,10 @@
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
                 FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
-                Executor backgroundExecutor) {
+                Executor backgroundExecutor, PowerManagerFlags powerManagerFlags) {
             return new Notifier(
                     looper, context, batteryStats, suspendBlocker, policy, faceDownDetector,
-                    screenUndimDetector, backgroundExecutor);
+                    screenUndimDetector, backgroundExecutor, powerManagerFlags, /*injector=*/ null);
         }
 
         SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
@@ -1373,7 +1373,7 @@
             mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
                     mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
                     mPolicy, mFaceDownDetector, mScreenUndimDetector,
-                    BackgroundThread.getExecutor());
+                    BackgroundThread.getExecutor(), mFeatureFlags);
 
             mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP,
                     new PowerGroup(WAKEFULNESS_AWAKE, mPowerGroupWakefulnessChangeListener,
diff --git a/services/core/java/com/android/server/power/WakeLockLog.java b/services/core/java/com/android/server/power/WakeLockLog.java
index b131311..968ff59 100644
--- a/services/core/java/com/android/server/power/WakeLockLog.java
+++ b/services/core/java/com/android/server/power/WakeLockLog.java
@@ -154,9 +154,10 @@
      * @param tag The wake lock tag
      * @param ownerUid The owner UID of the wake lock.
      * @param flags Flags used for the wake lock.
+     * @param eventTime The time at which the event occurred
      */
-    public void onWakeLockAcquired(String tag, int ownerUid, int flags) {
-        onWakeLockEvent(TYPE_ACQUIRE, tag, ownerUid, flags);
+    public void onWakeLockAcquired(String tag, int ownerUid, int flags, long eventTime) {
+        onWakeLockEvent(TYPE_ACQUIRE, tag, ownerUid, flags, eventTime);
     }
 
     /**
@@ -164,9 +165,10 @@
      *
      * @param tag The wake lock tag
      * @param ownerUid The owner UID of the wake lock.
+     * @param eventTime The time at which the event occurred
      */
-    public void onWakeLockReleased(String tag, int ownerUid) {
-        onWakeLockEvent(TYPE_RELEASE, tag, ownerUid, 0 /* flags */);
+    public void onWakeLockReleased(String tag, int ownerUid, long eventTime) {
+        onWakeLockEvent(TYPE_RELEASE, tag, ownerUid, 0 /* flags */, eventTime);
     }
 
     /**
@@ -242,9 +244,10 @@
      * @param tag The wake lock's identifying tag.
      * @param ownerUid The owner UID of the wake lock.
      * @param flags The flags used with the wake lock.
+     * @param eventTime The time at which the event occurred
      */
     private void onWakeLockEvent(int eventType, String tag, int ownerUid,
-            int flags) {
+            int flags, long eventTime) {
         if (tag == null) {
             Slog.w(TAG, "Insufficient data to log wakelock [tag: " + tag
                     + ", ownerUid: " + ownerUid
@@ -252,7 +255,8 @@
             return;
         }
 
-        final long time = mInjector.currentTimeMillis();
+        final long time = (eventTime == -1) ? mInjector.currentTimeMillis() : eventTime;
+
         final int translatedFlags = eventType == TYPE_ACQUIRE
                 ? translateFlagsFromPowerManager(flags)
                 : 0;
diff --git a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
index a5a7069..ff1d2e4 100644
--- a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
+++ b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java
@@ -35,18 +35,31 @@
             Flags.FLAG_ENABLE_EARLY_SCREEN_TIMEOUT_DETECTOR,
             Flags::enableEarlyScreenTimeoutDetector);
 
+    private final FlagState mImproveWakelockLatency = new FlagState(
+            Flags.FLAG_IMPROVE_WAKELOCK_LATENCY,
+            Flags::improveWakelockLatency
+    );
+
     /** Returns whether early-screen-timeout-detector is enabled on not. */
     public boolean isEarlyScreenTimeoutDetectorEnabled() {
         return mEarlyScreenTimeoutDetectorFlagState.isEnabled();
     }
 
     /**
+     * @return Whether to improve the wakelock acquire/release latency or not
+     */
+    public boolean improveWakelockLatency() {
+        return mImproveWakelockLatency.isEnabled();
+    }
+
+    /**
      * dumps all flagstates
      * @param pw printWriter
      */
     public void dump(PrintWriter pw) {
         pw.println("PowerManagerFlags:");
         pw.println(" " + mEarlyScreenTimeoutDetectorFlagState);
+        pw.println(" " + mImproveWakelockLatency);
     }
 
     private static class FlagState {
diff --git a/services/core/java/com/android/server/power/feature/power_flags.aconfig b/services/core/java/com/android/server/power/feature/power_flags.aconfig
index ca58153..3581b2f 100644
--- a/services/core/java/com/android/server/power/feature/power_flags.aconfig
+++ b/services/core/java/com/android/server/power/feature/power_flags.aconfig
@@ -10,3 +10,11 @@
     bug: "309861917"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "improve_wakelock_latency"
+    namespace: "power"
+    description: "Feature flag for tracking the optimizations to improve the latency of acquiring and releasing a wakelock."
+    bug: "339590565"
+    is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index e280bdc..5be5bc5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -984,36 +984,26 @@
                 Region touchableRegion = mTempRegion3;
                 windowState.getTouchableRegion(touchableRegion);
                 Region windowBounds = mTempRegion2;
-                if (Flags.useWindowOriginalTouchableRegionWhenMagnificationRecomputeBounds()) {
-                    // For b/323366243, if using the bounds from touchableRegion.getBounds, in
-                    // non-magnifiable windowBounds computation, part of the non-touchableRegion
-                    // may be included into nonMagnifiedBounds. This will make users lose
-                    // the magnification control on mis-included areas.
-                    // Therefore, to prevent the above issue, we change to use the window exact
-                    // touchableRegion in magnificationRegion computation.
-                    // Like the original approach, the touchableRegion is in non-magnified display
-                    // space, so first we need to offset the region by the windowFrames bounds, then
-                    // apply the transform matrix to the region to get the exact region in magnified
-                    // display space.
-                    // TODO: For a long-term plan, since touchable regions provided by WindowState
-                    //  doesn't actually reflect the real touchable regions on display, we should
-                    //  delete the WindowState dependency and migrate to use the touchableRegion
-                    //  from WindowInfoListener data. (b/330653961)
-                    touchableRegion.translate(-windowState.getFrame().left,
-                            -windowState.getFrame().top);
-                    applyMatrixToRegion(matrix, touchableRegion);
-                    windowBounds.set(touchableRegion);
-                } else {
-                    Rect touchableFrame = mTempRect1;
-                    touchableRegion.getBounds(touchableFrame);
-                    RectF windowFrame = mTempRectF;
-                    windowFrame.set(touchableFrame);
-                    windowFrame.offset(-windowState.getFrame().left,
-                            -windowState.getFrame().top);
-                    matrix.mapRect(windowFrame);
-                    windowBounds.set((int) windowFrame.left, (int) windowFrame.top,
-                            (int) windowFrame.right, (int) windowFrame.bottom);
-                }
+
+                // For b/323366243, if using the bounds from touchableRegion.getBounds, in
+                // non-magnifiable windowBounds computation, part of the non-touchableRegion
+                // may be included into nonMagnifiedBounds. This will make users lose
+                // the magnification control on mis-included areas.
+                // Therefore, to prevent the above issue, we change to use the window exact
+                // touchableRegion in magnificationRegion computation.
+                // Like the original approach, the touchableRegion is in non-magnified display
+                // space, so first we need to offset the region by the windowFrames bounds, then
+                // apply the transform matrix to the region to get the exact region in magnified
+                // display space.
+                // TODO: For a long-term plan, since touchable regions provided by WindowState
+                //  doesn't actually reflect the real touchable regions on display, we should
+                //  delete the WindowState dependency and migrate to use the touchableRegion
+                //  from WindowInfoListener data. (b/330653961)
+                touchableRegion.translate(-windowState.getFrame().left,
+                        -windowState.getFrame().top);
+                applyMatrixToRegion(matrix, touchableRegion);
+                windowBounds.set(touchableRegion);
+
                 // Only update new regions
                 Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
                 portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76e7f53..d053bbb 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -77,7 +77,6 @@
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
 import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
 import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
@@ -87,6 +86,7 @@
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
@@ -121,6 +121,7 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15;
+import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -128,7 +129,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED;
 import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING;
-import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
@@ -682,6 +682,12 @@
     // it references to gets removed. This should also be cleared when we move out of pip.
     private Task mLastParentBeforePip;
 
+    // The token of the previous TaskFragment parent of this embedded ActivityRecord when it is
+    // reparented to a new Task due to picture-in-picture.
+    // Note that the TaskFragment may be finished and no longer attached in WM hierarchy.
+    @Nullable
+    private IBinder mLastEmbeddedParentTfTokenBeforePip;
+
     // Only set if this instance is a launch-into-pip Activity, points to the
     // host Activity the launch-into-pip Activity is originated from.
     private ActivityRecord mLaunchIntoPipHostActivity;
@@ -1806,6 +1812,11 @@
         mLastTaskFragmentOrganizerBeforePip = organizedTf != null
                 ? organizedTf.getTaskFragmentOrganizer()
                 : null;
+        if (organizedTf != null
+                // Not necessary for content pip.
+                && launchIntoPipHostActivity == null) {
+            mLastEmbeddedParentTfTokenBeforePip = organizedTf.getFragmentToken();
+        }
     }
 
     void clearLastParentBeforePip() {
@@ -1815,12 +1826,17 @@
         }
         mLaunchIntoPipHostActivity = null;
         mLastTaskFragmentOrganizerBeforePip = null;
+        mLastEmbeddedParentTfTokenBeforePip = null;
     }
 
     @Nullable Task getLastParentBeforePip() {
         return mLastParentBeforePip;
     }
 
+    @Nullable IBinder getLastEmbeddedParentTfTokenBeforePip() {
+        return mLastEmbeddedParentTfTokenBeforePip;
+    }
+
     @Nullable ActivityRecord getLaunchIntoPipHostActivity() {
         return mLaunchIntoPipHostActivity;
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 08aeede..72b854b 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1768,7 +1768,6 @@
             if (!avoidMoveToFront() && (mService.mHomeProcess == null
                     || mService.mHomeProcess.mUid != realCallingUid)
                     && (prevTopTask != null && prevTopTask.isActivityTypeHomeOrRecents())
-                    && !targetTask.isActivityTypeHomeOrRecents()
                     && r.mTransitionController.isTransientHide(targetTask)) {
                 mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
             }
@@ -2167,7 +2166,7 @@
             // We don't need to start a new activity, and the client said not to do anything
             // if that is the case, so this is it!  And for paranoia, make sure we have
             // correctly resumed the top activity.
-            if (!mMovedToFront && mDoResume && !avoidMoveToFront()) {
+            if (!mMovedToFront && mDoResume) {
                 ProtoLog.d(WM_DEBUG_TASKS, "Bring to front target: %s from %s", mTargetRootTask,
                         targetTaskTop);
                 mTargetRootTask.moveToFront("intentActivityFound");
@@ -2196,7 +2195,7 @@
         if (mMovedToFront) {
             // We moved the task to front, use starting window to hide initial drawn delay.
             targetTaskTop.showStartingWindow(true /* taskSwitch */);
-        } else if (mDoResume && !avoidMoveToFront()) {
+        } else if (mDoResume) {
             // Make sure the root task and its belonging display are moved to topmost.
             mTargetRootTask.moveToFront("intentActivityFound");
         }
@@ -2733,7 +2732,7 @@
         // If a target task is specified, try to reuse that one
         if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
             Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
-            if (launchTask != null) {
+            if (launchTask != null && launchTask.isLeafTask()) {
                 return launchTask;
             }
             return null;
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index f7910b0..62931bb 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -20,7 +20,6 @@
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityOptions.BackgroundActivityStartMode;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED;
-import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_COMPAT;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
 import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -106,7 +105,6 @@
     static final String AUTO_OPT_IN_NOT_PENDING_INTENT = "notPendingIntent";
     static final String AUTO_OPT_IN_CALL_FOR_RESULT = "callForResult";
     static final String AUTO_OPT_IN_SAME_UID = "sameUid";
-    static final String AUTO_OPT_IN_COMPAT = "compatibility";
 
     /** If enabled the creator will not allow BAL on its behalf by default. */
     @ChangeId
@@ -305,10 +303,6 @@
             } else if (callingUid == realCallingUid && !balRequireOptInSameUid()) {
                 mAutoOptInReason = AUTO_OPT_IN_SAME_UID;
                 mAutoOptInCaller = false;
-            } else if (realCallerBackgroundActivityStartMode
-                    == MODE_BACKGROUND_ACTIVITY_START_COMPAT) {
-                mAutoOptInReason = AUTO_OPT_IN_COMPAT;
-                mAutoOptInCaller = false;
             } else {
                 mAutoOptInReason = null;
                 mAutoOptInCaller = false;
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 16d7b4f..6e11e08 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1149,6 +1149,17 @@
     }
 
     boolean shouldApplyUserFullscreenOverride() {
+        // Do not override orientation to fullscreen for camera activities.
+        // Fixed-orientation activities are rarely tested in other orientations, and it often
+        // results in sideways or stretched previews. As the camera compat treatment targets
+        // fixed-orientation activities, overriding the orientation disables the treatment.
+        final DisplayContent displayContent = mActivityRecord.mDisplayContent;
+        if (displayContent != null && displayContent.mDisplayRotationCompatPolicy != null
+                && displayContent.mDisplayRotationCompatPolicy
+                .isCameraActive(mActivityRecord, /* mustBeFullscreen= */ true)) {
+            return false;
+        }
+
         if (isUserFullscreenOverrideEnabled()) {
             mUserAspectRatio = getUserMinAspectRatioOverrideCode();
 
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 26e4eaa..a3f1503 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1241,7 +1241,7 @@
                 // have any running activities, not starting one and not home stack.
                 shouldBeVisible = hasRunningActivities
                         || (starting != null && starting.isDescendantOf(this))
-                        || isActivityTypeHome();
+                        || (isActivityTypeHome() && !isEmbedded());
                 break;
             }
 
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 24b533a..c4e932a 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -365,7 +365,8 @@
 
         @Nullable
         TaskFragmentTransaction.Change prepareActivityReparentedToTask(
-                @NonNull ActivityRecord activity) {
+                @NonNull ActivityRecord activity, @Nullable ActivityRecord nextFillTaskActivity,
+                @Nullable IBinder lastParentTfToken) {
             if (activity.finishing) {
                 Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
                 return null;
@@ -408,10 +409,21 @@
             }
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
                     activity.token, task.mTaskId);
-            return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
-                    .setTaskId(task.mTaskId)
-                    .setActivityIntent(trimIntent(activity.intent))
-                    .setActivityToken(activityToken);
+
+            final TaskFragmentTransaction.Change change =
+                    new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
+                            .setTaskId(task.mTaskId)
+                            .setActivityIntent(trimIntent(activity.intent))
+                            .setActivityToken(activityToken);
+            if (lastParentTfToken != null) {
+                change.setTaskFragmentToken(lastParentTfToken);
+            }
+            // Only pass the activity token to the client if it belongs to the same process.
+            if (Flags.fixPipRestoreToOverlay() && nextFillTaskActivity != null
+                    && nextFillTaskActivity.getPid() == mOrganizerPid) {
+                change.setOtherActivityToken(nextFillTaskActivity.token);
+            }
+            return change;
         }
 
         void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) {
@@ -733,13 +745,13 @@
     }
 
     void onActivityReparentedToTask(@NonNull ActivityRecord activity) {
+        final Task task = activity.getTask();
         final ITaskFragmentOrganizer organizer;
         if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
             // If the activity is previously embedded in an organized TaskFragment.
             organizer = activity.mLastTaskFragmentOrganizerBeforePip;
         } else {
             // Find the topmost TaskFragmentOrganizer.
-            final Task task = activity.getTask();
             final TaskFragment[] organizedTf = new TaskFragment[1];
             task.forAllLeafTaskFragments(tf -> {
                 if (tf.isOrganizedTaskFragment()) {
@@ -757,10 +769,24 @@
             Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
             return;
         }
-        addPendingEvent(new PendingTaskFragmentEvent.Builder(
+
+        final IBinder parentTfTokenBeforePip = activity.getLastEmbeddedParentTfTokenBeforePip();
+        final PendingTaskFragmentEvent.Builder builder = new PendingTaskFragmentEvent.Builder(
                 PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK, organizer)
                 .setActivity(activity)
-                .build());
+                .setTaskFragmentToken(activity.getLastEmbeddedParentTfTokenBeforePip());
+
+        // Sets the next activity behinds the reparented Activity that's also not in the last
+        // embedded parent TF.
+        final ActivityRecord candidateAssociatedActivity = task.getActivity(
+                ar -> ar != activity && !ar.finishing
+                        && ar.getTaskFragment().getFragmentToken() != parentTfTokenBeforePip);
+        if (candidateAssociatedActivity != null && (!candidateAssociatedActivity.isEmbedded()
+                || candidateAssociatedActivity.getTaskFragment().fillsParent())) {
+            builder.setOtherActivity(candidateAssociatedActivity);
+        }
+
+        addPendingEvent(builder.build());
     }
 
     void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
@@ -889,11 +915,16 @@
         @Nullable
         private final TaskFragment mTaskFragment;
         @Nullable
+        private final IBinder mTaskFragmentToken;
+        @Nullable
         private final IBinder mErrorCallbackToken;
         @Nullable
         private final Throwable mException;
         @Nullable
         private final ActivityRecord mActivity;
+        // An additional Activity that's needed to send back to the client other than the mActivity.
+        @Nullable
+        private final ActivityRecord mOtherActivity;
         @Nullable
         private final Task mTask;
         // Set when the event is deferred due to the host task is invisible. The defer time will
@@ -905,17 +936,21 @@
         private PendingTaskFragmentEvent(@EventType int eventType,
                 ITaskFragmentOrganizer taskFragmentOrg,
                 @Nullable TaskFragment taskFragment,
+                @Nullable IBinder taskFragmentToken,
                 @Nullable IBinder errorCallbackToken,
                 @Nullable Throwable exception,
                 @Nullable ActivityRecord activity,
+                @Nullable ActivityRecord otherActivity,
                 @Nullable Task task,
                 @TaskFragmentOperation.OperationType int opType) {
             mEventType = eventType;
             mTaskFragmentOrg = taskFragmentOrg;
             mTaskFragment = taskFragment;
+            mTaskFragmentToken = taskFragmentToken;
             mErrorCallbackToken = errorCallbackToken;
             mException = exception;
             mActivity = activity;
+            mOtherActivity = otherActivity;
             mTask = task;
             mOpType = opType;
         }
@@ -943,12 +978,16 @@
             @Nullable
             private TaskFragment mTaskFragment;
             @Nullable
+            private IBinder mTaskFragmentToken;
+            @Nullable
             private IBinder mErrorCallbackToken;
             @Nullable
             private Throwable mException;
             @Nullable
             private ActivityRecord mActivity;
             @Nullable
+            private ActivityRecord mOtherActivity;
+            @Nullable
             private Task mTask;
             @TaskFragmentOperation.OperationType
             private int mOpType;
@@ -963,6 +1002,11 @@
                 return this;
             }
 
+            Builder setTaskFragmentToken(@Nullable IBinder fragmentToken) {
+                mTaskFragmentToken = fragmentToken;
+                return this;
+            }
+
             Builder setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
                 mErrorCallbackToken = errorCallbackToken;
                 return this;
@@ -978,6 +1022,11 @@
                 return this;
             }
 
+            Builder setOtherActivity(@NonNull ActivityRecord otherActivity) {
+                mOtherActivity = otherActivity;
+                return this;
+            }
+
             Builder setTask(@NonNull Task task) {
                 mTask = requireNonNull(task);
                 return this;
@@ -990,7 +1039,8 @@
 
             PendingTaskFragmentEvent build() {
                 return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
-                        mErrorCallbackToken, mException, mActivity, mTask, mOpType);
+                        mTaskFragmentToken, mErrorCallbackToken, mException, mActivity,
+                        mOtherActivity, mTask, mOpType);
             }
         }
     }
@@ -1191,7 +1241,8 @@
                 return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
                         event.mOpType, event.mException);
             case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK:
-                return state.prepareActivityReparentedToTask(event.mActivity);
+                return state.prepareActivityReparentedToTask(event.mActivity, event.mOtherActivity,
+                        event.mTaskFragmentToken);
             default:
                 throw new IllegalArgumentException("Unknown TaskFragmentEvent=" + event.mEventType);
         }
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java
index 5e3bc56..be70421 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodMapTest.java
@@ -44,49 +44,49 @@
     }
 
     @Test
-    public void testEqualsSameObject() {
+    public void testAreSameSameObject() {
         final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
         final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
         final var map = toMap(imi1, imi2);
         assertTrue("Must return true for the same instance",
-                InputMethodMap.equals(map, map));
+                InputMethodMap.areSame(map, map));
     }
 
     @Test
-    public void testEqualsEquivalentObject() {
+    public void testAreSameEquivalentObject() {
         final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
         final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
         assertTrue("Must return true for the equivalent instances",
-                InputMethodMap.equals(toMap(imi1, imi2), toMap(imi1, imi2)));
+                InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi1, imi2)));
 
         assertTrue("Must return true for the equivalent instances",
-                InputMethodMap.equals(toMap(imi1, imi2), toMap(imi2, imi1)));
+                InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi2, imi1)));
     }
 
     @Test
-    public void testEqualsDifferentKeys() {
+    public void testAreSameDifferentKeys() {
         final var imi1 = createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
         final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
         final var imi3 = createFakeInputMethodInfo(TEST_IME_ID3, createFakeSubtypes(3));
         assertFalse("Must return false if keys are different",
-                InputMethodMap.equals(toMap(imi1), toMap(imi1, imi2)));
+                InputMethodMap.areSame(toMap(imi1), toMap(imi1, imi2)));
         assertFalse("Must return false if keys are different",
-                InputMethodMap.equals(toMap(imi1, imi2), toMap(imi1)));
+                InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi1)));
         assertFalse("Must return false if keys are different",
-                InputMethodMap.equals(toMap(imi1, imi2), toMap(imi1, imi3)));
+                InputMethodMap.areSame(toMap(imi1, imi2), toMap(imi1, imi3)));
     }
 
     @Test
-    public void testEqualsDifferentValues() {
+    public void testAreSameDifferentValues() {
         final var imi1_without_subtypes =
                 createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(0));
         final var imi1_with_subtypes =
                 createFakeInputMethodInfo(TEST_IME_ID1, createFakeSubtypes(3));
         final var imi2 = createFakeInputMethodInfo(TEST_IME_ID2, createFakeSubtypes(3));
         assertFalse("Must return false if values are different",
-                InputMethodMap.equals(toMap(imi1_without_subtypes), toMap(imi1_with_subtypes)));
+                InputMethodMap.areSame(toMap(imi1_without_subtypes), toMap(imi1_with_subtypes)));
         assertFalse("Must return false if values are different",
-                InputMethodMap.equals(
+                InputMethodMap.areSame(
                         toMap(imi1_without_subtypes, imi2),
                         toMap(imi1_with_subtypes, imi2)));
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 54b2d4d..8844e6c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -709,6 +709,64 @@
         assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
     }
 
+    @Test
+    public void testCreateVirtualDisplayOwnFocus_checkDisplayDeviceInfo() throws RemoteException {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        // This is effectively the DisplayManager service published to ServiceManager.
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+        final String uniqueId = "uniqueId --- Own Focus Test -- checkDisplayDeviceInfo";
+        float refreshRate = 60.0f;
+        int width = 600;
+        int height = 800;
+        int dpi = 320;
+        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
+
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, width, height, dpi);
+        builder.setFlags(flags);
+        builder.setUniqueId(uniqueId);
+        builder.setRequestedRefreshRate(refreshRate);
+
+        // Create a virtual display in its own display group.
+        final VirtualDisplayConfig ownerDisplayConfig = builder.build();
+        int displayId = bs.createVirtualDisplay(ownerDisplayConfig, /* callback= */ mMockAppToken,
+                /* projection= */ null, PACKAGE_NAME);
+        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
+                nullable(IMediaProjection.class));
+
+        DisplayInfo displayInfo = bs.getDisplayInfo(displayId);
+        assertNotNull(displayInfo);
+        assertTrue((displayInfo.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
+        final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
+                PACKAGE_NAME, Process.myUid(), ownerDisplayConfig);
+        assertEquals(displayInfo.uniqueId, displayUniqueId);
+        assertEquals(displayInfo.name, VIRTUAL_DISPLAY_NAME);
+        assertEquals(displayInfo.ownerPackageName, PACKAGE_NAME);
+        assertEquals(displayInfo.getRefreshRate(), refreshRate, 0.1f);
+
+        performTraversalInternal(displayManager);
+
+        // Flush the handler.
+        displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+        assertNotNull(ddi);
+        assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
+        assertEquals(ddi.width, width);
+        assertEquals(ddi.height, height);
+        assertEquals(ddi.name, displayInfo.name);
+        assertEquals(ddi.ownerPackageName, displayInfo.ownerPackageName);
+        assertEquals(ddi.uniqueId, displayInfo.uniqueId);
+        assertEquals(ddi.renderFrameRate, displayInfo.getRefreshRate(), 0.1f);
+    }
+
     /**
      * Tests that the virtual display is created along-side the default display.
      */
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
index c1f4fee..e88e28b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationStartInfoTest.java
@@ -142,6 +142,7 @@
         final String app1PackageName = "com.android.test.stub1";
         final long appStartTimestampIntentStarted = 1000000;
         final long appStartTimestampActivityLaunchFinished = 2000000;
+        final long appStartTimestampFirstFrameDrawn = 2500000;
         final long appStartTimestampReportFullyDrawn = 3000000;
         final long appStartTimestampService = 4000000;
         final long appStartTimestampBroadcast = 5000000;
@@ -272,6 +273,8 @@
 
         mAppStartInfoTracker.onActivityLaunchFinished(appStartTimestampIntentStarted, COMPONENT,
                 appStartTimestampActivityLaunchFinished, ApplicationStartInfo.LAUNCH_MODE_STANDARD);
+        mAppStartInfoTracker.addTimestampToStart(app1PackageName, app1Uid,
+                appStartTimestampFirstFrameDrawn, ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME);
         list.clear();
         mAppStartInfoTracker.getStartInfo(app1PackageName, app1Uid, app1Pid1, 0, list);
         verifyInProgressRecordsSize(1);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
index 72c0a9e..2cbc226 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
+++ b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS
@@ -1 +1,3 @@
 include /services/core/java/com/android/server/am/OWNERS
+
+per-file ApplicationStartInfoTest.java = yforta@google.com, carmenjackson@google.com, jji@google.com
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index a9ff3a1..4460c6a 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -22,10 +22,12 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
@@ -52,6 +54,7 @@
 import com.android.server.LocalServices;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.power.batterysaver.BatterySaverStateMachine;
+import com.android.server.power.feature.PowerManagerFlags;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import org.junit.Before;
@@ -77,6 +80,9 @@
     @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
     @Mock private Vibrator mVibrator;
     @Mock private StatusBarManagerInternal mStatusBarManagerInternal;
+    @Mock private WakeLockLog mWakeLockLog;
+
+    @Mock private PowerManagerFlags mPowerManagerFlags;
 
     private PowerManagerService mService;
     private Context mContextSpy;
@@ -222,6 +228,7 @@
 
     @Test
     public void testOnWakeLockListener_RemoteException_NoRethrow() {
+        when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
         createNotifier();
 
         IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
@@ -235,6 +242,9 @@
         mNotifier.onWakeLockReleased(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
                 "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
                 exceptingCallback);
+        verifyZeroInteractions(mWakeLockLog);
+        mTestLooper.dispatchAll();
+        verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
         mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
                 "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
                 exceptingCallback);
@@ -244,8 +254,27 @@
                 PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
                 "my.package.name", uid, pid, /* newWorkSource= */ null, /* newHistoryTag= */ null,
                 exceptingCallback);
+        verifyNoMoreInteractions(mWakeLockLog);
         mTestLooper.dispatchAll();
+        verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+                PowerManager.PARTIAL_WAKE_LOCK, 1);
         // If we didn't throw, we're good!
+
+        // Test with improveWakelockLatency flag false, hence the wakelock log will run on the same
+        // thread
+        clearInvocations(mWakeLockLog);
+        when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(false);
+
+        mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+                "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+                exceptingCallback);
+        verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+                PowerManager.PARTIAL_WAKE_LOCK, -1);
+
+        mNotifier.onWakeLockReleased(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+                "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+                exceptingCallback);
+        verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
     }
 
     private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@@ -253,7 +282,7 @@
         Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                 SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
                 FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
-                Executor backgroundExecutor) {
+                Executor backgroundExecutor, PowerManagerFlags powerManagerFlags) {
             return mNotifierMock;
         }
 
@@ -326,6 +355,18 @@
     }
 
     private void createNotifier() {
+        Notifier.Injector injector = new Notifier.Injector() {
+            @Override
+            public long currentTimeMillis() {
+                return 1;
+            }
+
+            @Override
+            public WakeLockLog getWakeLockLog(Context context) {
+                return mWakeLockLog;
+            }
+        };
+
         mNotifier = new Notifier(
                 mTestLooper.getLooper(),
                 mContextSpy,
@@ -335,7 +376,7 @@
                 null,
                 null,
                 null,
-                mTestExecutor);
+                mTestExecutor, mPowerManagerFlags, injector);
     }
 
     private static class FakeExecutor implements Executor {
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 7f165e0..b737e0f 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -114,6 +114,7 @@
 import com.android.server.power.batterysaver.BatterySaverController;
 import com.android.server.power.batterysaver.BatterySaverPolicy;
 import com.android.server.power.batterysaver.BatterySaverStateMachine;
+import com.android.server.power.feature.PowerManagerFlags;
 import com.android.server.testutils.OffsettableClock;
 
 import com.google.testing.junit.testparameterinjector.TestParameter;
@@ -275,7 +276,7 @@
             Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                     SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
                     FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
-                    Executor executor) {
+                    Executor executor, PowerManagerFlags powerManagerFlags) {
                 return mNotifierMock;
             }
 
diff --git a/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java b/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
index 0fad25d..1c4db6a 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/WakeLockLogTest.java
@@ -57,19 +57,42 @@
     }
 
     @Test
+    public void testAddTwoItems_withNoEventTimeSupplied() {
+        final int tagDatabaseSize = 128;
+        final int logSize = 20;
+        TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
+        WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
+        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
+        log.onWakeLockAcquired("TagPartial", 101,
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, -1);
+
+        when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
+        log.onWakeLockAcquired("TagFull", 102,
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, -1);
+
+        assertEquals("Wake Lock Log\n"
+                        + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
+                        + "(partial,on-after-release)\n"
+                        + "  01-01 00:00:01.150 - 102 (some.package2) - ACQ TagFull "
+                        + "(full,acq-causes-wake)\n"
+                        + "  -\n"
+                        + "  Events: 2, Time-Resets: 0\n"
+                        + "  Buffer, Bytes used: 6\n",
+                dumpLog(log, false));
+    }
+
+    @Test
     public void testAddTwoItems() {
         final int tagDatabaseSize = 128;
         final int logSize = 20;
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("TagPartial", 101,
-                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
         log.onWakeLockAcquired("TagFull", 102,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1150L);
 
         assertEquals("Wake Lock Log\n"
                 + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
@@ -89,11 +112,9 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
-        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1350L);
-        log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK, 1350L);
 
         assertEquals("Wake Lock Log\n"
                 + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial (partial)\n"
@@ -111,11 +132,9 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
-        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
-        log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK, 1150L);
 
         assertEquals("Wake Lock Log\n"
                 + "  01-01 00:00:01.000 - --- - ACQ UNKNOWN (partial)\n"
@@ -134,41 +153,33 @@
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
         // Wake lock 1 acquired - log size = 3
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
-        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagPartial", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
 
         // Wake lock 2 acquired - log size = 3 + 3 = 6
-        when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
-        log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagFull", 102, PowerManager.FULL_WAKE_LOCK, 1150L);
 
         // Wake lock 3 acquired - log size = 6 + 3 = 9
-        when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
-        log.onWakeLockAcquired("TagThree", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagThree", 101, PowerManager.PARTIAL_WAKE_LOCK, 1151L);
 
         // We need more space - wake lock 1 acquisition is removed from the log and saved in the
         // list. Log size = 9 - 3 + 2 = 8
-        when(injectorSpy.currentTimeMillis()).thenReturn(1152L);
-        log.onWakeLockReleased("TagThree", 101);
+        log.onWakeLockReleased("TagThree", 101, 1152L);
 
         // We need more space - wake lock 2 acquisition is removed from the log and saved in the
         // list. Log size = 8 - 3 + 2 = 7
-        when(injectorSpy.currentTimeMillis()).thenReturn(1153L);
-        log.onWakeLockReleased("TagPartial", 101);
+        log.onWakeLockReleased("TagPartial", 101, 1153L);
 
         // We need more space - wake lock 3 acquisition is removed from the log and saved in the
         // list. Log size = 7 - 3 + 3 = 7
-        when(injectorSpy.currentTimeMillis()).thenReturn(1154L);
-        log.onWakeLockAcquired("TagFour", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagFour", 101, PowerManager.PARTIAL_WAKE_LOCK, 1154L);
 
         // We need more space - wake lock 3 release is removed from the log and wake lock 3
         // acquisition is removed from the list. Log size = 7 - 2 + 3 = 8
-        when(injectorSpy.currentTimeMillis()).thenReturn(1155L);
-        log.onWakeLockAcquired("TagFive", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("TagFive", 101, PowerManager.PARTIAL_WAKE_LOCK, 1155L);
 
         // We need more space - wake lock 1 release is removed from the log and wake lock 1
         // acquisition is removed from the list. Log size = 8 - 2 + 2 = 8
-        when(injectorSpy.currentTimeMillis()).thenReturn(1156L);
-        log.onWakeLockReleased("TagFull", 102);
+        log.onWakeLockReleased("TagFull", 102, 1156L);
 
         // Wake lock 2 acquisition is still printed because its release have not rolled off the log
         // yet.
@@ -191,8 +202,8 @@
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
         // Bad tag means it wont get written
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
-        log.onWakeLockAcquired(null /* tag */, 0 /* ownerUid */, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired(
+                null /* tag */, 0 /* ownerUid */, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
 
         assertEquals("Wake Lock Log\n"
                 + "  -\n"
@@ -208,9 +219,8 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("*job*/com.one.two.3hree/.one..Last", 101,
-                PowerManager.PARTIAL_WAKE_LOCK);
+                PowerManager.PARTIAL_WAKE_LOCK, 1000L);
 
         assertEquals("Wake Lock Log\n"
                 + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ "
@@ -228,10 +238,8 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
-        log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK);
-        when(injectorSpy.currentTimeMillis()).thenReturn(1001L);
-        log.onWakeLockReleased("HowdyTag", 101);
+        log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK, 1000L);
+        log.onWakeLockReleased("HowdyTag", 101, 1001L);
 
         assertEquals("Wake Lock Log\n"
                 + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ HowdyTag (partial)\n"
@@ -250,12 +258,10 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1100L);
-        log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK);
+        log.onWakeLockAcquired("HowdyTag", 101, PowerManager.PARTIAL_WAKE_LOCK, 1100L);
 
         // New element goes back in time...should not be written to log.
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
-        log.onWakeLockReleased("HowdyTag", 101);
+        log.onWakeLockReleased("HowdyTag", 101, 1000L);
 
         assertEquals("Wake Lock Log\n"
                 + "  01-01 00:00:01.100 - 101 (some.package1) - ACQ HowdyTag (partial)\n"
@@ -272,9 +278,8 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("TagPartial", 101,
-                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.SYSTEM_WAKELOCK);
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.SYSTEM_WAKELOCK, 1000L);
 
         assertEquals("Wake Lock Log\n"
                         + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
@@ -293,9 +298,8 @@
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
         when(mPackageManager.getPackagesForUid(101)).thenReturn(null);
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("TagPartial", 101,
-                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
 
         assertEquals("Wake Lock Log\n"
                         + "  01-01 00:00:01.000 - 101 - ACQ TagPartial "
@@ -316,9 +320,8 @@
         when(mPackageManager.getPackagesForUid(101)).thenReturn(
                 new String[]{ "some.package1", "some.package2", "some.package3" });
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("TagPartial", 101,
-                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
 
         assertEquals("Wake Lock Log\n"
                         + "  01-01 00:00:01.000 - 101 (some.package1,...) - ACQ TagPartial "
@@ -336,17 +339,14 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("TagPartial", 101,
-                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
         log.onWakeLockAcquired("TagFull", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1150L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
         log.onWakeLockAcquired("TagFull2", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1151L);
 
         assertEquals("Wake Lock Log\n"
                         + "  01-01 00:00:01.000 - 101 (some.package1) - ACQ TagPartial "
@@ -370,29 +370,23 @@
         TestInjector injectorSpy = spy(new TestInjector(tagDatabaseSize, logSize));
         WakeLockLog log = new WakeLockLog(injectorSpy, mContext);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1000L);
         log.onWakeLockAcquired("TagPartial", 101,
-                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE);
+                PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, 1000L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1150L);
         log.onWakeLockAcquired("TagFull", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1150L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1151L);
         log.onWakeLockAcquired("TagFull2", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1151L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1152L);
         log.onWakeLockAcquired("TagFull3", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1152L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1153L);
         log.onWakeLockAcquired("TagFull4", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1153L);
 
-        when(injectorSpy.currentTimeMillis()).thenReturn(1154L);
         log.onWakeLockAcquired("TagFull5", 101,
-                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP);
+                PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, 1154L);
 
         // The first 3 events have been removed from the log and they exist in the saved
         // acquisitions list. They should also use the cache when fetching the package names.
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index cb4fc75..ca15aa2 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -30,7 +30,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -42,6 +44,7 @@
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -102,6 +105,7 @@
 import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.accessibility.util.ShortcutUtils;
 import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.content.PackageMonitor;
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
@@ -1620,6 +1624,67 @@
                 .containsExactlyElementsIn(Set.of(daltonizerTile));
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
+    public void onHandleForceStop_dontDoIt_packageEnabled_returnsTrue() {
+        setupShortcutTargetServices();
+        AccessibilityUserState userState = mA11yms.getCurrentUserState();
+        userState.mEnabledServices.addAll(
+                userState.mInstalledServices.stream().map(
+                        (AccessibilityServiceInfo::getComponentName)).toList());
+        String[] packages = userState.mEnabledServices.stream().map(
+                ComponentName::getPackageName).toList().toArray(new String[0]);
+
+        PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
+        when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        mA11yms.setPackageMonitor(monitor);
+
+        assertTrue(mA11yms.getPackageMonitor().onHandleForceStop(
+                new Intent(),
+                packages,
+                UserHandle.USER_SYSTEM,
+                false
+        ));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
+    public void onHandleForceStop_doIt_packageEnabled_returnsFalse() {
+        setupShortcutTargetServices();
+        AccessibilityUserState userState = mA11yms.getCurrentUserState();
+        userState.mEnabledServices.addAll(
+                userState.mInstalledServices.stream().map(
+                        (AccessibilityServiceInfo::getComponentName)).toList());
+        String[] packages = userState.mEnabledServices.stream().map(
+                ComponentName::getPackageName).toList().toArray(new String[0]);
+
+        PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
+        when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        mA11yms.setPackageMonitor(monitor);
+
+        assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
+                new Intent(),
+                packages,
+                UserHandle.USER_SYSTEM,
+                true
+        ));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
+    public void onHandleForceStop_dontDoIt_packageNotEnabled_returnsFalse() {
+        PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
+        when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        mA11yms.setPackageMonitor(monitor);
+
+        assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
+                new Intent(),
+                new String[]{ "FOO", "BAR"},
+                UserHandle.USER_SYSTEM,
+                false
+        ));
+    }
+
     private static AccessibilityServiceInfo mockAccessibilityServiceInfo(
             ComponentName componentName) {
         return mockAccessibilityServiceInfo(
@@ -1630,7 +1695,7 @@
             ComponentName componentName,
             boolean isSystemApp, boolean isAlwaysOnService) {
         AccessibilityServiceInfo accessibilityServiceInfo =
-                Mockito.spy(new AccessibilityServiceInfo());
+                spy(new AccessibilityServiceInfo());
         accessibilityServiceInfo.setComponentName(componentName);
         ResolveInfo mockResolveInfo = Mockito.mock(ResolveInfo.class);
         when(accessibilityServiceInfo.getResolveInfo()).thenReturn(mockResolveInfo);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index 5787780..37e0818 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -24,8 +24,6 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
@@ -252,7 +250,6 @@
                 case ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN:
                 case ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN:
                 case ActivityOptions.KEY_TRANSIENT_LAUNCH:
-                case ActivityOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED:
                 case "android:activity.animationFinishedListener":
                     // KEY_ANIMATION_FINISHED_LISTENER
                 case "android:activity.animSpecs": // KEY_ANIM_SPECS
@@ -322,7 +319,7 @@
             Log.e("ActivityOptionsTests", "Unknown key " + key + " is found. "
                     + "Please review if the given bundle should be protected with permissions.");
         }
-        assertThat(unknownKeys).isEmpty();
+        assertTrue(unknownKeys.isEmpty());
     }
 
     public static class TrampolineActivity extends Activity {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 6b17de4..c7f5020 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -908,6 +908,24 @@
     }
 
     @Test
+    public void testOverrideOrientationIfNeeded_fullscreenOverride_cameraActivity_unchanged() {
+        doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled();
+        doReturn(true).when(mLetterboxConfiguration)
+                .isCameraCompatTreatmentEnabledAtBuildTime();
+
+        // Recreate DisplayContent with DisplayRotationCompatPolicy
+        mActivity = setUpActivityWithComponent();
+        mController = new LetterboxUiController(mWm, mActivity);
+        spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
+
+        doReturn(false).when(mDisplayContent.mDisplayRotationCompatPolicy)
+                .isCameraActive(mActivity, /* mustBeFullscreen= */ true);
+
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, mController.overrideOrientationIfNeeded(
+                /* candidate */ SCREEN_ORIENTATION_PORTRAIT));
+    }
+
+    @Test
     public void testOverrideOrientationIfNeeded_respectOrientationRequestOverUserFullScreen() {
         spyOn(mController);
         doReturn(true).when(mController).shouldApplyUserFullscreenOverride();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index a90a158..d57a7e6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -961,6 +962,22 @@
         assertEquals(appLeftTop, task.getDisplayContent().mFocusedApp);
     }
 
+    @Test
+    public void testShouldBeVisible_invisibleForEmptyTaskFragment() {
+        final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true)
+                .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build();
+        final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+                .setParentTask(task)
+                .build();
+
+        // Empty taskFragment should be invisible
+        assertFalse(taskFragment.shouldBeVisible(null));
+
+        // Should be invisible even if it is ACTIVITY_TYPE_HOME.
+        when(taskFragment.getActivityType()).thenReturn(ACTIVITY_TYPE_HOME);
+        assertFalse(taskFragment.shouldBeVisible(null));
+    }
+
     private WindowState createAppWindow(ActivityRecord app, String name) {
         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, app, name,
                 0 /* ownerId */, false /* ownerCanAddInternalSystemWindow */, new TestIWindow());