Merge changes from topic "notif_force_group" into main

* changes:
  Notification API hardening: add FLAG_SILENT
  Notification API hardening: forced auto-grouping
diff --git a/core/api/current.txt b/core/api/current.txt
index 8e4de7a..46f426b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12494,6 +12494,7 @@
     method @FlaggedApi("android.os.allow_private_profile") @Nullable @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public final android.content.pm.LauncherUserInfo getLauncherUserInfo(@NonNull android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method @FlaggedApi("android.os.allow_private_profile") @NonNull @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public java.util.List<java.lang.String> getPreInstalledSystemPackages(@NonNull android.os.UserHandle);
+    method @FlaggedApi("android.os.get_private_space_settings") @Nullable @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public android.content.IntentSender getPrivateSpaceSettingsIntent();
     method @RequiresPermission(conditional=true, anyOf={"android.permission.ACCESS_HIDDEN_PROFILES_FULL", android.Manifest.permission.ACCESS_HIDDEN_PROFILES}) public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method @Nullable public android.content.IntentSender getShortcutConfigActivityIntent(@NonNull android.content.pm.LauncherActivityInfo);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e4a8407..7ae5d1b 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -674,7 +674,7 @@
     method @Nullable public String getCurrentWebViewPackageName();
     method @FlaggedApi("android.webkit.update_service_v2") @NonNull public android.webkit.WebViewProviderInfo getDefaultWebViewPackage();
     method @Nullable public static android.webkit.WebViewUpdateManager getInstance();
-    method @NonNull public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
+    method @NonNull @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.QUERY_ALL_PACKAGES}) public android.webkit.WebViewProviderInfo[] getValidWebViewPackages();
     method @NonNull public android.webkit.WebViewProviderResponse waitForAndGetProvider();
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index b7de93a..099dbbc 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2775,12 +2775,6 @@
 
   @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class ParsedVibration {
     ctor public ParsedVibration(@NonNull java.util.List<android.os.VibrationEffect>);
-    method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @Nullable public android.os.VibrationEffect resolve(@NonNull android.os.Vibrator);
-  }
-
-  @FlaggedApi("android.os.vibrator.vibration_xml_apis") public final class VibrationXmlParser {
-    method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.vibrator.persistence.ParsedVibration parse(@NonNull java.io.InputStream) throws java.io.IOException;
-    method @FlaggedApi("android.os.vibrator.vibration_xml_apis") @NonNull public static android.os.VibrationEffect parseVibrationEffect(@NonNull java.io.InputStream) throws java.io.IOException;
   }
 
   public static final class VibrationXmlParser.ParseFailedException extends java.io.IOException {
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index ef8501f..aca9bb4 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -297,6 +297,12 @@
     public boolean isTopActivityTransparent;
 
     /**
+     * Whether the top activity has specified style floating.
+     * @hide
+     */
+    public boolean isTopActivityStyleFloating;
+
+    /**
      * Encapsulate specific App Compat information.
      * @hide
      */
@@ -429,6 +435,7 @@
                 && parentTaskId == that.parentTaskId
                 && Objects.equals(topActivity, that.topActivity)
                 && isTopActivityTransparent == that.isTopActivityTransparent
+                && isTopActivityStyleFloating == that.isTopActivityStyleFloating
                 && appCompatTaskInfo.equalsForTaskOrganizer(that.appCompatTaskInfo);
     }
 
@@ -498,6 +505,7 @@
         mTopActivityLocusId = source.readTypedObject(LocusId.CREATOR);
         displayAreaFeatureId = source.readInt();
         isTopActivityTransparent = source.readBoolean();
+        isTopActivityStyleFloating = source.readBoolean();
         appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR);
     }
 
@@ -545,6 +553,7 @@
         dest.writeTypedObject(mTopActivityLocusId, flags);
         dest.writeInt(displayAreaFeatureId);
         dest.writeBoolean(isTopActivityTransparent);
+        dest.writeBoolean(isTopActivityStyleFloating);
         dest.writeTypedObject(appCompatTaskInfo, flags);
     }
 
@@ -582,6 +591,7 @@
                 + " locusId=" + mTopActivityLocusId
                 + " displayAreaFeatureId=" + displayAreaFeatureId
                 + " isTopActivityTransparent=" + isTopActivityTransparent
+                + " isTopActivityStyleFloating=" + isTopActivityStyleFloating
                 + " appCompatTaskInfo=" + appCompatTaskInfo
                 + "}";
     }
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index df27f9d..52c84dc 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -935,12 +935,11 @@
      *
      * @return {@link IntentSender} object which launches the Private Space Settings Activity, if
      * successful, null otherwise.
-     * @hide
      */
     // Alternatively, a system app can access this api for private profile if they've been granted
     // with the {@code android.Manifest.permission#ACCESS_HIDDEN_PROFILES_FULL} permission.
     @Nullable
-    @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+    @FlaggedApi(Flags.FLAG_GET_PRIVATE_SPACE_SETTINGS)
     @RequiresPermission(conditional = true,
             anyOf = {ACCESS_HIDDEN_PROFILES_FULL, ACCESS_HIDDEN_PROFILES})
     public IntentSender getPrivateSpaceSettingsIntent() {
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 124d07f..c7d94c6 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -151,6 +151,16 @@
 }
 
 flag {
+    name: "fix_get_user_property_cache"
+    namespace: "multiuser"
+    description: "Cache is not optimised for getUserProperty for values below 0, eg. UserHandler.USER_NULL or UserHandle.USER_ALL"
+    bug: "350416200"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
     name: "cache_quiet_mode_state"
     namespace: "multiuser"
     description: "Optimise quiet mode state retrieval"
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 5012a79..7353d76 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -26,6 +26,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * @hide
@@ -370,6 +371,20 @@
         return isEqual;
     }
 
+    @Override
+    public int hashCode() {
+        if (!Flags.fixApiCheck()) {
+            return super.hashCode();
+        }
+
+        return Objects.hash(mId, mName, mVendor, mToolchain, mToolchainVersion,
+                getStaticSwVersion(), mChrePlatformId, mPeakMips,
+                mStoppedPowerDrawMw, mSleepPowerDrawMw, mPeakPowerDrawMw,
+                mMaxPacketLengthBytes, mSupportsReliableMessages,
+                Arrays.hashCode(mSupportedSensors),
+                Arrays.hashCode(mMemoryRegions));
+    }
+
     private ContextHubInfo(Parcel in) {
         mId = in.readInt();
         mName = in.readString();
diff --git a/core/java/android/hardware/location/ContextHubIntentEvent.java b/core/java/android/hardware/location/ContextHubIntentEvent.java
index 06c5334..002c683 100644
--- a/core/java/android/hardware/location/ContextHubIntentEvent.java
+++ b/core/java/android/hardware/location/ContextHubIntentEvent.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.PendingIntent;
+import android.chre.flags.Flags;
 import android.content.Intent;
 
 import java.util.Objects;
@@ -275,6 +276,16 @@
         return isEqual;
     }
 
+    @Override
+    public int hashCode() {
+        if (!Flags.fixApiCheck()) {
+            return super.hashCode();
+        }
+
+        return Objects.hash(mEventType, mContextHubInfo, mNanoAppId,
+                mNanoAppMessage, mNanoAppAbortCode, mClientAuthorizationState);
+    }
+
     private static void hasExtraOrThrow(Intent intent, String extra) {
         if (!intent.hasExtra(extra)) {
             throw new IllegalArgumentException("Intent did not have extra: " + extra);
diff --git a/core/java/android/hardware/location/MemoryRegion.java b/core/java/android/hardware/location/MemoryRegion.java
index c033228..d95894f 100644
--- a/core/java/android/hardware/location/MemoryRegion.java
+++ b/core/java/android/hardware/location/MemoryRegion.java
@@ -19,9 +19,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.chre.flags.Flags;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /**
  * @hide
  */
@@ -128,6 +131,16 @@
     }
 
     @Override
+    public int hashCode() {
+        if (!Flags.fixApiCheck()) {
+            return super.hashCode();
+        }
+
+        return Objects.hash(mSizeBytes, mSizeBytesFree, mIsReadable,
+                mIsWritable, mIsExecutable);
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/hardware/location/NanoAppMessage.java b/core/java/android/hardware/location/NanoAppMessage.java
index 905caf0..85a5d45 100644
--- a/core/java/android/hardware/location/NanoAppMessage.java
+++ b/core/java/android/hardware/location/NanoAppMessage.java
@@ -26,6 +26,7 @@
 import libcore.util.HexEncoding;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * A class describing messages send to or from nanoapps through the Context Hub Service.
@@ -273,4 +274,15 @@
 
         return isEqual;
     }
+
+    @Override
+    public int hashCode() {
+        if (!Flags.fixApiCheck()) {
+            return super.hashCode();
+        }
+
+        return Objects.hash(mNanoAppId, mMessageType, mIsBroadcasted,
+                Arrays.hashCode(mMessageBody), mIsReliable,
+                mMessageSequenceNumber);
+    }
 }
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 6458534..f026997 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -216,3 +216,11 @@
     description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead"
     bug: "324046728"
 }
+
+flag {
+    name: "get_private_space_settings"
+    namespace: "profile_experiences"
+    description: "Guards a new Private Profile API in LauncherApps"
+    bug: "346294653"
+    is_exported: true
+}
diff --git a/core/java/android/os/vibrator/persistence/ParsedVibration.java b/core/java/android/os/vibrator/persistence/ParsedVibration.java
index 74d3a7b..1916269 100644
--- a/core/java/android/os/vibrator/persistence/ParsedVibration.java
+++ b/core/java/android/os/vibrator/persistence/ParsedVibration.java
@@ -38,7 +38,6 @@
  *
  * @hide
  */
-@TestApi // This was used in CTS before the flag was introduced.
 @SystemApi
 @FlaggedApi(FLAG_VIBRATION_XML_APIS)
 public final class ParsedVibration {
@@ -62,7 +61,6 @@
      *
      * @hide
      */
-    @TestApi // This was used in CTS before the flag was introduced.
     @SystemApi
     @FlaggedApi(FLAG_VIBRATION_XML_APIS)
     @Nullable
diff --git a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
index e2312e0..7d9624c 100644
--- a/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
+++ b/core/java/android/os/vibrator/persistence/VibrationXmlParser.java
@@ -121,7 +121,6 @@
  *
  * @hide
  */
-@TestApi // This was used in CTS before the flag was introduced.
 @SystemApi
 @FlaggedApi(FLAG_VIBRATION_XML_APIS)
 public final class VibrationXmlParser {
@@ -195,7 +194,6 @@
      *
      * @hide
      */
-    @TestApi // Replacing test APIs used in CTS before the flagged system APIs was introduced.
     @SystemApi
     @FlaggedApi(FLAG_VIBRATION_XML_APIS)
     @NonNull
@@ -217,7 +215,6 @@
      *
      * @hide
      */
-    @TestApi // Replacing test APIs used in CTS before the flagged system APIs was introduced.
     @SystemApi
     @FlaggedApi(FLAG_VIBRATION_XML_APIS)
     @NonNull
diff --git a/core/java/android/view/ViewTraversalTracingStrings.java b/core/java/android/view/ViewTraversalTracingStrings.java
index 7dde87b..e95205b 100644
--- a/core/java/android/view/ViewTraversalTracingStrings.java
+++ b/core/java/android/view/ViewTraversalTracingStrings.java
@@ -58,6 +58,6 @@
         out.append(" ");
         out.append(className);
         v.appendId(out);
-        return out.substring(0, Math.min(out.length() - 1, Trace.MAX_SECTION_NAME_LEN - 1));
+        return out.substring(0, Math.min(out.length(), Trace.MAX_SECTION_NAME_LEN));
     }
 }
diff --git a/core/java/android/webkit/WebViewUpdateManager.java b/core/java/android/webkit/WebViewUpdateManager.java
index 07576a2..dd48df9 100644
--- a/core/java/android/webkit/WebViewUpdateManager.java
+++ b/core/java/android/webkit/WebViewUpdateManager.java
@@ -101,6 +101,8 @@
      * enabled for all users.
      */
     @SuppressLint({"ParcelableList", "ArrayReturn"})
+    @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS,
+            android.Manifest.permission.QUERY_ALL_PACKAGES})
     public @NonNull WebViewProviderInfo[] getValidWebViewPackages() {
         try {
             return mService.getValidWebViewPackages();
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 5b99ff9..cc880e1 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -113,4 +113,12 @@
     namespace: "large_screen_experiences_app_compat"
     description: "Enables sysui animation for user aspect ratio button"
     bug: "300357441"
+}
+
+flag {
+  name: "app_compat_ui_framework"
+  namespace: "large_screen_experiences_app_compat"
+  description: "Whether the declarative compat UI framework is enabled"
+  bug: "270361630"
+  is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
index 8f7fdd6..61ec49c 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
@@ -35,7 +35,8 @@
     private val shouldOverrideByDevOption: Boolean
 ) {
   // All desktop mode related flags will be added here
-  DESKTOP_WINDOWING_MODE(DesktopModeStatus::isDesktopModeFlagEnabled, true);
+  DESKTOP_WINDOWING_MODE(DesktopModeStatus::isDesktopModeFlagEnabled, true),
+  WALLPAPER_ACTIVITY(Flags::enableDesktopWindowingWallpaperActivity, true);
 
   // Local cache for toggle override, which is initialized once on its first access. It needs to be
   // refreshed only on reboots as overridden state takes effect on reboots.
@@ -52,10 +53,14 @@
           context.contentResolver == null) {
         flagFunction()
       } else {
+        val shouldToggleBeEnabledByDefault = DesktopModeStatus.shouldDevOptionBeEnabledByDefault()
         when (getToggleOverride(context)) {
           ToggleOverride.OVERRIDE_UNSET -> flagFunction()
-          ToggleOverride.OVERRIDE_OFF -> false
-          ToggleOverride.OVERRIDE_ON -> true
+          // When toggle override matches its default state, don't override flags. This helps users
+          // reset their feature overrides.
+          ToggleOverride.OVERRIDE_OFF ->
+              if (shouldToggleBeEnabledByDefault) false else flagFunction()
+          ToggleOverride.OVERRIDE_ON -> if (shouldToggleBeEnabledByDefault) flagFunction() else true
         }
       }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt
index 6781d08..d1b2347 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/AppCompatUtils.kt
@@ -19,6 +19,16 @@
 package com.android.wm.shell.compatui
 
 import android.app.TaskInfo
-fun isSingleTopActivityTranslucent(task: TaskInfo) =
-    task.isTopActivityTransparent && task.numActivities == 1
+import android.content.Context
+import com.android.internal.R
 
+// TODO(b/347289970): Consider replacing with API
+fun isTopActivityExemptFromDesktopWindowing(context: Context, task: TaskInfo) =
+    isSystemUiTask(context, task) || (task.isTopActivityTransparent && task.numActivities == 1
+            && !task.isTopActivityStyleFloating)
+
+private fun isSystemUiTask(context: Context, task: TaskInfo): Boolean {
+    val sysUiPackageName: String =
+        context.resources.getString(R.string.config_systemUi)
+    return task.baseActivity?.packageName == sysUiPackageName
+}
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 4868a2f..e247912 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
@@ -66,7 +66,7 @@
 import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
 import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
 import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
-import com.android.wm.shell.compatui.isSingleTopActivityTranslucent
+import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
 import com.android.wm.shell.draganddrop.DragAndDropController
@@ -158,8 +158,6 @@
                 visualIndicator = null
             }
         }
-    private val sysUIPackageName = context.resources.getString(
-        com.android.internal.R.string.config_systemUi)
 
     private val transitionAreaHeight
         get() =
@@ -219,11 +217,6 @@
         return visualIndicator
     }
 
-    // TODO(b/347289970): Consider replacing with API
-    private fun isSystemUIApplication(taskInfo: RunningTaskInfo): Boolean {
-        return taskInfo.baseActivity?.packageName == sysUIPackageName
-    }
-
     fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) {
         toggleResizeDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener)
         enterDesktopTaskTransitionHandler.setOnTaskResizeAnimationListener(listener)
@@ -351,19 +344,12 @@
         wct: WindowContainerTransaction = WindowContainerTransaction(),
         transitionSource: DesktopModeTransitionSource,
     ) {
-        if (Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)) {
+        if (Flags.enableDesktopWindowingModalsPolicy()
+            && isTopActivityExemptFromDesktopWindowing(context, task)) {
             KtProtoLog.w(
                 WM_SHELL_DESKTOP_MODE,
                 "DesktopTasksController: Cannot enter desktop, " +
-                    "translucent top activity found. This is likely a modal dialog."
-            )
-            return
-        }
-        if (isSystemUIApplication(task)) {
-            KtProtoLog.w(
-                WM_SHELL_DESKTOP_MODE,
-                "DesktopTasksController: Cannot enter desktop, " +
-                        "systemUI top activity found."
+                        "ineligible top activity found."
             )
             return
         }
@@ -942,10 +928,8 @@
                 when {
                     // Check if the closing task needs to be handled
                     TransitionUtil.isClosingType(request.type) -> handleTaskClosing(task)
-                    // Check if the task has a top transparent activity
-                    shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task)
-                    // Check if the task has a top systemUI activity
-                    isSystemUIApplication(task) -> handleIncompatibleTaskLaunch(task)
+                    // Check if the top task shouldn't be allowed to enter desktop mode
+                    isIncompatibleTask(task) -> handleIncompatibleTaskLaunch(task)
                     // Check if fullscreen task should be updated
                     task.isFullscreen -> handleFullscreenTaskLaunch(task, transition)
                     // Check if freeform task should be updated
@@ -979,9 +963,9 @@
             .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) }
     }
 
-    // TODO(b/347289970): Consider replacing with API
-    private fun shouldLaunchAsModal(task: TaskInfo) =
-        Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)
+    private fun isIncompatibleTask(task: TaskInfo) =
+        Flags.enableDesktopWindowingModalsPolicy()
+                && isTopActivityExemptFromDesktopWindowing(context, task)
 
     private fun shouldHandleTaskClosing(request: TransitionRequestInfo): Boolean {
         return Flags.enableDesktopWindowingWallpaperActivity() &&
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index bd25846..21307a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -77,6 +77,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
+import com.android.window.flags.Flags;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
@@ -579,6 +580,14 @@
         final boolean isOpening = isOpeningType(transitType);
         final boolean isClosing = isClosingType(transitType);
         final int mode = change.getMode();
+        // Ensure wallpapers stay in the back
+        if (change.hasFlags(FLAG_IS_WALLPAPER) && Flags.ensureWallpaperInTransitions()) {
+            if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+                return -zSplitLine + numChanges - i;
+            } else {
+                return -zSplitLine - i;
+            }
+        }
         // Put all the OPEN/SHOW on top
         if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
             if (isOpening) {
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 e3aa31f..440fc4d 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
@@ -32,7 +32,7 @@
 
 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.compatui.AppCompatUtils.isSingleTopActivityTranslucent;
+import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing;
 import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -105,7 +105,6 @@
 import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
 
 import java.io.PrintWriter;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Supplier;
 
@@ -1034,12 +1033,8 @@
                 && taskInfo.isFocused) {
             return false;
         }
-        // TODO(b/347289970): Consider replacing with API
         if (Flags.enableDesktopWindowingModalsPolicy()
-                && isSingleTopActivityTranslucent(taskInfo)) {
-            return false;
-        }
-        if (isSystemUIApplication(taskInfo)) {
+                && isTopActivityExemptFromDesktopWindowing(mContext, taskInfo)) {
             return false;
         }
         return DesktopModeStatus.canEnterDesktopMode(mContext)
@@ -1118,14 +1113,6 @@
                 && mSplitScreenController.isTaskInSplitScreen(taskId);
     }
 
-    // TODO(b/347289970): Consider replacing with API
-    private boolean isSystemUIApplication(RunningTaskInfo taskInfo) {
-        if (taskInfo.baseActivity != null) {
-            return (Objects.equals(taskInfo.baseActivity.getPackageName(), mSysUIPackageName));
-        }
-        return false;
-    }
-
     private void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + "DesktopModeWindowDecorViewModel");
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index a0a61fe2..d0e8215 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -117,12 +117,10 @@
 
     /**
      * Checks that all parts of the screen are covered at the start and end of the transition
-     *
-     * TODO b/197726599 Prevents all states from being checked
      */
     @Presubmit
     @Test
-    fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered(allStates = false)
+    fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered()
 
     /** Checks [pipApp] window remains visible and on top throughout the transition */
     @Presubmit
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
index 4cd2a36..ecaf970 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/AppCompatUtilsTest.kt
@@ -16,8 +16,10 @@
 
 package com.android.wm.shell.compatui
 
+import android.content.ComponentName
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.internal.R
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
 import org.junit.Assert.assertFalse
@@ -34,26 +36,55 @@
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
 class AppCompatUtilsTest : ShellTestCase() {
-
     @Test
-    fun testIsSingleTopActivityTranslucent() {
-        assertTrue(isSingleTopActivityTranslucent(
+    fun testIsTopActivityExemptFromDesktopWindowing_topActivityTransparent() {
+        assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
             createFreeformTask(/* displayId */ 0)
                     .apply {
                         isTopActivityTransparent = true
                         numActivities = 1
                     }))
-        assertFalse(isSingleTopActivityTranslucent(
+        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
             createFreeformTask(/* displayId */ 0)
                     .apply {
                         isTopActivityTransparent = true
                         numActivities = 0
                     }))
-        assertFalse(isSingleTopActivityTranslucent(
+    }
+
+    @Test
+    fun testIsTopActivityExemptFromDesktopWindowing_singleTopActivity() {
+        assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
+            createFreeformTask(/* displayId */ 0)
+                    .apply {
+                        isTopActivityTransparent = true
+                        numActivities = 1
+                    }))
+        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
             createFreeformTask(/* displayId */ 0)
                     .apply {
                         isTopActivityTransparent = false
                         numActivities = 1
                     }))
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testIsTopActivityExemptFromDesktopWindowing__topActivityStyleFloating() {
+        assertFalse(isTopActivityExemptFromDesktopWindowing(mContext,
+            createFreeformTask(/* displayId */ 0)
+                    .apply {
+                        isTopActivityStyleFloating = true
+                    }))
+    }
+
+    @Test
+    fun testIsTopActivityExemptFromDesktopWindowing_systemUiTask() {
+        val systemUIPackageName = context.resources.getString(R.string.config_systemUi)
+        val baseComponent = ComponentName(systemUIPackageName, /* class */ "")
+        assertTrue(isTopActivityExemptFromDesktopWindowing(mContext,
+            createFreeformTask(/* displayId */ 0)
+                    .apply {
+                        baseActivity = baseComponent
+                    }))
+    }
+}
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 8c7de5c..bd38d36 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
@@ -700,19 +700,37 @@
   }
 
   @Test
-  fun moveToDesktop_topActivityTranslucent_doesNothing() {
-    setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+  fun moveToDesktop_topActivityTranslucentWithStyleFloating_taskIsMovedToDesktop() {
     val task =
-        setUpFullscreenTask().apply {
-          isTopActivityTransparent = true
-          numActivities = 1
-        }
+      setUpFullscreenTask().apply {
+        isTopActivityTransparent = true
+        isTopActivityStyleFloating = true
+        numActivities = 1
+      }
+
+    controller.moveToDesktop(task, transitionSource = UNKNOWN)
+
+    val wct = getLatestEnterDesktopWct()
+    assertThat(wct.changes[task.token.asBinder()]?.windowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+  }
+
+  @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+  fun moveToDesktop_topActivityTranslucentWithoutStyleFloating_doesNothing() {
+    val task =
+      setUpFullscreenTask().apply {
+        isTopActivityTransparent = true
+        isTopActivityStyleFloating = false
+        numActivities = 1
+      }
 
     controller.moveToDesktop(task, transitionSource = UNKNOWN)
     verifyEnterDesktopWCTNotExecuted()
   }
 
   @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
   fun moveToDesktop_systemUIActivity_doesNothing() {
     val task = setUpFullscreenTask()
 
@@ -1374,20 +1392,40 @@
   }
 
   @Test
-  fun handleRequest_shouldLaunchAsModal_returnSwitchToFullscreenWCT() {
-    setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+  fun handleRequest_topActivityTransparentWithStyleFloating_returnSwitchToFreeformWCT() {
+    val freeformTask = setUpFreeformTask()
+    markTaskVisible(freeformTask)
+
     val task =
-        setUpFreeformTask().apply {
-          isTopActivityTransparent = true
-          numActivities = 1
-        }
+      setUpFullscreenTask().apply {
+        isTopActivityTransparent = true
+        isTopActivityStyleFloating = true
+        numActivities = 1
+      }
 
     val result = controller.handleRequest(Binder(), createTransition(task))
     assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
-        .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+            .isEqualTo(WINDOWING_MODE_FREEFORM)
   }
 
   @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+  fun handleRequest_topActivityTransparentWithoutStyleFloating_returnSwitchToFullscreenWCT() {
+    val task =
+      setUpFreeformTask().apply {
+        isTopActivityTransparent = true
+        isTopActivityStyleFloating = false
+        numActivities = 1
+      }
+
+    val result = controller.handleRequest(Binder(), createTransition(task))
+    assertThat(result?.changes?.get(task.token.asBinder())?.windowingMode)
+            .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
+  }
+
+  @Test
+  @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
   fun handleRequest_systemUIActivity_returnSwitchToFullscreenWCT() {
     val task = setUpFreeformTask()
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
index 17983b2..3ec65c7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
@@ -25,6 +25,7 @@
 import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY
 import com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.shared.DesktopModeStatus
@@ -32,6 +33,7 @@
 import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ToggleOverride.OVERRIDE_OFF
 import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ToggleOverride.OVERRIDE_ON
 import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.ToggleOverride.OVERRIDE_UNSET
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Rule
@@ -308,6 +310,138 @@
         .isEqualTo(OVERRIDE_UNSET.setting.toString())
   }
 
+  @Test
+  @EnableFlags(
+    FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
+    FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+    FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagEnabled_overrideUnset_featureFlagOn_returnsTrue() {
+    setOverride(OVERRIDE_UNSET.setting)
+
+    // For unset overrides, follow flag
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
+  }
+
+  @Test
+  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagEnabled_overrideUnset_featureFlagOff_returnsFalse() {
+    setOverride(OVERRIDE_UNSET.setting)
+
+    // For unset overrides, follow flag
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
+  }
+
+  @Test
+  @EnableFlags(
+    FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
+    FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+    FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagEnabled_overrideOn_featureFlagOn_returnsTrue() {
+    setOverride(OVERRIDE_ON.setting)
+
+    // When toggle override matches its default state (dw flag), don't override flags
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
+  }
+
+  @Test
+  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagEnabled_overrideOn_featureFlagOff_returnFalse() {
+    setOverride(OVERRIDE_ON.setting)
+
+    // When toggle override matches its default state (dw flag), don't override flags
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
+  }
+
+  @Test
+  @EnableFlags(
+    FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION,
+    FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
+    FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagEnabled_overrideOff_featureFlagOn_returnsFalse() {
+    setOverride(OVERRIDE_OFF.setting)
+
+    // Follow override if they exist, and is not equal to default toggle state (dw flag)
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
+  }
+
+  @Test
+  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagEnabled_overrideOff_featureFlagOff_returnsFalse() {
+    setOverride(OVERRIDE_OFF.setting)
+
+    // Follow override if they exist, and is not equal to default toggle state (dw flag)
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
+  }
+
+  @Test
+  @EnableFlags(
+    FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+  fun isEnabled_dwFlagDisabled_overrideUnset_featureFlagOn_returnsTrue() {
+    setOverride(OVERRIDE_UNSET.setting)
+
+    // For unset overrides, follow flag
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
+  }
+
+  @Test
+  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+  @DisableFlags(
+    FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagDisabled_overrideUnset_featureFlagOff_returnsFalse() {
+    setOverride(OVERRIDE_UNSET.setting)
+
+    // For unset overrides, follow flag
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
+  }
+
+  @Test
+  @EnableFlags(
+    FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+  fun isEnabled_dwFlagDisabled_overrideOn_featureFlagOn_returnsTrue() {
+    setOverride(OVERRIDE_ON.setting)
+
+    // Follow override if they exist, and is not equal to default toggle state (dw flag)
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
+  }
+
+  @Test
+  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+  @DisableFlags(
+    FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagDisabled_overrideOn_featureFlagOff_returnTrue() {
+    setOverride(OVERRIDE_ON.setting)
+
+    // Follow override if they exist, and is not equal to default toggle state (dw flag)
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
+  }
+
+  @Test
+  @EnableFlags(
+    FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+  fun isEnabled_dwFlagDisabled_overrideOff_featureFlagOn_returnsTrue() {
+    setOverride(OVERRIDE_OFF.setting)
+
+    // When toggle override matches its default state (dw flag), don't override flags
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isTrue()
+  }
+
+  @Test
+  @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+  @DisableFlags(
+    FLAG_ENABLE_DESKTOP_WINDOWING_MODE, FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+  fun isEnabled_dwFlagDisabled_overrideOff_featureFlagOff_returnsFalse() {
+    setOverride(OVERRIDE_OFF.setting)
+
+    // When toggle override matches its default state (dw flag), don't override flags
+    assertThat(WALLPAPER_ACTIVITY.isEnabled(mContext)).isFalse()
+  }
+
   private fun setOverride(setting: Int?) {
     val contentResolver = mContext.contentResolver
     val key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES
@@ -319,10 +453,15 @@
   }
 
   private fun resetCache() {
-    val cachedToggleOverride =
+    val cachedToggleOverrideDesktopMode =
         DESKTOP_WINDOWING_MODE::class.java.getDeclaredField("cachedToggleOverride")
-    cachedToggleOverride.isAccessible = true
-    cachedToggleOverride.set(DESKTOP_WINDOWING_MODE, null)
+    cachedToggleOverrideDesktopMode.isAccessible = true
+    cachedToggleOverrideDesktopMode.set(DESKTOP_WINDOWING_MODE, null)
+
+    val cachedToggleOverrideWallpaperActivity =
+      WALLPAPER_ACTIVITY::class.java.getDeclaredField("cachedToggleOverride")
+    cachedToggleOverrideWallpaperActivity.isAccessible = true
+    cachedToggleOverrideWallpaperActivity.set(WALLPAPER_ACTIVITY, null)
 
     // Clear override cache stored in System property
     System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
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 0ec6713..0bf5a67 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
@@ -348,10 +348,35 @@
     }
 
     @Test
-    fun testDecorationIsNotCreatedForTopTranslucentActivities() {
-        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+    fun testDecorationIsCreatedForTopTranslucentActivitiesWithStyleFloating() {
+        val mockitoSession: StaticMockitoSession = mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .spyStatic(DesktopModeStatus::class.java)
+                .startMocking()
+        try {
+            val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
+                isTopActivityTransparent = true
+                isTopActivityStyleFloating = true
+                numActivities = 1
+            }
+            doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+            setUpMockDecorationsForTasks(task)
+
+            onTaskOpening(task)
+            verify(mockDesktopModeWindowDecorFactory)
+                    .create(any(), any(), any(), eq(task), any(), any(), any(), any(), any())
+        } finally {
+            mockitoSession.finishMocking()
+        }
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
+    fun testDecorationIsNotCreatedForTopTranslucentActivitiesWithoutStyleFloating() {
         val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true).apply {
             isTopActivityTransparent = true
+            isTopActivityStyleFloating = false
             numActivities = 1
         }
         onTaskOpening(task)
@@ -361,6 +386,7 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODALS_POLICY)
     fun testDecorationIsNotCreatedForSystemUIActivities() {
         val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN, focused = true)
 
diff --git a/packages/SettingsLib/ActionButtonsPreference/Android.bp b/packages/SettingsLib/ActionButtonsPreference/Android.bp
index c36b82d..71ecb4c 100644
--- a/packages/SettingsLib/ActionButtonsPreference/Android.bp
+++ b/packages/SettingsLib/ActionButtonsPreference/Android.bp
@@ -19,7 +19,6 @@
 
     static_libs: [
         "androidx.preference_preference",
-        "SettingsLibUtils",
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
index 3e65d94..5dc11cf 100644
--- a/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
+++ b/packages/SettingsLib/ActionButtonsPreference/src/com/android/settingslib/widget/ActionButtonsPreference.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -31,12 +32,11 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
-import com.android.settingslib.utils.BuildCompatUtils;
+import com.android.settingslib.widget.preference.actionbuttons.R;
+
 import java.util.ArrayList;
 import java.util.List;
 
-import com.android.settingslib.widget.preference.actionbuttons.R;
-
 /**
  * This preference provides a four buttons layout with Settings style.
  * It looks like below
@@ -56,7 +56,7 @@
 public class ActionButtonsPreference extends Preference {
 
     private static final String TAG = "ActionButtonPreference";
-    private static final boolean mIsAtLeastS = BuildCompatUtils.isAtLeastS();
+    private static final boolean mIsAtLeastS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
     private static final int SINGLE_BUTTON_STYLE = 1;
     private static final int TWO_BUTTONS_STYLE = 2;
     private static final int THREE_BUTTONS_STYLE = 3;
diff --git a/packages/SettingsLib/ActivityEmbedding/Android.bp b/packages/SettingsLib/ActivityEmbedding/Android.bp
index 838a9e5..5561002 100644
--- a/packages/SettingsLib/ActivityEmbedding/Android.bp
+++ b/packages/SettingsLib/ActivityEmbedding/Android.bp
@@ -20,7 +20,6 @@
         "androidx.annotation_annotation",
         "androidx.core_core",
         "androidx.window_window",
-        "SettingsLibUtils",
     ],
     sdk_version: "system_current",
     min_sdk_version: "21",
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
index f89be9f..67aa8f4 100644
--- a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -20,13 +20,11 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.os.Build;
 import android.util.Log;
 
-import androidx.core.os.BuildCompat;
 import androidx.window.embedding.ActivityEmbeddingController;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 /**
  * An util class collecting all common methods for the embedding activity features.
  */
@@ -70,7 +68,7 @@
      * enabled (unsupported devices).
      */
     private static ComponentName getEmbeddingActivityComponent(Context context) {
-        if (!BuildCompatUtils.isAtLeastSV2()) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) {
             return null;
         }
         final Intent intent = new Intent(ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
@@ -95,7 +93,7 @@
      *                          Settings app
      */
     public static boolean shouldHideNavigateUpButton(Activity activity, boolean isSecondLayerPage) {
-        if (!BuildCompat.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
             return false;
         }
 
diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp
index 07290de..3f671b9 100644
--- a/packages/SettingsLib/BannerMessagePreference/Android.bp
+++ b/packages/SettingsLib/BannerMessagePreference/Android.bp
@@ -20,7 +20,6 @@
     static_libs: [
         "androidx.preference_preference",
         "SettingsLibSettingsTheme",
-        "SettingsLibUtils",
     ],
 
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
index 33775a6..6cd777e 100644
--- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -38,7 +38,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
-import com.android.settingslib.utils.BuildCompatUtils;
 import com.android.settingslib.widget.preference.banner.R;
 /**
  * Banner message is a banner displaying important information (permission request, page error etc),
@@ -84,7 +83,7 @@
     }
 
     private static final String TAG = "BannerPreference";
-    private static final boolean IS_AT_LEAST_S = BuildCompatUtils.isAtLeastS();
+    private static final boolean IS_AT_LEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
 
     private final BannerMessagePreference.ButtonInfo mPositiveButtonInfo =
             new BannerMessagePreference.ButtonInfo();
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 87ec0b8..4834039 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -22,7 +22,6 @@
         "androidx.core_core",
         "com.google.android.material_material",
         "SettingsLibSettingsTransition",
-        "SettingsLibUtils",
         "SettingsLibSettingsTheme",
     ],
     sdk_version: "system_current",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
index 8ebbac3..b252e5f 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/BasePreferencesFragment.java
@@ -16,11 +16,11 @@
 
 package com.android.settingslib.collapsingtoolbar;
 
+import android.os.Build;
+
 import androidx.fragment.app.FragmentActivity;
 import androidx.preference.PreferenceFragmentCompat;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 import com.google.android.material.appbar.AppBarLayout;
 
 /**
@@ -58,7 +58,7 @@
         if (activity != null) {
             activity.setTitle(getTitle());
 
-            if (BuildCompatUtils.isAtLeastS()) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                 AppBarLayout appBarLayout = (AppBarLayout) activity.findViewById(R.id.app_bar);
 
                 if (appBarLayout != null) {
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java
index 04c44e6..8b27626 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarAppCompatActivity.java
@@ -17,6 +17,7 @@
 package com.android.settingslib.collapsingtoolbar;
 
 import android.app.ActionBar;
+import android.os.Build;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -26,8 +27,6 @@
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 import com.google.android.material.appbar.AppBarLayout;
 import com.google.android.material.appbar.CollapsingToolbarLayout;
 import com.google.android.material.color.DynamicColors;
@@ -66,12 +65,12 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        if (BuildCompatUtils.isAtLeastS()) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
             DynamicColors.applyToActivityIfAvailable(this);
         }
         setTheme(com.android.settingslib.widget.theme.R.style.Theme_SubSettingsBase);
 
-        if (mCustomizeLayoutResId > 0 && !BuildCompatUtils.isAtLeastS()) {
+        if (mCustomizeLayoutResId > 0 && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
             super.setContentView(mCustomizeLayoutResId);
             return;
         }
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 143101f..86ce2ab 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -18,6 +18,7 @@
 
 import android.app.ActionBar;
 import android.content.pm.PackageManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -27,8 +28,6 @@
 import androidx.annotation.Nullable;
 import androidx.fragment.app.FragmentActivity;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 import com.google.android.material.appbar.AppBarLayout;
 import com.google.android.material.appbar.CollapsingToolbarLayout;
 
@@ -60,7 +59,8 @@
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         // for backward compatibility on R devices or wearable devices due to small device size.
-        if (mCustomizeLayoutResId > 0 && (!BuildCompatUtils.isAtLeastS() || isWatch())) {
+        if (mCustomizeLayoutResId > 0 && (Build.VERSION.SDK_INT < Build.VERSION_CODES.S
+                || isWatch())) {
             super.setContentView(mCustomizeLayoutResId);
             return;
         }
diff --git a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
index c52386b..7be4482 100644
--- a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
+++ b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
@@ -30,7 +30,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.core.os.BuildCompat;
 import androidx.fragment.app.Fragment;
 import androidx.viewpager2.widget.ViewPager2;
 
@@ -226,7 +225,8 @@
     // to be here only for this API level - when then private profile was introduced.
     @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
     private boolean shouldShowPrivateProfileIfItsOne(UserHandle userHandle) {
-        if (!BuildCompat.isAtLeastV() || !android.os.Flags.allowPrivateProfile()) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM
+                || !android.os.Flags.allowPrivateProfile()) {
             return false;
         }
         try {
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
deleted file mode 100644
index bf3651b..0000000
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.utils;
-
-import android.os.Build;
-
-import androidx.annotation.ChecksSdkIntAtLeast;
-
-/**
- * An util class to check whether the current OS version is higher or equal to sdk version of
- * device.
- */
-public final class BuildCompatUtils {
-
-    /**
-     * Implementation of BuildCompat.isAtLeastS() suitable for use in Settings
-     *
-     * @return Whether the current OS version is higher or equal to S.
-     */
-    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
-    public static boolean isAtLeastS() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
-    }
-
-    /**
-     * Implementation of BuildCompat.isAtLeastS() suitable for use in Settings
-     *
-     * @return Whether the current OS version is higher or equal to Sv2.
-     */
-    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S_V2)
-    public static boolean isAtLeastSV2() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2;
-    }
-
-    /**
-     * Implementation of BuildCompat.isAtLeastT() suitable for use in Settings
-     *
-     * @return Whether the current OS version is higher or equal to T.
-     */
-    @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
-    public static boolean isAtLeastT() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
-    }
-
-    private BuildCompatUtils() {}
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 734b92c..6ca9279 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -38,8 +38,6 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 /**
  * Helper class for managing settings preferences that can be disabled
  * by device admins via user restrictions.
@@ -120,9 +118,10 @@
         if (mDisabledSummary) {
             final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
             if (summaryView != null) {
-                final CharSequence disabledText = BuildCompatUtils.isAtLeastT()
-                        ? getDisabledByAdminUpdatableString()
-                        : mContext.getString(R.string.disabled_by_admin_summary_text);
+                final CharSequence disabledText =
+                        (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
+                                ? getDisabledByAdminUpdatableString()
+                                : mContext.getString(R.string.disabled_by_admin_summary_text);
                 if (mDisabledByAdmin) {
                     summaryView.setText(disabledText);
                 } else if (mDisabledByEcm) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 45754eb..fffbb54 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -25,6 +25,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.AttributeSet;
@@ -40,8 +41,6 @@
 import androidx.preference.PreferenceViewHolder;
 import androidx.preference.SwitchPreferenceCompat;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 /**
  * Version of SwitchPreferenceCompat that can be disabled by a device admin
  * using a user restriction.
@@ -164,7 +163,7 @@
 
     private static String getUpdatableEnterpriseString(
             Context context, String updatableStringId, int resId) {
-        if (!BuildCompatUtils.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
             return context.getString(resId);
         }
         return context.getSystemService(DevicePolicyManager.class).getResources().getString(
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index c2506d3..b02b0c4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -66,7 +66,6 @@
 import com.android.settingslib.drawable.UserIconDrawable;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.settingslib.fuelgauge.BatteryUtils;
-import com.android.settingslib.utils.BuildCompatUtils;
 
 import java.util.List;
 
@@ -147,7 +146,7 @@
         String name = info != null ? info.name : null;
         if (info.isManagedProfile()) {
             // We use predefined values for managed profiles
-            return BuildCompatUtils.isAtLeastT()
+            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
                     ? getUpdatableManagedUserTitle(context)
                     : context.getString(R.string.managed_user_title);
         } else if (info.isGuest()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 721e7b9..53441c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -24,6 +24,7 @@
 import android.net.Uri;
 import android.provider.DeviceConfig;
 import android.provider.MediaStore;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -808,7 +809,8 @@
      * <p>If CachedBluetoothDevice#getGroupId is invalid, fetch group id from
      * LeAudioProfile#getGroupId.
      */
-    public static int getGroupId(@NonNull CachedBluetoothDevice cachedDevice) {
+    public static int getGroupId(@Nullable CachedBluetoothDevice cachedDevice) {
+        if (cachedDevice == null) return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
         int groupId = cachedDevice.getGroupId();
         String anonymizedAddress = cachedDevice.getDevice().getAnonymizedAddress();
         if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
@@ -824,4 +826,44 @@
         Log.d(TAG, "getGroupId return invalid id for device: " + anonymizedAddress);
         return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
     }
+
+    /** Get primary device Uri in broadcast. */
+    @NonNull
+    public static String getPrimaryGroupIdUriForBroadcast() {
+        return "bluetooth_le_broadcast_fallback_active_group_id";
+    }
+
+    /** Get primary device group id in broadcast. */
+    @WorkerThread
+    public static int getPrimaryGroupIdForBroadcast(@NonNull Context context) {
+        return Settings.Secure.getInt(
+                context.getContentResolver(),
+                getPrimaryGroupIdUriForBroadcast(),
+                BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+    }
+
+    /** Get secondary {@link CachedBluetoothDevice} in broadcast. */
+    @Nullable
+    @WorkerThread
+    public static CachedBluetoothDevice getSecondaryDeviceForBroadcast(
+            @NonNull Context context, @Nullable LocalBluetoothManager localBtManager) {
+        if (localBtManager == null) return null;
+        int primaryGroupId = getPrimaryGroupIdForBroadcast(context);
+        if (primaryGroupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) return null;
+        LocalBluetoothLeBroadcastAssistant assistant =
+                localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+        CachedBluetoothDeviceManager deviceManager = localBtManager.getCachedDeviceManager();
+        List<BluetoothDevice> devices = assistant.getAllConnectedDevices();
+        for (BluetoothDevice device : devices) {
+            CachedBluetoothDevice cachedDevice = deviceManager.findDevice(device);
+            if (hasConnectedBroadcastSource(cachedDevice, localBtManager)) {
+                int groupId = getGroupId(cachedDevice);
+                if (groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+                        && groupId != primaryGroupId) {
+                    return cachedDevice;
+                }
+            }
+        }
+        return null;
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index ea65ade..84afb9f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -25,7 +25,6 @@
 import androidx.annotation.EmptySuper;
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
-import androidx.core.os.BuildCompat;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
@@ -141,7 +140,7 @@
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     protected void replaceEnterpriseStringTitle(PreferenceScreen screen,
             String preferenceKey, String overrideKey, int resource) {
-        if (!BuildCompat.isAtLeastT() || mDevicePolicyManager == null) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || mDevicePolicyManager == null) {
             return;
         }
 
@@ -159,7 +158,7 @@
     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
     protected void replaceEnterpriseStringSummary(
             PreferenceScreen screen, String preferenceKey, String overrideKey, int resource) {
-        if (!BuildCompat.isAtLeastT() || mDevicePolicyManager == null) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || mDevicePolicyManager == null) {
             return;
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index f07daa3..243403e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -48,8 +48,6 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.settingslib.utils.BuildCompatUtils;
-
 /**
  * Converts the user avatar icon to a circularly clipped one with an optional badge and frame
  */
@@ -88,7 +86,7 @@
      * @return drawable containing just the badge
      */
     public static Drawable getManagedUserDrawable(Context context) {
-        if (BuildCompatUtils.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
             return getUpdatableManagedUserDrawable(context);
         } else {
             return getDrawableForDisplayDensity(
@@ -227,7 +225,7 @@
     }
 
     private static Drawable getManagementBadge(Context context) {
-        if (BuildCompatUtils.isAtLeastT()) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
             return getUpdatableManagementBadge(context);
         } else {
             return getDrawableForDisplayDensity(
diff --git a/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt b/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt
index 4d25237..2952764 100644
--- a/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/statusbar/notification/data/repository/ZenModeRepository.kt
@@ -73,12 +73,12 @@
 
                 awaitClose { context.unregisterReceiver(receiver) }
             }
-            .apply {
+            .let {
                 if (Flags.volumePanelBroadcastFix()) {
-                    flowOn(backgroundCoroutineContext)
-                    stateIn(scope, SharingStarted.WhileSubscribed(), null)
+                    it.flowOn(backgroundCoroutineContext)
+                        .stateIn(scope, SharingStarted.WhileSubscribed(), null)
                 } else {
-                    shareIn(
+                    it.shareIn(
                         started = SharingStarted.WhileSubscribed(),
                         scope = scope,
                     )
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
index 202ff40..bdd582d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
@@ -61,6 +61,10 @@
     }
 
     suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean) {
+        val streamModel = getAudioStream(audioStream).first()
+        if (!streamModel.isAffectedByMute) {
+            return
+        }
         if (audioStream.value == AudioManager.STREAM_RING) {
             val mode =
                 if (isMuted) AudioManager.RINGER_MODE_VIBRATE else AudioManager.RINGER_MODE_NORMAL
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index a638df5..28bf348 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -22,11 +22,13 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeBroadcastReceiveState;
 import android.content.Context;
@@ -36,10 +38,13 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Settings;
 import android.util.Pair;
 
 import com.android.settingslib.widget.AdaptiveIcon;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -562,4 +567,77 @@
 
         assertThat(BluetoothUtils.isAvailableHearingDevice(mCachedBluetoothDevice)).isEqualTo(true);
     }
+
+    @Test
+    public void getGroupId_getCsipProfileId() {
+        when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
+
+        assertThat(BluetoothUtils.getGroupId(mCachedBluetoothDevice)).isEqualTo(1);
+    }
+
+    @Test
+    public void getGroupId_getLeAudioProfileId() {
+        when(mCachedBluetoothDevice.getGroupId())
+                .thenReturn(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+        LeAudioProfile leAudio = mock(LeAudioProfile.class);
+        when(leAudio.getGroupId(mBluetoothDevice)).thenReturn(1);
+        when(mCachedBluetoothDevice.getProfiles()).thenReturn(ImmutableList.of(leAudio));
+
+        assertThat(BluetoothUtils.getGroupId(mCachedBluetoothDevice)).isEqualTo(1);
+    }
+
+    @Test
+    public void getSecondaryDeviceForBroadcast_errorState_returnNull() {
+        assertThat(BluetoothUtils.getSecondaryDeviceForBroadcast(mContext, mLocalBluetoothManager))
+                .isNull();
+    }
+
+    @Test
+    public void getSecondaryDeviceForBroadcast_noSecondary_returnNull() {
+        Settings.Secure.putInt(
+                mContext.getContentResolver(),
+                BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+                1);
+        CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+        when(deviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+        when(mCachedBluetoothDevice.getGroupId()).thenReturn(1);
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of(state));
+        when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mBluetoothDevice));
+
+        assertThat(BluetoothUtils.getSecondaryDeviceForBroadcast(mContext, mLocalBluetoothManager))
+                .isNull();
+    }
+
+    @Test
+    public void getSecondaryDeviceForBroadcast_returnCorrectDevice() {
+        Settings.Secure.putInt(
+                mContext.getContentResolver(),
+                BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
+                1);
+        CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+        when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+        CachedBluetoothDevice cachedBluetoothDevice = mock(CachedBluetoothDevice.class);
+        BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
+        when(cachedBluetoothDevice.getDevice()).thenReturn(bluetoothDevice);
+        when(cachedBluetoothDevice.getGroupId()).thenReturn(1);
+        when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+        when(mCachedBluetoothDevice.getGroupId()).thenReturn(2);
+        when(deviceManager.findDevice(bluetoothDevice)).thenReturn(cachedBluetoothDevice);
+        when(deviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+        BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+        List<Long> bisSyncState = new ArrayList<>();
+        bisSyncState.add(1L);
+        when(state.getBisSyncState()).thenReturn(bisSyncState);
+        when(mAssistant.getAllSources(any(BluetoothDevice.class)))
+                .thenReturn(ImmutableList.of(state));
+        when(mAssistant.getAllConnectedDevices())
+                .thenReturn(ImmutableList.of(mBluetoothDevice, bluetoothDevice));
+
+        assertThat(BluetoothUtils.getSecondaryDeviceForBroadcast(mContext, mLocalBluetoothManager))
+                .isEqualTo(mCachedBluetoothDevice);
+    }
 }
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b5776e2..469b9ce 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -23,7 +23,10 @@
 // See: http://go/android-license-faq
 license {
     name: "frameworks_base_packages_SystemUI_license",
-    visibility: [":__subpackages__"],
+    visibility: [
+        ":__subpackages__",
+        "//development/samples/SceneTransitionLayoutDemo:__subpackages__",
+    ],
     license_kinds: [
         "SPDX-license-identifier-Apache-2.0",
     ],
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 6bbac45..07f7436 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1136,4 +1136,14 @@
   metadata {
     purpose: PURPOSE_BUGFIX
   }
-}
\ No newline at end of file
+}
+
+flag {
+   namespace: "systemui"
+   name: "fetch_bookmarks_xml_keyboard_shortcuts"
+   description: "Fetches application launch keyboard shortcuts from system server rather than building a hardcoded list."
+   bug: "312452252"
+   metadata {
+       purpose: PURPOSE_BUGFIX
+   }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index e8fdfc8..d95b388 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -913,6 +913,7 @@
     private val topOrLeftBehavior: NestedScrollBehavior,
     private val bottomOrRightBehavior: NestedScrollBehavior,
     private val isExternalOverscrollGesture: () -> Boolean,
+    private val pointersInfoOwner: PointersInfoOwner,
 ) {
     private val layoutState = layoutImpl.state
     private val draggableHandler = layoutImpl.draggableHandler(orientation)
@@ -924,25 +925,12 @@
         // moving on to the next scene.
         var canChangeScene = false
 
-        val actionUpOrLeft =
-            Swipe(
-                direction =
-                    when (orientation) {
-                        Orientation.Horizontal -> SwipeDirection.Left
-                        Orientation.Vertical -> SwipeDirection.Up
-                    },
-                pointerCount = 1,
-            )
-
-        val actionDownOrRight =
-            Swipe(
-                direction =
-                    when (orientation) {
-                        Orientation.Horizontal -> SwipeDirection.Right
-                        Orientation.Vertical -> SwipeDirection.Down
-                    },
-                pointerCount = 1,
-            )
+        var _lastPointersInfo: PointersInfo? = null
+        fun pointersInfo(): PointersInfo {
+            return checkNotNull(_lastPointersInfo) {
+                "PointersInfo should be initialized before the transition begins."
+            }
+        }
 
         fun hasNextScene(amount: Float): Boolean {
             val transitionState = layoutState.transitionState
@@ -950,8 +938,30 @@
             val fromScene = layoutImpl.scene(scene)
             val nextScene =
                 when {
-                    amount < 0f -> fromScene.userActions[actionUpOrLeft]
-                    amount > 0f -> fromScene.userActions[actionDownOrRight]
+                    amount < 0f -> {
+                        val actionUpOrLeft =
+                            Swipe(
+                                direction =
+                                    when (orientation) {
+                                        Orientation.Horizontal -> SwipeDirection.Left
+                                        Orientation.Vertical -> SwipeDirection.Up
+                                    },
+                                pointerCount = pointersInfo().pointersDown,
+                            )
+                        fromScene.userActions[actionUpOrLeft]
+                    }
+                    amount > 0f -> {
+                        val actionDownOrRight =
+                            Swipe(
+                                direction =
+                                    when (orientation) {
+                                        Orientation.Horizontal -> SwipeDirection.Right
+                                        Orientation.Vertical -> SwipeDirection.Down
+                                    },
+                                pointerCount = pointersInfo().pointersDown,
+                            )
+                        fromScene.userActions[actionDownOrRight]
+                    }
                     else -> null
                 }
             if (nextScene != null) return true
@@ -985,6 +995,8 @@
                     return@PriorityNestedScrollConnection false
                 }
 
+                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+
                 // If the current swipe transition is *not* closed to 0f or 1f, then we want the
                 // scroll events to intercept the current transition to continue the scene
                 // transition.
@@ -1002,6 +1014,8 @@
                 val isZeroOffset =
                     if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
 
+                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+
                 val canStart =
                     when (behavior) {
                         NestedScrollBehavior.DuringTransitionBetweenScenes -> {
@@ -1039,6 +1053,8 @@
                 // We could start an overscroll animation
                 canChangeScene = false
 
+                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+
                 val canStart = behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
                 if (canStart) {
                     isIntercepting = false
@@ -1049,10 +1065,11 @@
             canContinueScroll = { true },
             canScrollOnFling = false,
             onStart = { offsetAvailable ->
+                val pointersInfo = pointersInfo()
                 dragController =
                     draggableHandler.onDragStarted(
-                        pointersDown = 1,
-                        startedPosition = null,
+                        pointersDown = pointersInfo.pointersDown,
+                        startedPosition = pointersInfo.startedPosition,
                         overSlop = if (isIntercepting) 0f else offsetAvailable,
                     )
             },
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index f40f265..cdcfc84 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -29,18 +29,21 @@
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.PointerInputScope
 import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
-import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
+import androidx.compose.ui.input.pointer.changedToDown
 import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
 import androidx.compose.ui.input.pointer.positionChange
 import androidx.compose.ui.input.pointer.positionChangeIgnoreConsumed
 import androidx.compose.ui.input.pointer.util.VelocityTracker
 import androidx.compose.ui.input.pointer.util.addPointerInputChange
 import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+import androidx.compose.ui.node.DelegatableNode
 import androidx.compose.ui.node.DelegatingNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.node.ObserverModifierNode
 import androidx.compose.ui.node.PointerInputModifierNode
+import androidx.compose.ui.node.TraversableNode
 import androidx.compose.ui.node.currentValueOf
+import androidx.compose.ui.node.findNearestAncestor
 import androidx.compose.ui.node.observeReads
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.unit.IntSize
@@ -48,11 +51,12 @@
 import androidx.compose.ui.util.fastAll
 import androidx.compose.ui.util.fastAny
 import androidx.compose.ui.util.fastFirstOrNull
-import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastSumBy
 import kotlin.coroutines.cancellation.CancellationException
 import kotlin.math.sign
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.isActive
+import kotlinx.coroutines.launch
 
 /**
  * Make an element draggable in the given [orientation].
@@ -112,6 +116,18 @@
     }
 }
 
+private val TRAVERSE_KEY = Any()
+
+/** Find the nearest [PointersInfoOwner] ancestor or throw. */
+internal fun DelegatableNode.requireAncestorPointersInfoOwner(): PointersInfoOwner {
+    val ancestorNode =
+        checkNotNull(findNearestAncestor(TRAVERSE_KEY)) {
+            "This should never happen! Couldn't find a MultiPointerDraggableNode. " +
+                "Are we inside an SceneTransitionLayout?"
+        }
+    return ancestorNode as PointersInfoOwner
+}
+
 internal class MultiPointerDraggableNode(
     orientation: Orientation,
     enabled: () -> Boolean,
@@ -120,15 +136,19 @@
         (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController,
     var swipeDetector: SwipeDetector = DefaultSwipeDetector,
 ) :
-    PointerInputModifierNode,
     DelegatingNode(),
+    PointerInputModifierNode,
     CompositionLocalConsumerModifierNode,
+    TraversableNode,
+    PointersInfoOwner,
     ObserverModifierNode {
     private val pointerInputHandler: suspend PointerInputScope.() -> Unit = { pointerInput() }
     private val delegate = delegate(SuspendingPointerInputModifierNode(pointerInputHandler))
     private val velocityTracker = VelocityTracker()
     private var previousEnabled: Boolean = false
 
+    override val traverseKey: Any = TRAVERSE_KEY
+
     var enabled: () -> Boolean = enabled
         set(value) {
             // Reset the pointer input whenever enabled changed.
@@ -185,12 +205,42 @@
         bounds: IntSize
     ) = delegate.onPointerEvent(pointerEvent, pass, bounds)
 
+    private var startedPosition: Offset? = null
+    private var pointersDown: Int = 0
+
+    override fun pointersInfo(): PointersInfo {
+        return PointersInfo(
+            startedPosition = startedPosition,
+            // Note: We could have 0 pointers during fling or for other reasons.
+            pointersDown = pointersDown.coerceAtLeast(1),
+        )
+    }
+
     private suspend fun PointerInputScope.pointerInput() {
         if (!enabled()) {
             return
         }
 
         coroutineScope {
+            launch {
+                // Intercepts pointer inputs and exposes [PointersInfo], via
+                // [requireAncestorPointersInfoOwner], to our descendants.
+                awaitPointerEventScope {
+                    while (isActive) {
+                        // During the Initial pass, we receive the event after our ancestors.
+                        val pointers = awaitPointerEvent(PointerEventPass.Initial).changes
+
+                        pointersDown = pointers.countDown()
+                        if (pointersDown == 0) {
+                            // There are no more pointers down
+                            startedPosition = null
+                        } else if (startedPosition == null) {
+                            startedPosition = pointers.first().position
+                        }
+                    }
+                }
+            }
+
             awaitPointerEventScope {
                 while (isActive) {
                     try {
@@ -314,15 +364,16 @@
             }
 
         if (drag != null) {
-            // Count the number of pressed pointers.
-            val pressed = mutableSetOf<PointerId>()
-            currentEvent.changes.fastForEach { change ->
-                if (change.pressed) {
-                    pressed.add(change.id)
-                }
-            }
-
-            val controller = onDragStart(drag.position, overSlop, pressed.size)
+            val controller =
+                onDragStart(
+                    // The startedPosition is the starting position when a gesture begins (when the
+                    // first pointer touches the screen), not the point where we begin dragging.
+                    // For example, this could be different if one of our children intercepts the
+                    // gesture first and then we do.
+                    requireNotNull(startedPosition),
+                    overSlop,
+                    pointersDown,
+                )
 
             val successful: Boolean
             try {
@@ -364,12 +415,10 @@
         fun canBeConsumed(changes: List<PointerInputChange>): Boolean {
             // At least one pointer down AND
             return changes.fastAny { it.pressed } &&
-                // All pointers must be:
+                // All pointers must be either:
                 changes.fastAll {
-                    // A) recently pressed: even if the event has already been consumed, we can
-                    // still use the recently added finger event to determine whether to initiate
-                    // dragging the scene.
-                    it.changedToDownIgnoreConsumed() ||
+                    // A) unconsumed AND recently pressed
+                    it.changedToDown() ||
                         // B) unconsumed AND in a new position (on the current axis)
                         it.positionChange().toFloat() != 0f
                 }
@@ -461,4 +510,15 @@
             }
         }
     }
+
+    private fun List<PointerInputChange>.countDown() = fastSumBy { if (it.pressed) 1 else 0 }
 }
+
+internal fun interface PointersInfoOwner {
+    fun pointersInfo(): PointersInfo
+}
+
+internal data class PointersInfo(
+    val startedPosition: Offset?,
+    val pointersDown: Int,
+)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 1fa6b3f7..ddff2f7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -128,6 +128,7 @@
     bottomOrRightBehavior: NestedScrollBehavior,
     isExternalOverscrollGesture: () -> Boolean,
 ) : DelegatingNode() {
+    lateinit var pointersInfoOwner: PointersInfoOwner
     private var priorityNestedScrollConnection: PriorityNestedScrollConnection =
         scenePriorityNestedScrollConnection(
             layoutImpl = layoutImpl,
@@ -135,6 +136,7 @@
             topOrLeftBehavior = topOrLeftBehavior,
             bottomOrRightBehavior = bottomOrRightBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
+            pointersInfoOwner = { pointersInfoOwner.pointersInfo() }
         )
 
     private var nestedScrollNode: DelegatableNode =
@@ -144,6 +146,7 @@
         )
 
     override fun onAttach() {
+        pointersInfoOwner = requireAncestorPointersInfoOwner()
         delegate(nestedScrollNode)
     }
 
@@ -171,6 +174,7 @@
                 topOrLeftBehavior = topOrLeftBehavior,
                 bottomOrRightBehavior = bottomOrRightBehavior,
                 isExternalOverscrollGesture = isExternalOverscrollGesture,
+                pointersInfoOwner = pointersInfoOwner,
             )
         nestedScrollNode =
             nestedScrollModifierNode(
@@ -187,6 +191,7 @@
     topOrLeftBehavior: NestedScrollBehavior,
     bottomOrRightBehavior: NestedScrollBehavior,
     isExternalOverscrollGesture: () -> Boolean,
+    pointersInfoOwner: PointersInfoOwner,
 ) =
     NestedScrollHandlerImpl(
             layoutImpl = layoutImpl,
@@ -194,5 +199,6 @@
             topOrLeftBehavior = topOrLeftBehavior,
             bottomOrRightBehavior = bottomOrRightBehavior,
             isExternalOverscrollGesture = isExternalOverscrollGesture,
+            pointersInfoOwner = pointersInfoOwner,
         )
         .connection
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 65b388f..ff83d4b 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -113,7 +113,10 @@
                     orientation = draggableHandler.orientation,
                     topOrLeftBehavior = nestedScrollBehavior,
                     bottomOrRightBehavior = nestedScrollBehavior,
-                    isExternalOverscrollGesture = { isExternalOverscrollGesture }
+                    isExternalOverscrollGesture = { isExternalOverscrollGesture },
+                    pointersInfoOwner = {
+                        PointersInfo(startedPosition = Offset.Zero, pointersDown = 1)
+                    }
                 )
                 .connection
 
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 2de6faa..1ae9992 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -839,6 +839,80 @@
     }
 
     @Test
+    fun elementTransitionDuringNestedScrollWith2Pointers() {
+        // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+        // detected as a drag event.
+        var touchSlop = 0f
+        val translateY = 10.dp
+        val layoutWidth = 200.dp
+        val layoutHeight = 400.dp
+
+        val state =
+            rule.runOnUiThread {
+                MutableSceneTransitionLayoutState(
+                    initialScene = SceneA,
+                    transitions =
+                        transitions {
+                            from(SceneA, to = SceneB) {
+                                translate(TestElements.Foo, y = translateY)
+                            }
+                        },
+                )
+                    as MutableSceneTransitionLayoutStateImpl
+            }
+
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(
+                state = state,
+                modifier = Modifier.size(layoutWidth, layoutHeight)
+            ) {
+                scene(
+                    SceneA,
+                    userActions = mapOf(Swipe(SwipeDirection.Down, pointerCount = 2) to SceneB)
+                ) {
+                    Box(
+                        Modifier
+                            // Unconsumed scroll gesture will be intercepted by STL
+                            .verticalNestedScrollToScene()
+                            // A scrollable that does not consume the scroll gesture
+                            .scrollable(
+                                rememberScrollableState(consumeScrollDelta = { 0f }),
+                                Orientation.Vertical
+                            )
+                            .fillMaxSize()
+                    ) {
+                        Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+                    }
+                }
+                scene(SceneB) { Spacer(Modifier.fillMaxSize()) }
+            }
+        }
+
+        assertThat(state.transitionState).isIdle()
+        val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag)
+        fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+
+        // Swipe down with 2 pointers by half of verticalSwipeDistance.
+        rule.onRoot().performTouchInput {
+            val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+            repeat(2) { i -> down(pointerId = i, middleTop) }
+            repeat(2) { i ->
+                // Scroll 50%
+                moveBy(
+                    pointerId = i,
+                    delta = Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f),
+                    delayMillis = 1_000,
+                )
+            }
+        }
+
+        val transition = assertThat(state.transitionState).isTransition()
+        assertThat(transition).hasProgress(0.5f)
+        fooElement.assertTopPositionInRootIsEqualTo(translateY * 0.5f)
+    }
+
+    @Test
     fun elementTransitionWithDistanceDuringOverscroll() {
         val layoutWidth = 200.dp
         val layoutHeight = 400.dp
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index 460b640..ecafb17 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -128,7 +128,7 @@
         var started = false
         var dragged = false
         var stopped = false
-        var consumeBeforeMultiPointerDraggable = false
+        var consumedByDescendant = false
 
         var touchSlop = 0f
         rule.setContent {
@@ -138,6 +138,7 @@
                     .multiPointerDraggable(
                         orientation = Orientation.Vertical,
                         enabled = { true },
+                        // We want to start a drag gesture immediately
                         startDragImmediately = { true },
                         onDragStarted = { _, _, _ ->
                             started = true
@@ -157,7 +158,7 @@
                             awaitPointerEventScope {
                                 while (isActive) {
                                     val change = awaitPointerEvent().changes.first()
-                                    if (consumeBeforeMultiPointerDraggable) {
+                                    if (consumedByDescendant) {
                                         change.consume()
                                     }
                                 }
@@ -168,18 +169,19 @@
         }
 
         // The first part of the gesture is consumed by our descendant
-        consumeBeforeMultiPointerDraggable = true
+        consumedByDescendant = true
         rule.onRoot().performTouchInput {
             down(middle)
             moveBy(Offset(0f, touchSlop))
         }
 
-        started = false
-        dragged = false
-        stopped = false
+        // The events were consumed by our descendant, we should not start a drag gesture.
+        assertThat(started).isFalse()
+        assertThat(dragged).isFalse()
+        assertThat(stopped).isFalse()
 
         // The next events could be consumed by us
-        consumeBeforeMultiPointerDraggable = false
+        consumedByDescendant = false
         rule.onRoot().performTouchInput {
             // The pointer is moved to a new position without reporting it
             updatePointerBy(0, Offset(0f, touchSlop))
@@ -188,7 +190,7 @@
             up()
         }
 
-        // This event should not be used to start a drag gesture
+        // The "up" event should not be used to start a drag gesture
         assertThat(started).isFalse()
         assertThat(dragged).isFalse()
         assertThat(stopped).isFalse()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index de6f1cc..41bf630 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -314,7 +314,6 @@
                         }
                     },
             )
-                as MutableSceneTransitionLayoutStateImpl
 
         // Default transition from A to B.
         assertThat(state.setTargetScene(SceneB, coroutineScope = this)).isNotNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt
index 0f5e458..8914c80 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractorTest.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
@@ -54,6 +55,9 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
 import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -208,6 +212,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun showWhenLockedActivityLaunchedFromPowerGesture_falseIfReturningToGone() =
         testScope.runTest {
             val values by collectValues(underTest.showWhenLockedActivityLaunchedFromPowerGesture)
@@ -245,6 +250,42 @@
 
     @Test
     @EnableSceneContainer
+    fun showWhenLockedActivityLaunchedFromPowerGesture_falseIfReturningToGone_scene_container() =
+        testScope.runTest {
+            val values by collectValues(underTest.showWhenLockedActivityLaunchedFromPowerGesture)
+            powerInteractor.setAwakeForTest()
+            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+            powerInteractor.setAsleepForTest()
+
+            kosmos.setSceneTransition(Transition(Scenes.Gone, Scenes.Lockscreen))
+            transitionRepository.sendTransitionSteps(
+                from = KeyguardState.UNDEFINED,
+                to = KeyguardState.AOD,
+                testScope = testScope,
+                throughTransitionState = TransitionState.RUNNING
+            )
+
+            powerInteractor.onCameraLaunchGestureDetected()
+            kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true)
+            powerInteractor.setAwakeForTest()
+            runCurrent()
+
+            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+            transitionRepository.sendTransitionSteps(
+                from = KeyguardState.AOD,
+                to = KeyguardState.UNDEFINED,
+                testScope = testScope,
+            )
+
+            assertThat(values)
+                .containsExactly(
+                    false,
+                )
+        }
+
+    @Test
+    @EnableSceneContainer
     fun occludingActivityWillDismissKeyguard() =
         testScope.runTest {
             val occludingActivityWillDismissKeyguard by
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
index 6e49e43..8a68417 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
@@ -35,6 +35,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
+import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -48,6 +49,20 @@
     private val underTest: AudioVolumeInteractor =
         with(kosmos) { AudioVolumeInteractor(audioRepository, notificationsSoundPolicyInteractor) }
 
+    @Before
+    fun setUp() =
+        with(kosmos) {
+            audioRepository.setAudioStreamModel(
+                audioRepository.getAudioStream(audioStream).value.copy(isAffectedByMute = true)
+            )
+            audioRepository.setAudioStreamModel(
+                audioRepository
+                    .getAudioStream(AudioStream(AudioManager.STREAM_RING))
+                    .value
+                    .copy(isAffectedByMute = true)
+            )
+        }
+
     @Test
     fun setMuted_mutesStream() {
         with(kosmos) {
@@ -189,10 +204,14 @@
             testScope.runTest {
                 val audioStreamModel by collectLastValue(underTest.getAudioStream(audioStream))
                 audioRepository.setAudioStreamModel(
-                    audioStreamModel!!.copy(isAffectedByMute = false)
+                    audioStreamModel!!.copy(isAffectedByMute = false, isMuted = false)
                 )
 
+                underTest.setMuted(audioStream, true)
+                runCurrent()
+
                 assertThat(audioStreamModel!!.isAffectedByMute).isFalse()
+                assertThat(audioStreamModel!!.isMuted).isFalse()
             }
         }
     }
diff --git a/packages/SystemUI/res/layout/app_clips_screenshot.xml b/packages/SystemUI/res/layout/app_clips_screenshot.xml
index 6d4e410..b09d35d 100644
--- a/packages/SystemUI/res/layout/app_clips_screenshot.xml
+++ b/packages/SystemUI/res/layout/app_clips_screenshot.xml
@@ -16,6 +16,7 @@
   -->
 <androidx.constraintlayout.widget.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:background="@null"
@@ -30,9 +31,10 @@
         android:layout_height="48dp"
         android:layout_marginStart="8dp"
         android:background="@drawable/overlay_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorPrimary"
         android:paddingHorizontal="24dp"
         android:text="@string/app_clips_save_add_to_note"
-        android:textColor="?android:textColorSecondary"
+        android:textColor="?androidprv:attr/materialColorOnPrimary"
         app:layout_constraintBottom_toTopOf="@id/preview"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
index 6032f0b..b33924c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/AccessibilityRepository.kt
@@ -18,10 +18,10 @@
 
 import android.view.accessibility.AccessibilityManager
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
-import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import com.android.app.tracing.FlowTracing.tracedAwaitClose
+import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow
 import dagger.Module
 import dagger.Provides
-import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
 
@@ -38,24 +38,28 @@
     }
 }
 
+private const val TAG = "AccessibilityRepository"
+
 private class AccessibilityRepositoryImpl(
     manager: AccessibilityManager,
 ) : AccessibilityRepository {
     override val isTouchExplorationEnabled: Flow<Boolean> =
-        conflatedCallbackFlow {
+        tracedConflatedCallbackFlow(TAG) {
                 val listener = TouchExplorationStateChangeListener(::trySend)
                 manager.addTouchExplorationStateChangeListener(listener)
                 trySend(manager.isTouchExplorationEnabled)
-                awaitClose { manager.removeTouchExplorationStateChangeListener(listener) }
+                tracedAwaitClose(TAG) {
+                    manager.removeTouchExplorationStateChangeListener(listener)
+                }
             }
             .distinctUntilChanged()
 
     override val isEnabled: Flow<Boolean> =
-        conflatedCallbackFlow {
+        tracedConflatedCallbackFlow(TAG) {
                 val listener = AccessibilityManager.AccessibilityStateChangeListener(::trySend)
                 manager.addAccessibilityStateChangeListener(listener)
                 trySend(manager.isEnabled)
-                awaitClose { manager.removeAccessibilityStateChangeListener(listener) }
+                tracedAwaitClose(TAG) { manager.removeAccessibilityStateChangeListener(listener) }
             }
             .distinctUntilChanged()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
index f54fd22..b47fb65 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepository.kt
@@ -16,12 +16,18 @@
 
 package com.android.systemui.keyboard.shortcut.data.repository
 
+import android.content.Context
+import android.hardware.input.InputManager
+import android.util.Log
+import android.view.InputDevice
+import android.view.KeyCharacterMap
 import android.view.KeyEvent
 import android.view.KeyboardShortcutGroup
 import android.view.KeyboardShortcutInfo
 import android.view.WindowManager
 import android.view.WindowManager.KeyboardShortcutsReceiver
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyboard.shortcut.data.source.KeyboardShortcutGroupsSource
 import com.android.systemui.keyboard.shortcut.qualifiers.MultitaskingShortcuts
 import com.android.systemui.keyboard.shortcut.qualifiers.SystemShortcuts
@@ -30,29 +36,46 @@
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.IME
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MULTI_TASKING
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.SYSTEM
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class ShortcutHelperCategoriesRepository
 @Inject
 constructor(
+    private val context: Context,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
     @SystemShortcuts private val systemShortcutsSource: KeyboardShortcutGroupsSource,
     @MultitaskingShortcuts private val multitaskingShortcutsSource: KeyboardShortcutGroupsSource,
     private val windowManager: WindowManager,
-    shortcutHelperStateRepository: ShortcutHelperStateRepository
+    private val inputManager: InputManager,
+    stateRepository: ShortcutHelperStateRepository
 ) {
 
-    val systemShortcutsCategory =
-        shortcutHelperStateRepository.state.map {
+    private val activeInputDevice =
+        stateRepository.state.map {
             if (it is Active) {
+                withContext(backgroundDispatcher) { inputManager.getInputDevice(it.deviceId) }
+            } else {
+                null
+            }
+        }
+
+    val systemShortcutsCategory =
+        activeInputDevice.map {
+            if (it != null) {
                 toShortcutCategory(
-                    systemShortcutsSource.shortcutGroups(),
-                    ShortcutCategoryType.SYSTEM
+                    it.keyCharacterMap,
+                    SYSTEM,
+                    systemShortcutsSource.shortcutGroups()
                 )
             } else {
                 null
@@ -60,76 +83,128 @@
         }
 
     val multitaskingShortcutsCategory =
-        shortcutHelperStateRepository.state.map {
-            if (it is Active) {
-                toShortcutCategory(multitaskingShortcutsSource.shortcutGroups(), MULTI_TASKING)
+        activeInputDevice.map {
+            if (it != null) {
+                toShortcutCategory(
+                    it.keyCharacterMap,
+                    MULTI_TASKING,
+                    multitaskingShortcutsSource.shortcutGroups()
+                )
             } else {
                 null
             }
         }
 
     val imeShortcutsCategory =
-        shortcutHelperStateRepository.state.map {
-            if (it is Active) retrieveImeShortcuts(it.deviceId) else null
-        }
+        activeInputDevice.map { if (it != null) retrieveImeShortcuts(it) else null }
 
-    private suspend fun retrieveImeShortcuts(deviceId: Int): ShortcutCategory? {
+    private suspend fun retrieveImeShortcuts(
+        inputDevice: InputDevice,
+    ): ShortcutCategory? {
         return suspendCancellableCoroutine { continuation ->
             val shortcutsReceiver = KeyboardShortcutsReceiver { shortcutGroups ->
-                continuation.resumeWith(Result.success(toShortcutCategory(shortcutGroups, IME)))
+                continuation.resumeWith(
+                    Result.success(
+                        toShortcutCategory(inputDevice.keyCharacterMap, IME, shortcutGroups)
+                    )
+                )
             }
-            windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, deviceId)
+            windowManager.requestImeKeyboardShortcuts(shortcutsReceiver, inputDevice.id)
         }
     }
 
     private fun toShortcutCategory(
-        shortcutGroups: List<KeyboardShortcutGroup>,
+        keyCharacterMap: KeyCharacterMap,
         type: ShortcutCategoryType,
+        shortcutGroups: List<KeyboardShortcutGroup>,
     ): ShortcutCategory? {
         val subCategories =
             shortcutGroups
                 .map { shortcutGroup ->
                     ShortcutSubCategory(
-                        label = shortcutGroup.label.toString(),
-                        shortcuts = toShortcuts(shortcutGroup.items)
+                        shortcutGroup.label.toString(),
+                        toShortcuts(keyCharacterMap, shortcutGroup.items)
                     )
                 }
                 .filter { it.shortcuts.isNotEmpty() }
         return if (subCategories.isEmpty()) {
+            Log.wtf(TAG, "Empty sub categories after converting $shortcutGroups")
             null
         } else {
             ShortcutCategory(type, subCategories)
         }
     }
 
-    private fun toShortcuts(infoList: List<KeyboardShortcutInfo>) =
-        infoList.mapNotNull { toShortcut(it) }
+    private fun toShortcuts(
+        keyCharacterMap: KeyCharacterMap,
+        infoList: List<KeyboardShortcutInfo>
+    ) = infoList.mapNotNull { toShortcut(keyCharacterMap, it) }
 
-    private fun toShortcut(shortcutInfo: KeyboardShortcutInfo): Shortcut? {
-        val shortcutCommand = toShortcutCommand(shortcutInfo)
+    private fun toShortcut(
+        keyCharacterMap: KeyCharacterMap,
+        shortcutInfo: KeyboardShortcutInfo
+    ): Shortcut? {
+        val shortcutCommand = toShortcutCommand(keyCharacterMap, shortcutInfo)
         return if (shortcutCommand == null) null
         else Shortcut(label = shortcutInfo.label!!.toString(), commands = listOf(shortcutCommand))
     }
 
-    private fun toShortcutCommand(info: KeyboardShortcutInfo): ShortcutCommand? {
-        val keyCodes = mutableListOf<Int>()
+    private fun toShortcutCommand(
+        keyCharacterMap: KeyCharacterMap,
+        info: KeyboardShortcutInfo
+    ): ShortcutCommand? {
+        val keys = mutableListOf<ShortcutKey>()
         var remainingModifiers = info.modifiers
         SUPPORTED_MODIFIERS.forEach { supportedModifier ->
             if ((supportedModifier and remainingModifiers) != 0) {
-                keyCodes += supportedModifier
+                keys += toShortcutKey(keyCharacterMap, supportedModifier) ?: return null
                 // "Remove" the modifier from the remaining modifiers
                 remainingModifiers = remainingModifiers and supportedModifier.inv()
             }
         }
         if (remainingModifiers != 0) {
             // There is a remaining modifier we don't support
+            Log.wtf(TAG, "Unsupported modifiers remaining: $remainingModifiers")
             return null
         }
-        keyCodes += info.keycode
-        return ShortcutCommand(keyCodes)
+        if (info.keycode != 0) {
+            keys += toShortcutKey(keyCharacterMap, info.keycode, info.baseCharacter) ?: return null
+        }
+        if (keys.isEmpty()) {
+            Log.wtf(TAG, "No keys for $info")
+            return null
+        }
+        return ShortcutCommand(keys)
+    }
+
+    private fun toShortcutKey(
+        keyCharacterMap: KeyCharacterMap,
+        keyCode: Int,
+        baseCharacter: Char = Char.MIN_VALUE,
+    ): ShortcutKey? {
+        val iconResId = ShortcutHelperKeys.keyIcons[keyCode]
+        if (iconResId != null) {
+            return ShortcutKey.Icon(iconResId)
+        }
+        if (baseCharacter > Char.MIN_VALUE) {
+            return ShortcutKey.Text(baseCharacter.toString())
+        }
+        val specialKeyLabel = ShortcutHelperKeys.specialKeyLabels[keyCode]
+        if (specialKeyLabel != null) {
+            val label = specialKeyLabel(context)
+            return ShortcutKey.Text(label)
+        }
+        val displayLabelCharacter = keyCharacterMap.getDisplayLabel(keyCode)
+        if (displayLabelCharacter.code != 0) {
+            return ShortcutKey.Text(displayLabelCharacter.toString())
+        }
+        Log.wtf(TAG, "Couldn't find label or icon for key: $keyCode")
+        return null
     }
 
     companion object {
+        private const val TAG = "SHCategoriesRepo"
+
         private val SUPPORTED_MODIFIERS =
             listOf(
                 KeyEvent.META_META_ON,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
index e5b870a..adc6d95 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/Shortcut.kt
@@ -21,8 +21,8 @@
 class ShortcutBuilder(private val label: String) {
     val commands = mutableListOf<ShortcutCommand>()
 
-    fun command(vararg keyCodes: Int) {
-        commands += ShortcutCommand(keyCodes.toList())
+    fun command(builder: ShortcutCommandBuilder.() -> Unit) {
+        commands += ShortcutCommandBuilder().apply(builder).build()
     }
 
     fun build() = Shortcut(label, commands)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
index 3ac7fa8..5d05359 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCategory.kt
@@ -30,8 +30,8 @@
 class ShortcutCategoryBuilder(val type: ShortcutCategoryType) {
     private val subCategories = mutableListOf<ShortcutSubCategory>()
 
-    fun subCategory(label: String, shortcuts: List<Shortcut>) {
-        subCategories += ShortcutSubCategory(label, shortcuts)
+    fun subCategory(label: String, builder: ShortcutSubCategoryBuilder.() -> Unit) {
+        subCategories += ShortcutSubCategoryBuilder(label).apply(builder).build()
     }
 
     fun build() = ShortcutCategory(type, subCategories)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
index a98a8ff..e5b8096 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutCommand.kt
@@ -16,4 +16,23 @@
 
 package com.android.systemui.keyboard.shortcut.shared.model
 
-data class ShortcutCommand(val keyCodes: List<Int>)
+import androidx.annotation.DrawableRes
+
+data class ShortcutCommand(val keys: List<ShortcutKey>)
+
+class ShortcutCommandBuilder {
+    private val keys = mutableListOf<ShortcutKey>()
+
+    fun key(text: String) {
+        keys += ShortcutKey.Text(text)
+    }
+
+    fun key(@DrawableRes drawableResId: Int) {
+        keys += ShortcutKey.Icon(drawableResId)
+    }
+
+    fun build() = ShortcutCommand(keys)
+}
+
+fun shortcutCommand(block: ShortcutCommandBuilder.() -> Unit) =
+    ShortcutCommandBuilder().apply(block).build()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
new file mode 100644
index 0000000..1abb78c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutKey.kt
@@ -0,0 +1,25 @@
+/*
+ * 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.keyboard.shortcut.shared.model
+
+import androidx.annotation.DrawableRes
+
+sealed interface ShortcutKey {
+    data class Text(val value: String) : ShortcutKey
+
+    data class Icon(@DrawableRes val drawableResId: Int) : ShortcutKey
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
index 4545b4c..1401678 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
@@ -17,3 +17,13 @@
 package com.android.systemui.keyboard.shortcut.shared.model
 
 data class ShortcutSubCategory(val label: String, val shortcuts: List<Shortcut>)
+
+class ShortcutSubCategoryBuilder(val label: String) {
+    private val shortcuts = mutableListOf<Shortcut>()
+
+    fun shortcut(label: String, builder: ShortcutBuilder.() -> Unit) {
+        shortcuts += ShortcutBuilder(label).apply(builder).build()
+    }
+
+    fun build() = ShortcutSubCategory(label, shortcuts)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 5f6fe1c..b32d0950 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -27,6 +27,7 @@
 import android.os.Handler
 import android.os.PowerManager
 import android.os.RemoteException
+import android.os.Trace
 import android.util.Log
 import android.view.RemoteAnimationTarget
 import android.view.SurfaceControl
@@ -385,10 +386,15 @@
                         valueAnimator.animatedValue as Float, openingWallpaperTargets)
             }
             addListener(object : AnimatorListenerAdapter() {
+                override fun onAnimationStart(animation: Animator) {
+                    super.onAnimationStart(animation)
+                    Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, "WallpaperAlphaAnimation", 0)
+                }
                 override fun onAnimationEnd(animation: Animator) {
                     Log.d(TAG, "wallpaperCannedUnlockAnimator#onAnimationEnd")
                     keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation(
                         false /* cancelled */)
+                    Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, "WallpaperAlphaAnimation", 0)
                 }
             })
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
index e9bd889..e6bab4c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
@@ -19,8 +19,9 @@
 
 import android.content.Context
 import android.os.UserHandle
+import com.android.app.tracing.FlowTracing.tracedAwaitClose
+import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-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.settings.UserTracker
@@ -28,7 +29,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
@@ -55,19 +55,20 @@
     private val userHandle: UserHandle,
 ) : KeyguardQuickAffordanceSelectionManager {
 
-    private val userId: Flow<Int> = conflatedCallbackFlow {
-        val callback =
-            object : UserTracker.Callback {
-                override fun onUserChanged(newUser: Int, userContext: Context) {
-                    trySendWithFailureLogging(newUser, TAG)
+    private val userId: Flow<Int> =
+        tracedConflatedCallbackFlow("userId") {
+            val callback =
+                object : UserTracker.Callback {
+                    override fun onUserChanged(newUser: Int, userContext: Context) {
+                        trySendWithFailureLogging(newUser, TAG)
+                    }
                 }
-            }
 
-        userTracker.addCallback(callback) { it.run() }
-        trySendWithFailureLogging(userTracker.userId, TAG)
+            userTracker.addCallback(callback) { it.run() }
+            trySendWithFailureLogging(userTracker.userId, TAG)
 
-        awaitClose { userTracker.removeCallback(callback) }
-    }
+            tracedAwaitClose("userId") { userTracker.removeCallback(callback) }
+        }
 
     private val clientOrNull: StateFlow<CustomizationProviderClient?> =
         userId
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 3877e7a..76e88a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.keyguard.shared.model.BiometricUnlockMode.Companion.isWakeAndUnlock
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.util.kotlin.Utils.Companion.sample
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
@@ -100,10 +101,14 @@
                         biometricUnlockState,
                     ) ->
                     if (isWakeAndUnlock(biometricUnlockState.mode)) {
-                        startTransitionTo(
-                            KeyguardState.GONE,
-                            ownerReason = "biometric wake and unlock",
-                        )
+                        if (SceneContainerFlag.isEnabled) {
+                            // TODO(b/336576536): Check if adaptation for scene framework is needed
+                        } else {
+                            startTransitionTo(
+                                KeyguardState.GONE,
+                                ownerReason = "biometric wake and unlock",
+                            )
+                        }
                     }
                 }
         }
@@ -131,21 +136,35 @@
                         isIdleOnCommunal,
                         canTransitionToGoneOnWake,
                         primaryBouncerShowing) ->
-                    startTransitionTo(
-                        if (!deviceEntryRepository.isLockscreenEnabled()) {
-                            KeyguardState.GONE
-                        } else if (canTransitionToGoneOnWake) {
-                            KeyguardState.GONE
-                        } else if (primaryBouncerShowing) {
-                            KeyguardState.PRIMARY_BOUNCER
-                        } else if (occluded) {
-                            KeyguardState.OCCLUDED
-                        } else if (isIdleOnCommunal) {
-                            KeyguardState.GLANCEABLE_HUB
+                    if (!deviceEntryRepository.isLockscreenEnabled()) {
+                        if (SceneContainerFlag.isEnabled) {
+                            // TODO(b/336576536): Check if adaptation for scene framework is needed
                         } else {
-                            KeyguardState.LOCKSCREEN
+                            startTransitionTo(KeyguardState.GONE)
                         }
-                    )
+                    } else if (canTransitionToGoneOnWake) {
+                        if (SceneContainerFlag.isEnabled) {
+                            // TODO(b/336576536): Check if adaptation for scene framework is needed
+                        } else {
+                            startTransitionTo(KeyguardState.GONE)
+                        }
+                    } else if (primaryBouncerShowing) {
+                        if (SceneContainerFlag.isEnabled) {
+                            // TODO(b/336576536): Check if adaptation for scene framework is needed
+                        } else {
+                            startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
+                        }
+                    } else if (occluded) {
+                        startTransitionTo(KeyguardState.OCCLUDED)
+                    } else if (isIdleOnCommunal) {
+                        if (SceneContainerFlag.isEnabled) {
+                            // TODO(b/336576536): Check if adaptation for scene framework is needed
+                        } else {
+                            startTransitionTo(KeyguardState.GLANCEABLE_HUB)
+                        }
+                    } else {
+                        startTransitionTo(KeyguardState.LOCKSCREEN)
+                    }
                 }
         }
     }
@@ -177,23 +196,55 @@
                             // Handled by dismissFromDozing().
                             !isWakeAndUnlock(biometricUnlockState.mode)
                     ) {
-                        startTransitionTo(
-                            if (!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen) {
-                                KeyguardState.GONE
-                            } else if (
-                                KeyguardWmStateRefactor.isEnabled &&
-                                    !deviceEntryRepository.isLockscreenEnabled()
-                            ) {
-                                KeyguardState.GONE
-                            } else if (primaryBouncerShowing) {
-                                KeyguardState.PRIMARY_BOUNCER
-                            } else if (isIdleOnCommunal) {
-                                KeyguardState.GLANCEABLE_HUB
+                        if (!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen) {
+                            if (SceneContainerFlag.isEnabled) {
+                                // TODO(b/336576536): Check if adaptation for scene framework is
+                                // needed
                             } else {
-                                KeyguardState.LOCKSCREEN
-                            },
-                            ownerReason = "waking from dozing"
-                        )
+                                startTransitionTo(
+                                    KeyguardState.GONE,
+                                    ownerReason = "waking from dozing"
+                                )
+                            }
+                        } else if (
+                            KeyguardWmStateRefactor.isEnabled &&
+                                !deviceEntryRepository.isLockscreenEnabled()
+                        ) {
+                            if (SceneContainerFlag.isEnabled) {
+                                // TODO(b/336576536): Check if adaptation for scene framework is
+                                // needed
+                            } else {
+                                startTransitionTo(
+                                    KeyguardState.GONE,
+                                    ownerReason = "waking from dozing"
+                                )
+                            }
+                        } else if (primaryBouncerShowing) {
+                            if (SceneContainerFlag.isEnabled) {
+                                // TODO(b/336576536): Check if adaptation for scene framework is
+                                // needed
+                            } else {
+                                startTransitionTo(
+                                    KeyguardState.PRIMARY_BOUNCER,
+                                    ownerReason = "waking from dozing"
+                                )
+                            }
+                        } else if (isIdleOnCommunal) {
+                            if (SceneContainerFlag.isEnabled) {
+                                // TODO(b/336576536): Check if adaptation for scene framework is
+                                // needed
+                            } else {
+                                startTransitionTo(
+                                    KeyguardState.GLANCEABLE_HUB,
+                                    ownerReason = "waking from dozing"
+                                )
+                            }
+                        } else {
+                            startTransitionTo(
+                                KeyguardState.LOCKSCREEN,
+                                ownerReason = "waking from dozing"
+                            )
+                        }
                     }
                 }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 9700648..0e76487 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -91,8 +91,8 @@
 
     private fun listenForDreamingToGlanceableHub() {
         if (!communalHub()) return
-        if (SceneContainerFlag.isEnabled)
-            return // TODO(b/336576536): Check if adaptation for scene framework is needed
+        // TODO(b/336576536): Check if adaptation for scene framework is needed
+        if (SceneContainerFlag.isEnabled) return
         scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) {
             glanceableHubTransitions.listenForGlanceableHubTransition(
                 transitionOwnerName = TAG,
@@ -103,6 +103,8 @@
     }
 
     private fun listenForDreamingToPrimaryBouncer() {
+        // TODO(b/336576536): Check if adaptation for scene framework is needed
+        if (SceneContainerFlag.isEnabled) return
         scope.launch {
             keyguardInteractor.primaryBouncerShowing
                 .sample(startedKeyguardTransitionStep, ::Pair)
@@ -179,8 +181,8 @@
     }
 
     private fun listenForDreamingToGoneWhenDismissable() {
-        if (SceneContainerFlag.isEnabled)
-            return // TODO(b/336576536): Check if adaptation for scene framework is needed
+        // TODO(b/336576536): Check if adaptation for scene framework is needed
+        if (SceneContainerFlag.isEnabled) return
         scope.launch {
             keyguardInteractor.isAbleToDream
                 .sampleCombine(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index ab1194e..859326a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -23,9 +23,10 @@
 import android.graphics.Point
 import android.util.MathUtils
 import com.android.app.animation.Interpolators
+import com.android.app.tracing.FlowTracing.tracedAwaitClose
+import com.android.app.tracing.FlowTracing.tracedConflatedCallbackFlow
 import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
 import com.android.systemui.dagger.SysUISingleton
@@ -58,7 +59,6 @@
 import javax.inject.Provider
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -198,22 +198,22 @@
     val isActiveDreamLockscreenHosted: StateFlow<Boolean> = repository.isActiveDreamLockscreenHosted
 
     /** Event for when the camera gesture is detected */
-    val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
-        val callback =
-            object : CommandQueue.Callbacks {
-                override fun onCameraLaunchGestureDetected(source: Int) {
-                    trySendWithFailureLogging(
-                        cameraLaunchSourceIntToModel(source),
-                        TAG,
-                        "updated onCameraLaunchGestureDetected"
-                    )
+    val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> =
+        tracedConflatedCallbackFlow("KeyguardInteractor#onCameraLaunchDetected") {
+            val callback =
+                object : CommandQueue.Callbacks {
+                    override fun onCameraLaunchGestureDetected(source: Int) {
+                        trySendWithFailureLogging(
+                            cameraLaunchSourceIntToModel(source),
+                            TAG,
+                            "updated onCameraLaunchGestureDetected")
+                    }
                 }
-            }
 
-        commandQueue.addCallback(callback)
+            commandQueue.addCallback(callback)
 
-        awaitClose { commandQueue.removeCallback(callback) }
-    }
+            tracedAwaitClose("onCameraLaunchDetected") { commandQueue.removeCallback(callback) }
+        }
 
     /**
      * Dozing and dreaming have overlapping events. If the doze state remains in FINISH, it means
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
index 41ccea7..5af38ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardOcclusionInteractor.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.util.kotlin.sample
 import dagger.Lazy
 import javax.inject.Inject
@@ -94,10 +95,15 @@
                 // currently
                 // GONE, in which case we're going back to GONE and launching the insecure camera).
                 powerInteractor.detailedWakefulness
-                    .sample(transitionInteractor.currentKeyguardState, ::Pair)
-                    .map { (wakefulness, currentKeyguardState) ->
-                        wakefulness.powerButtonLaunchGestureTriggered &&
-                            currentKeyguardState != KeyguardState.GONE
+                    .sample(
+                        transitionInteractor.isFinishedIn(
+                            Scenes.Gone,
+                            stateWithoutSceneContainer = KeyguardState.GONE
+                        ),
+                        ::Pair
+                    )
+                    .map { (wakefulness, isOnGone) ->
+                        wakefulness.powerButtonLaunchGestureTriggered && !isOnGone
                     },
                 // Emit false once that activity goes away.
                 isShowWhenLockedActivityOnTop.filter { !it }.map { false }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
index 82255a0..bcbdc9c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractor.kt
@@ -19,9 +19,10 @@
 import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.KeyguardSurfaceBehindRepository
-import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor.Companion.isSurfaceVisible
+import com.android.systemui.keyguard.shared.model.Edge
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
+import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor
 import com.android.systemui.util.kotlin.sample
 import com.android.systemui.util.kotlin.toPx
@@ -56,12 +57,18 @@
      */
     val viewParams: Flow<KeyguardSurfaceBehindModel> =
         combine(
-                transitionInteractor.startedKeyguardTransitionStep,
-                transitionInteractor.currentKeyguardState,
+                transitionInteractor.isInTransition(
+                    Edge.create(to = Scenes.Gone),
+                    edgeWithoutSceneContainer = Edge.create(to = KeyguardState.GONE)
+                ),
+                transitionInteractor.isFinishedIn(
+                    Scenes.Gone,
+                    stateWithoutSceneContainer = KeyguardState.GONE
+                ),
                 notificationLaunchInteractor.isLaunchAnimationRunning,
-            ) { startedStep, currentState, notifAnimationRunning ->
+            ) { transitioningToGone, isOnGone, notifAnimationRunning ->
                 // If we're in transition to GONE, special unlock animation params apply.
-                if (startedStep.to == KeyguardState.GONE && currentState != KeyguardState.GONE) {
+                if (transitioningToGone) {
                     if (notifAnimationRunning) {
                         // If the notification launch animation is running, leave the alpha at 0f.
                         // The ActivityLaunchAnimator will morph it from the notification at the
@@ -87,14 +94,14 @@
                             animateFromTranslationY =
                                 SURFACE_TRANSLATION_Y_DISTANCE_DP.toPx(context).toFloat(),
                             translationY = 0f,
-                            startVelocity = swipeToDismissInteractor.dismissFling.value?.velocity
-                                    ?: 0f,
+                            startVelocity =
+                                swipeToDismissInteractor.dismissFling.value?.velocity ?: 0f,
                         )
                     }
                 }
 
                 // Default to the visibility of the current state, with no animations.
-                KeyguardSurfaceBehindModel(alpha = if (isSurfaceVisible(currentState)) 1f else 0f)
+                KeyguardSurfaceBehindModel(alpha = if (isOnGone) 1f else 0f)
             }
             .distinctUntilChanged()
 
@@ -103,10 +110,14 @@
      */
     private val isNotificationLaunchAnimationRunningOnKeyguard =
         notificationLaunchInteractor.isLaunchAnimationRunning
-            .sample(transitionInteractor.finishedKeyguardState, ::Pair)
-            .map { (animationRunning, finishedState) ->
-                animationRunning && finishedState != KeyguardState.GONE
-            }
+            .sample(
+                transitionInteractor.isFinishedIn(
+                    Scenes.Gone,
+                    stateWithoutSceneContainer = KeyguardState.GONE
+                ),
+                ::Pair
+            )
+            .map { (animationRunning, isOnGone) -> animationRunning && !isOnGone }
             .onStart { emit(false) }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
index b3c9591..805dbb0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionBootInteractor.kt
@@ -22,7 +22,10 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OFF
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -57,17 +60,7 @@
 
     override fun start() {
         scope.launch {
-            val state =
-                if (showLockscreenOnBoot.first()) {
-                    KeyguardState.LOCKSCREEN
-                } else {
-                    KeyguardState.GONE
-                }
-
-            if (
-                internalTransitionInteractor.currentTransitionInfoInternal.value.from !=
-                    KeyguardState.OFF
-            ) {
+            if (internalTransitionInteractor.currentTransitionInfoInternal.value.from != OFF) {
                 Log.e(
                     "KeyguardTransitionInteractor",
                     "showLockscreenOnBoot emitted, but we've already " +
@@ -75,7 +68,23 @@
                         "transition, but this should not happen."
                 )
             } else {
-                repository.emitInitialStepsFromOff(state)
+                if (SceneContainerFlag.isEnabled) {
+                    // TODO(b/336576536): Some part of the transition implemented for flag off is
+                    //  missing here. There are two things achieved with this:
+                    //  1. Keyguard is hidden when the setup wizard is shown. This part is already
+                    //     implemented in scene container by disabling visibility instead of going
+                    //     to Gone. See [SceneContainerStartable.hydrateVisibility]. We might want
+                    //     to unify this logic here.
+                    //  2. When the auth method is set to NONE device boots into Gone (Launcher).
+                    //     For this we would just need to call changeScene(Scene.Gone).
+                    //     Unfortunately STL doesn't seem to be initialized at this point, therefore
+                    //     it needs a different solution.
+                    repository.emitInitialStepsFromOff(LOCKSCREEN)
+                } else {
+                    repository.emitInitialStepsFromOff(
+                        if (showLockscreenOnBoot.first()) LOCKSCREEN else GONE
+                    )
+                }
             }
         }
     }
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 973e898..bbc3d76 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
@@ -25,6 +25,7 @@
 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.util.kotlin.sample
 import java.util.UUID
 import kotlinx.coroutines.CoroutineDispatcher
@@ -81,6 +82,7 @@
         // a bugreport.
         ownerReason: String = "",
     ): UUID? {
+        toState.checkValidState()
         if (fromState != internalTransitionInteractor.currentTransitionInfoInternal.value.to) {
             Log.e(
                 name,
@@ -166,6 +168,8 @@
      */
     @Deprecated("Will be merged into maybeStartTransitionToOccludedOrInsecureCamera")
     suspend fun maybeHandleInsecurePowerGesture(): Boolean {
+        // TODO(b/336576536): Check if adaptation for scene framework is needed
+        if (SceneContainerFlag.isEnabled) return true
         if (keyguardOcclusionInteractor.shouldTransitionFromPowerButtonGesture()) {
             if (keyguardInteractor.isKeyguardDismissible.value) {
                 startTransitionTo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index c4383fc..680f966 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.FlowTracing.traceEmissionCount
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -229,7 +230,7 @@
                     )
                 }
                 .distinctUntilChanged()
-        }
+        }.traceEmissionCount({"QuickAfforcances#button${position.toSlotId()}"})
     }
 
     private fun KeyguardQuickAffordanceModel.toViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index de490a5..311cbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -96,12 +96,27 @@
                 logDebug { "lockScreenState:isConfigSelected=$isConfigSelected" }
                 logDebug { "lockScreenState:isDefaultNotesAppSet=$isDefaultNotesAppSet" }
 
+                val isCustomLockScreenShortcutEnabled =
+                    context.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled)
+                val isShortcutSelectedOrDefaultEnabled =
+                    if (isCustomLockScreenShortcutEnabled) {
+                        isConfigSelected
+                    } else {
+                        isStylusEverUsed
+                    }
+                logDebug {
+                    "lockScreenState:isCustomLockScreenShortcutEnabled=" +
+                        isCustomLockScreenShortcutEnabled
+                }
+                logDebug {
+                    "lockScreenState:isShortcutSelectedOrDefaultEnabled=" +
+                        isShortcutSelectedOrDefaultEnabled
+                }
                 if (
                     isEnabled &&
                         isUserUnlocked &&
                         isDefaultNotesAppSet &&
-                        isConfigSelected &&
-                        isStylusEverUsed
+                        isShortcutSelectedOrDefaultEnabled
                 ) {
                     val contentDescription = ContentDescription.Resource(pickerNameResourceId)
                     val icon = Icon.Resource(pickerIconResourceId, contentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java b/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
new file mode 100644
index 0000000..e13981d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util.kotlin;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * This is a background executor/dispatcher which guarantees that **within that instance**,
+ * operations will execute in the same order as they were dispatched.
+ * This is useful for background operations like register/unregister where ordering is important.
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface SettingsSingleThreadBackground { }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index b836016..a03221e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.util.kotlin
 
+import android.os.Handler
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
@@ -23,15 +24,16 @@
 import com.android.systemui.dagger.qualifiers.UiBackground
 import dagger.Module
 import dagger.Provides
-import java.util.concurrent.Executor
-import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.DelicateCoroutinesApi
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.android.asCoroutineDispatcher
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.newFixedThreadPoolContext
 import kotlinx.coroutines.plus
+import java.util.concurrent.Executor
+import kotlin.coroutines.CoroutineContext
 
 private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true
 
@@ -78,6 +80,14 @@
     }
 
     @Provides
+    @SysUISingleton
+    @SettingsSingleThreadBackground
+    fun settingsBgDispatcher(@Background bgHandler: Handler): CoroutineDispatcher {
+        // Handlers are guaranteed to be sequential so we use that one for now.
+        return bgHandler.asCoroutineDispatcher("SettingsBg")
+    }
+
+    @Provides
     @Background
     @SysUISingleton
     fun bgCoroutineContext(
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 4438763..816f55d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
@@ -23,7 +23,7 @@
 import android.net.Uri;
 import android.provider.Settings;
 
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
 
 import kotlinx.coroutines.CoroutineDispatcher;
 
@@ -37,7 +37,7 @@
 
     @Inject
     GlobalSettingsImpl(ContentResolver contentResolver,
-            @Background CoroutineDispatcher bgDispatcher) {
+            @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
         mContentResolver = contentResolver;
         mBgDispatcher = bgDispatcher;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
index 38ad5d0..9c98f43 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
@@ -22,13 +22,13 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.settings.UserTracker;
-
-import kotlinx.coroutines.CoroutineDispatcher;
+import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
 
 import javax.inject.Inject;
 
+import kotlinx.coroutines.CoroutineDispatcher;
+
 class SecureSettingsImpl implements SecureSettings {
     private final ContentResolver mContentResolver;
     private final UserTracker mUserTracker;
@@ -36,7 +36,7 @@
 
     @Inject
     SecureSettingsImpl(ContentResolver contentResolver, UserTracker userTracker,
-            @Background CoroutineDispatcher bgDispatcher) {
+            @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
         mContentResolver = contentResolver;
         mUserTracker = userTracker;
         mBgDispatcher = bgDispatcher;
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
index 68cc753..406d95b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
@@ -22,13 +22,13 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.settings.UserTracker;
-
-import kotlinx.coroutines.CoroutineDispatcher;
+import com.android.systemui.util.kotlin.SettingsSingleThreadBackground;
 
 import javax.inject.Inject;
 
+import kotlinx.coroutines.CoroutineDispatcher;
+
 class SystemSettingsImpl implements SystemSettings {
     private final ContentResolver mContentResolver;
     private final UserTracker mUserTracker;
@@ -36,7 +36,7 @@
 
     @Inject
     SystemSettingsImpl(ContentResolver contentResolver, UserTracker userTracker,
-            @Background CoroutineDispatcher bgDispatcher) {
+            @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) {
         mContentResolver = contentResolver;
         mUserTracker = userTracker;
         mBgCoroutineDispatcher = bgDispatcher;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
deleted file mode 100644
index b986c52..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperCategoriesRepositoryTest.kt
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.keyboard.shortcut.data.repository
-
-import android.view.KeyEvent
-import android.view.KeyboardShortcutGroup
-import android.view.KeyboardShortcutInfo
-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.keyboard.shortcut.shared.model.Shortcut
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
-import com.android.systemui.keyboard.shortcut.shared.model.shortcutCategory
-import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesRepository
-import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.testKosmos
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class ShortcutHelperCategoriesRepositoryTest : SysuiTestCase() {
-    @OptIn(ExperimentalCoroutinesApi::class)
-    private val kosmos = testKosmos().also { it.testDispatcher = UnconfinedTestDispatcher() }
-    private val repo = kosmos.shortcutHelperCategoriesRepository
-    private val helper = kosmos.shortcutHelperTestHelper
-    private val testScope = kosmos.testScope
-
-    @Test
-    fun stateActive_imeShortcuts_shortcutInfoCorrectlyConverted() =
-        testScope.runTest {
-            helper.setImeShortcuts(imeShortcutsGroupWithPreviousLanguageSwitchShortcut)
-            val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory)
-
-            helper.showFromActivity()
-
-            assertThat(imeShortcutCategory)
-                .isEqualTo(expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut)
-        }
-
-    @Test
-    fun stateActive_imeShortcuts_onlyUnsupportedShortcuts_discardsAll() =
-        testScope.runTest {
-            helper.setImeShortcuts(imeShortcutsGroupWithUnsupportedShortcutModifiers)
-            val imeShortcutCategory by collectLastValue(repo.imeShortcutsCategory)
-
-            helper.showFromActivity()
-
-            assertThat(imeShortcutCategory).isEqualTo(null)
-        }
-
-    private val switchToPreviousLanguageCommand =
-        ShortcutCommand(
-            listOf(KeyEvent.META_CTRL_ON, KeyEvent.META_SHIFT_ON, KeyEvent.KEYCODE_SPACE)
-        )
-
-    private val expectedImeShortcutCategoryWithDiscardedUnsupportedShortcuts =
-        shortcutCategory(ShortcutCategoryType.IME) { subCategory("input", emptyList()) }
-
-    private val switchToPreviousLanguageKeyboardShortcutInfo =
-        KeyboardShortcutInfo(
-            /* label = */ "switch to previous language",
-            /* keycode = */ switchToPreviousLanguageCommand.keyCodes[2],
-            /* modifiers = */ switchToPreviousLanguageCommand.keyCodes[0] or
-                switchToPreviousLanguageCommand.keyCodes[1],
-        )
-
-    private val expectedImeShortcutCategoryWithPreviousLanguageSwitchShortcut =
-        shortcutCategory(ShortcutCategoryType.IME) {
-            subCategory(
-                "input",
-                listOf(
-                    Shortcut(
-                        switchToPreviousLanguageKeyboardShortcutInfo.label!!.toString(),
-                        listOf(switchToPreviousLanguageCommand)
-                    )
-                )
-            )
-        }
-
-    private val imeShortcutsGroupWithPreviousLanguageSwitchShortcut =
-        listOf(
-            KeyboardShortcutGroup(
-                "input",
-                listOf(
-                    switchToPreviousLanguageKeyboardShortcutInfo,
-                )
-            )
-        )
-
-    private val shortcutInfoWithUnsupportedModifier =
-        KeyboardShortcutInfo(
-            /* label = */ "unsupported shortcut",
-            /* keycode = */ KeyEvent.KEYCODE_SPACE,
-            /* modifiers = */ 32
-        )
-
-    private val imeShortcutsGroupWithUnsupportedShortcutModifiers =
-        listOf(
-            KeyboardShortcutGroup(
-                "input",
-                listOf(
-                    shortcutInfoWithUnsupportedModifier,
-                )
-            )
-        )
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
index 3caa8f6..0b4e6a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/repository/ShortcutHelperStateRepositoryTest.kt
@@ -65,17 +65,6 @@
         }
 
     @Test
-    fun state_activeThroughActivity_virtualKeyboardActive_emitsActiveWithVirtualDeviceId() =
-        testScope.runTest {
-            val state by collectLastValue(repo.state)
-
-            fakeInputManager.addVirtualKeyboard()
-            helper.showFromActivity()
-
-            assertThat(state).isEqualTo(ShortcutHelperState.Active(VIRTUAL_KEYBOARD))
-        }
-
-    @Test
     fun state_activeThroughActivity_physicalKeyboardActive_emitsActiveWithDeviceId() =
         testScope.runTest {
             val deviceId = 456
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
new file mode 100644
index 0000000..c2814bd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -0,0 +1,235 @@
+/*
+ * 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.keyboard.shortcut.data.source
+
+import android.view.KeyEvent
+import android.view.KeyboardShortcutGroup
+import android.view.KeyboardShortcutInfo
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
+import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.res.R
+
+object TestShortcuts {
+
+    private val shortcutInfoWithRepeatedLabel =
+        KeyboardShortcutInfo(
+            /* label = */ "Shortcut with repeated label",
+            /* keycode = */ KeyEvent.KEYCODE_H,
+            /* modifiers = */ KeyEvent.META_META_ON,
+        )
+
+    private val shortcutInfoWithRepeatedLabelAlternate =
+        KeyboardShortcutInfo(
+            /* label = */ shortcutInfoWithRepeatedLabel.label,
+            /* keycode = */ KeyEvent.KEYCODE_L,
+            /* modifiers = */ KeyEvent.META_META_ON,
+        )
+
+    private val shortcutInfoWithRepeatedLabelSecondAlternate =
+        KeyboardShortcutInfo(
+            /* label = */ shortcutInfoWithRepeatedLabel.label,
+            /* keycode = */ KeyEvent.KEYCODE_M,
+            /* modifiers = */ KeyEvent.META_SHIFT_ON,
+        )
+
+    private val shortcutWithGroupedRepeatedLabel =
+        shortcut(shortcutInfoWithRepeatedLabel.label!!.toString()) {
+            command {
+                key(R.drawable.ic_ksh_key_meta)
+                key("H")
+            }
+            command {
+                key(R.drawable.ic_ksh_key_meta)
+                key("L")
+            }
+            command {
+                key("Shift")
+                key("M")
+            }
+        }
+
+    private val standardShortcutInfo1 =
+        KeyboardShortcutInfo(
+            /* label = */ "Standard shortcut 1",
+            /* keycode = */ KeyEvent.KEYCODE_N,
+            /* modifiers = */ KeyEvent.META_META_ON,
+        )
+
+    private val standardShortcut1 =
+        shortcut(standardShortcutInfo1.label!!.toString()) {
+            command {
+                key(R.drawable.ic_ksh_key_meta)
+                key("N")
+            }
+        }
+
+    private val standardShortcutInfo2 =
+        KeyboardShortcutInfo(
+            /* label = */ "Standard shortcut 2",
+            /* keycode = */ KeyEvent.KEYCODE_Z,
+            /* modifiers = */ KeyEvent.META_ALT_ON or KeyEvent.META_SHIFT_ON,
+        )
+
+    private val standardShortcut2 =
+        shortcut(standardShortcutInfo2.label!!.toString()) {
+            command {
+                key("Alt")
+                key("Shift")
+                key("Z")
+            }
+        }
+
+    private val standardShortcutInfo3 =
+        KeyboardShortcutInfo(
+            /* label = */ "Standard shortcut 3",
+            /* keycode = */ KeyEvent.KEYCODE_J,
+            /* modifiers = */ KeyEvent.META_CTRL_ON,
+        )
+
+    private val standardShortcut3 =
+        shortcut(standardShortcutInfo3.label!!.toString()) {
+            command {
+                key("Ctrl")
+                key("J")
+            }
+        }
+
+    private val shortcutInfoWithUnsupportedModifiers =
+        KeyboardShortcutInfo(
+            /* label = */ "Shortcut with unsupported modifiers",
+            /* keycode = */ KeyEvent.KEYCODE_A,
+            /* modifiers = */ KeyEvent.META_META_ON or KeyEvent.KEYCODE_SPACE,
+        )
+
+    private val groupWithRepeatedShortcutLabels =
+        KeyboardShortcutGroup(
+            "Group with duplicate labels",
+            listOf(
+                shortcutInfoWithRepeatedLabel,
+                shortcutInfoWithRepeatedLabelAlternate,
+                shortcutInfoWithRepeatedLabelSecondAlternate
+            )
+        )
+
+    private val subCategoryWithGroupedRepeatedShortcutLabels =
+        ShortcutSubCategory(
+            label = groupWithRepeatedShortcutLabels.label!!.toString(),
+            shortcuts = listOf(shortcutWithGroupedRepeatedLabel)
+        )
+
+    private val groupWithStandardShortcutInfo =
+        KeyboardShortcutGroup("Standard group", listOf(standardShortcutInfo1))
+
+    private val subCategoryWithStandardShortcut =
+        ShortcutSubCategory(
+            label = groupWithStandardShortcutInfo.label!!.toString(),
+            shortcuts = listOf(standardShortcut1)
+        )
+
+    private val groupWithOnlyUnsupportedModifierShortcut =
+        KeyboardShortcutGroup(
+            "Group with unsupported modifiers",
+            listOf(shortcutInfoWithUnsupportedModifiers)
+        )
+
+    private val groupWithSupportedAndUnsupportedModifierShortcut =
+        KeyboardShortcutGroup(
+            "Group with mix of supported and not supported modifiers",
+            listOf(standardShortcutInfo3, shortcutInfoWithUnsupportedModifiers)
+        )
+
+    private val subCategoryWithUnsupportedShortcutsRemoved =
+        ShortcutSubCategory(
+            groupWithSupportedAndUnsupportedModifierShortcut.label!!.toString(),
+            listOf(standardShortcut3)
+        )
+
+    private val standardGroup1 =
+        KeyboardShortcutGroup(
+            "Standard group 1",
+            listOf(standardShortcutInfo1, standardShortcutInfo2, standardShortcutInfo3)
+        )
+
+    private val standardSubCategory1 =
+        ShortcutSubCategory(
+            standardGroup1.label!!.toString(),
+            listOf(standardShortcut1, standardShortcut2, standardShortcut3)
+        )
+
+    private val standardGroup2 =
+        KeyboardShortcutGroup(
+            "Standard group 2",
+            listOf(standardShortcutInfo3, standardShortcutInfo2, standardShortcutInfo1)
+        )
+
+    private val standardSubCategory2 =
+        ShortcutSubCategory(
+            standardGroup2.label!!.toString(),
+            listOf(standardShortcut3, standardShortcut2, standardShortcut1)
+        )
+    private val standardGroup3 =
+        KeyboardShortcutGroup(
+            "Standard group 3",
+            listOf(standardShortcutInfo2, standardShortcutInfo1)
+        )
+
+    private val standardSubCategory3 =
+        ShortcutSubCategory(
+            standardGroup3.label!!.toString(),
+            listOf(standardShortcut2, standardShortcut1)
+        )
+    val imeGroups = listOf(standardGroup1, standardGroup2, standardGroup3)
+    val imeCategory =
+        ShortcutCategory(
+            type = ShortcutCategoryType.IME,
+            subCategories = listOf(standardSubCategory1, standardSubCategory2, standardSubCategory3)
+        )
+
+    val systemGroups = listOf(standardGroup3, standardGroup2, standardGroup1)
+    val systemCategory =
+        ShortcutCategory(
+            type = ShortcutCategoryType.SYSTEM,
+            subCategories = listOf(standardSubCategory3, standardSubCategory2, standardSubCategory1)
+        )
+
+    val multitaskingGroups = listOf(standardGroup2, standardGroup1)
+    val multitaskingCategory =
+        ShortcutCategory(
+            type = ShortcutCategoryType.MULTI_TASKING,
+            subCategories = listOf(standardSubCategory2, standardSubCategory1)
+        )
+
+    val groupsWithDuplicateShortcutLabels =
+        listOf(groupWithRepeatedShortcutLabels, groupWithStandardShortcutInfo)
+
+    val subCategoriesWithGroupedDuplicatedShortcutLabels =
+        listOf(subCategoryWithGroupedRepeatedShortcutLabels, subCategoryWithStandardShortcut)
+
+    val groupsWithUnsupportedModifier =
+        listOf(
+            groupWithStandardShortcutInfo,
+            groupWithOnlyUnsupportedModifierShortcut,
+            groupWithSupportedAndUnsupportedModifierShortcut
+        )
+
+    val subCategoriesWithUnsupportedModifiersRemoved =
+        listOf(subCategoryWithStandardShortcut, subCategoryWithUnsupportedShortcutsRemoved)
+
+    val groupsWithOnlyUnsupportedModifiers = listOf(groupWithOnlyUnsupportedModifierShortcut)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index c00e7e79..c6a7565 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -16,18 +16,16 @@
 
 package com.android.systemui.keyboard.shortcut.domain.interactor
 
-import android.view.KeyEvent
-import android.view.KeyboardShortcutGroup
-import android.view.KeyboardShortcutInfo
 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.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
-import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
-import com.android.systemui.keyboard.shortcut.shared.model.shortcut
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.IME
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MULTI_TASKING
+import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.SYSTEM
 import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesInteractor
 import com.android.systemui.keyboard.shortcut.shortcutHelperMultiTaskingShortcutsSource
 import com.android.systemui.keyboard.shortcut.shortcutHelperSystemShortcutsSource
@@ -56,15 +54,16 @@
             it.shortcutHelperSystemShortcutsSource = systemShortcutsSource
             it.shortcutHelperMultiTaskingShortcutsSource = multitaskingShortcutsSource
         }
+
     private val testScope = kosmos.testScope
     private val interactor = kosmos.shortcutHelperCategoriesInteractor
     private val helper = kosmos.shortcutHelperTestHelper
 
     @Before
-    fun setUp() {
-        // Setting these sources as empty temporarily. Will be populated in follow up CL.
-        systemShortcutsSource.setGroups(emptyList())
-        multitaskingShortcutsSource.setGroups(emptyList())
+    fun setShortcuts() {
+        helper.setImeShortcuts(TestShortcuts.imeGroups)
+        systemShortcutsSource.setGroups(TestShortcuts.systemGroups)
+        multitaskingShortcutsSource.setGroups(TestShortcuts.multitaskingGroups)
     }
 
     @Test
@@ -78,12 +77,17 @@
     @Test
     fun categories_stateActive_emitsAllCategoriesInOrder() =
         testScope.runTest {
-            helper.setImeShortcuts(imeShortcutGroups)
             val categories by collectLastValue(interactor.shortcutCategories)
 
             helper.showFromActivity()
 
-            assertThat(categories).containsExactly(imeShortcutCategory).inOrder()
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
         }
 
     @Test
@@ -96,159 +100,177 @@
             assertThat(categories).isEmpty()
         }
 
-    fun categories_stateActive_emitsGroupedShortcuts() =
+    @Test
+    fun categories_stateActive_imeShortcutsWithDuplicateLabels_emitsGroupedShortcuts() =
         testScope.runTest {
-            helper.setImeShortcuts(imeShortcutsGroupsWithDuplicateLabels)
+            helper.setImeShortcuts(TestShortcuts.groupsWithDuplicateShortcutLabels)
+
             val categories by collectLastValue(interactor.shortcutCategories)
 
             helper.showFromActivity()
 
-            assertThat(categories).containsExactly(expectedGroupedShortcutCategories)
-        }
-
-    private val switchToNextLanguageShortcut =
-        shortcut(label = "switch to next language") {
-            command(KeyEvent.META_CTRL_ON, KeyEvent.KEYCODE_SPACE)
-        }
-
-    private val switchToNextLanguageKeyboardShortcutInfo =
-        KeyboardShortcutInfo(
-            /* label = */ switchToNextLanguageShortcut.label,
-            /* keycode = */ switchToNextLanguageShortcut.commands[0].keyCodes[1],
-            /* modifiers = */ switchToNextLanguageShortcut.commands[0].keyCodes[0],
-        )
-
-    private val switchToNextLanguageShortcutAlternative =
-        shortcut("switch to next language") {
-            command(KeyEvent.META_CTRL_ON, KeyEvent.KEYCODE_SPACE)
-        }
-
-    private val switchToNextLanguageKeyboardShortcutInfoAlternative =
-        KeyboardShortcutInfo(
-            /* label = */ switchToNextLanguageShortcutAlternative.label,
-            /* keycode = */ switchToNextLanguageShortcutAlternative.commands[0].keyCodes[1],
-            /* modifiers = */ switchToNextLanguageShortcutAlternative.commands[0].keyCodes[0],
-        )
-
-    private val switchToPreviousLanguageShortcut =
-        shortcut("switch to previous language") {
-            command(
-                KeyEvent.META_SHIFT_ON,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        }
-
-    private val switchToPreviousLanguageKeyboardShortcutInfo =
-        KeyboardShortcutInfo(
-            /* label = */ switchToPreviousLanguageShortcut.label,
-            /* keycode = */ switchToPreviousLanguageShortcut.commands[0].keyCodes[1],
-            /* modifiers = */ switchToPreviousLanguageShortcut.commands[0].keyCodes[0],
-        )
-
-    private val switchToPreviousLanguageShortcutAlternative =
-        shortcut("switch to previous language") {
-            command(
-                KeyEvent.META_SHIFT_ON,
-                KeyEvent.KEYCODE_SPACE,
-            )
-        }
-
-    private val switchToPreviousLanguageKeyboardShortcutInfoAlternative =
-        KeyboardShortcutInfo(
-            /* label = */ switchToPreviousLanguageShortcutAlternative.label,
-            /* keycode = */ switchToPreviousLanguageShortcutAlternative.commands[0].keyCodes[1],
-            /* modifiers = */ switchToPreviousLanguageShortcutAlternative.commands[0].keyCodes[0],
-        )
-
-    private val showOnscreenKeyboardShortcut =
-        shortcut(label = "Show on-screen keyboard") {
-            command(KeyEvent.META_ALT_ON, KeyEvent.KEYCODE_K)
-        }
-
-    private val showOnScreenKeyboardShortcutInfo =
-        KeyboardShortcutInfo(
-            /* label = */ showOnscreenKeyboardShortcut.label,
-            /* keycode = */ showOnscreenKeyboardShortcut.commands[0].keyCodes[1],
-            /* modifiers = */ showOnscreenKeyboardShortcut.commands[0].keyCodes[0],
-        )
-
-    private val accessClipboardShortcut =
-        shortcut(label = "Access clipboard") { command(KeyEvent.META_ALT_ON, KeyEvent.KEYCODE_V) }
-
-    private val accessClipboardShortcutInfo =
-        KeyboardShortcutInfo(
-            /* label = */ accessClipboardShortcut.label,
-            /* keycode = */ accessClipboardShortcut.commands[0].keyCodes[1],
-            /* modifiers = */ accessClipboardShortcut.commands[0].keyCodes[0],
-        )
-
-    private val imeShortcutGroups =
-        listOf(
-            KeyboardShortcutGroup(
-                /* label = */ "input",
-                /* shortcutInfoList = */ listOf(
-                    switchToNextLanguageKeyboardShortcutInfo,
-                    switchToPreviousLanguageKeyboardShortcutInfo
-                )
-            )
-        )
-
-    private val imeShortcutCategory =
-        ShortcutCategory(
-            type = ShortcutCategoryType.IME,
-            subCategories =
-                listOf(
-                    ShortcutSubCategory(
-                        imeShortcutGroups[0].label.toString(),
-                        listOf(switchToNextLanguageShortcut, switchToPreviousLanguageShortcut)
-                    )
-                )
-        )
-
-    private val imeShortcutsGroupsWithDuplicateLabels =
-        listOf(
-            KeyboardShortcutGroup(
-                "input",
-                listOf(
-                    switchToNextLanguageKeyboardShortcutInfo,
-                    switchToNextLanguageKeyboardShortcutInfoAlternative,
-                    switchToPreviousLanguageKeyboardShortcutInfo,
-                    switchToPreviousLanguageKeyboardShortcutInfoAlternative
-                )
-            ),
-            KeyboardShortcutGroup(
-                "Gboard",
-                listOf(
-                    showOnScreenKeyboardShortcutInfo,
-                    accessClipboardShortcutInfo,
-                )
-            )
-        )
-
-    private val expectedGroupedShortcutCategories =
-        ShortcutCategory(
-            type = ShortcutCategoryType.IME,
-            subCategories =
-                listOf(
-                    ShortcutSubCategory(
-                        imeShortcutsGroupsWithDuplicateLabels[0].label.toString(),
-                        listOf(
-                            switchToNextLanguageShortcut.copy(
-                                commands =
-                                    switchToNextLanguageShortcut.commands +
-                                        switchToNextLanguageShortcutAlternative.commands
-                            ),
-                            switchToPreviousLanguageShortcut.copy(
-                                commands =
-                                    switchToPreviousLanguageShortcut.commands +
-                                        switchToPreviousLanguageShortcutAlternative.commands
-                            )
-                        ),
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    TestShortcuts.multitaskingCategory,
+                    ShortcutCategory(
+                        type = IME,
+                        subCategories =
+                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
                     ),
-                    ShortcutSubCategory(
-                        imeShortcutsGroupsWithDuplicateLabels[1].label.toString(),
-                        listOf(showOnscreenKeyboardShortcut, accessClipboardShortcut),
-                    )
                 )
-        )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_systemShortcutsWithDuplicateLabels_emitsGroupedShortcuts() =
+        testScope.runTest {
+            systemShortcutsSource.setGroups(TestShortcuts.groupsWithDuplicateShortcutLabels)
+
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    ShortcutCategory(
+                        type = SYSTEM,
+                        subCategories =
+                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+                    ),
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_multiTaskingShortcutsWithDuplicateLabels_emitsGroupedShortcuts() =
+        testScope.runTest {
+            multitaskingShortcutsSource.setGroups(TestShortcuts.groupsWithDuplicateShortcutLabels)
+
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    ShortcutCategory(
+                        type = MULTI_TASKING,
+                        subCategories =
+                            TestShortcuts.subCategoriesWithGroupedDuplicatedShortcutLabels
+                    ),
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_imeShortcutsWithUnsupportedModifiers_discardUnsupported() =
+        testScope.runTest {
+            helper.setImeShortcuts(TestShortcuts.groupsWithUnsupportedModifier)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    TestShortcuts.multitaskingCategory,
+                    ShortcutCategory(
+                        type = IME,
+                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+                    ),
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_systemShortcutsWithUnsupportedModifiers_discardUnsupported() =
+        testScope.runTest {
+            systemShortcutsSource.setGroups(TestShortcuts.groupsWithUnsupportedModifier)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    ShortcutCategory(
+                        type = SYSTEM,
+                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+                    ),
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_multitaskingShortcutsWithUnsupportedModifiers_discardUnsupported() =
+        testScope.runTest {
+            multitaskingShortcutsSource.setGroups(TestShortcuts.groupsWithUnsupportedModifier)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    ShortcutCategory(
+                        type = MULTI_TASKING,
+                        subCategories = TestShortcuts.subCategoriesWithUnsupportedModifiersRemoved
+                    ),
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_imeShortcutsWitOnlyUnsupportedModifiers_discardsCategory() =
+        testScope.runTest {
+            helper.setImeShortcuts(TestShortcuts.groupsWithOnlyUnsupportedModifiers)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    TestShortcuts.multitaskingCategory,
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_systemShortcutsWitOnlyUnsupportedModifiers_discardsCategory() =
+        testScope.runTest {
+            systemShortcutsSource.setGroups(TestShortcuts.groupsWithOnlyUnsupportedModifiers)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.multitaskingCategory,
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
+        }
+
+    @Test
+    fun categories_stateActive_multitaskingShortcutsWitOnlyUnsupportedModifiers_discardsCategory() =
+        testScope.runTest {
+            multitaskingShortcutsSource.setGroups(TestShortcuts.groupsWithOnlyUnsupportedModifiers)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            assertThat(categories)
+                .containsExactly(
+                    TestShortcuts.systemCategory,
+                    TestShortcuts.imeCategory,
+                )
+                .inOrder()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
index f32e775..c9871f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardSurfaceBehindInteractorTest.kt
@@ -21,6 +21,9 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.coroutines.collectValues
+import com.android.systemui.flags.DisableSceneContainer
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardSurfaceBehindModel
@@ -28,12 +31,18 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.util.mockTopActivityClassName
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.data.repository.Idle
+import com.android.systemui.scene.data.repository.Transition
+import com.android.systemui.scene.data.repository.setSceneTransition
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shared.system.ActivityManagerWrapper
 import com.android.systemui.shared.system.activityManagerWrapper
 import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor
 import com.android.systemui.testKosmos
 import com.android.systemui.util.assertValuesMatch
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -44,16 +53,22 @@
 @kotlinx.coroutines.ExperimentalCoroutinesApi
 class KeyguardSurfaceBehindInteractorTest : SysuiTestCase() {
     private val kosmos = testKosmos()
-    private val testScope = kosmos.testScope
-    private val underTest = kosmos.keyguardSurfaceBehindInteractor
-    private val transitionRepository = kosmos.fakeKeyguardTransitionRepository
-    private val inWindowUnlockInteractor = kosmos.inWindowLauncherUnlockAnimationInteractor
-    private val activityManagerWrapper = kosmos.activityManagerWrapper
+    private lateinit var testScope: TestScope
+    private lateinit var underTest: KeyguardSurfaceBehindInteractor
+    private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var inWindowUnlockInteractor: InWindowLauncherUnlockAnimationInteractor
+    private lateinit var activityManagerWrapper: ActivityManagerWrapper
 
     private val LAUNCHER_ACTIVITY_NAME = "launcher"
 
     @Before
     fun setUp() {
+        testScope = kosmos.testScope
+        underTest = kosmos.keyguardSurfaceBehindInteractor
+        transitionRepository = kosmos.fakeKeyguardTransitionRepository
+        inWindowUnlockInteractor = kosmos.inWindowLauncherUnlockAnimationInteractor
+        activityManagerWrapper = kosmos.activityManagerWrapper
+
         inWindowUnlockInteractor.setLauncherActivityClass(LAUNCHER_ACTIVITY_NAME)
 
         // Default to having something other than Launcher on top.
@@ -61,6 +76,7 @@
     }
 
     @Test
+    @DisableSceneContainer
     fun testSurfaceBehindModel_toAppSurface() =
         testScope.runTest {
             val values by collectValues(underTest.viewParams)
@@ -136,6 +152,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun testSurfaceBehindModel_toLauncher() =
         testScope.runTest {
             val values by collectValues(underTest.viewParams)
@@ -196,6 +213,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun testSurfaceBehindModel_fromNotificationLaunch() =
         testScope.runTest {
             val values by collectValues(underTest.viewParams)
@@ -230,6 +248,105 @@
         }
 
     @Test
+    @EnableSceneContainer
+    fun testSurfaceBehindModel_toAppSurface_scene_container() =
+        testScope.runTest {
+            val values by collectValues(underTest.viewParams)
+            runCurrent()
+
+            assertThat(values)
+                .containsExactly(
+                    // We're initialized in LOCKSCREEN.
+                    KeyguardSurfaceBehindModel(alpha = 0f),
+                )
+
+            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+            values.assertValuesMatch(
+                { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+                // Once we start a transition to GONE, we should fade in and translate up. The exact
+                // start value depends on screen density, so just look for != 0.
+                {
+                    it.animateFromAlpha == 0f &&
+                        it.alpha == 1f &&
+                        it.animateFromTranslationY != 0f &&
+                        it.translationY == 0f
+                }
+            )
+
+            kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+            values.assertValuesMatch(
+                { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+                {
+                    it.animateFromAlpha == 0f &&
+                        it.alpha == 1f &&
+                        it.animateFromTranslationY != 0f &&
+                        it.translationY == 0f
+                },
+                // Once the current state is GONE, we should default to alpha = 1f.
+                { it == KeyguardSurfaceBehindModel(alpha = 1f) }
+            )
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun testSurfaceBehindModel_toLauncher_scene_container() =
+        testScope.runTest {
+            val values by collectValues(underTest.viewParams)
+            activityManagerWrapper.mockTopActivityClassName(LAUNCHER_ACTIVITY_NAME)
+            runCurrent()
+
+            assertThat(values)
+                .containsExactly(
+                    // We're initialized in LOCKSCREEN.
+                    KeyguardSurfaceBehindModel(alpha = 0f),
+                )
+                .inOrder()
+
+            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+            assertThat(values)
+                .containsExactly(
+                    KeyguardSurfaceBehindModel(alpha = 0f),
+                    // We should instantly set alpha = 1, with no animations, when Launcher is
+                    // behind
+                    // the keyguard since we're playing in-window animations.
+                    KeyguardSurfaceBehindModel(alpha = 1f),
+                )
+                .inOrder()
+
+            kosmos.setSceneTransition(Idle(Scenes.Gone))
+
+            assertThat(values)
+                .containsExactly(
+                    KeyguardSurfaceBehindModel(alpha = 0f),
+                    // Should have remained at alpha = 1f through the entire animation.
+                    KeyguardSurfaceBehindModel(alpha = 1f),
+                )
+                .inOrder()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun testSurfaceBehindModel_fromNotificationLaunch_scene_container() =
+        testScope.runTest {
+            val values by collectValues(underTest.viewParams)
+            runCurrent()
+
+            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+            runCurrent()
+
+            kosmos.setSceneTransition(Transition(Scenes.Lockscreen, Scenes.Gone))
+
+            values.assertValuesMatch(
+                // We should be at alpha = 0f during the animation.
+                { it == KeyguardSurfaceBehindModel(alpha = 0f) },
+            )
+        }
+
+    @Test
+    @DisableSceneContainer
     fun notificationLaunchFromLockscreen_isAnimatingSurfaceTrue() =
         testScope.runTest {
             val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -253,6 +370,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun notificationLaunchFromGone_isAnimatingSurfaceFalse() =
         testScope.runTest {
             val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -276,6 +394,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun notificationLaunchFalse_isAnimatingSurfaceFalse() =
         testScope.runTest {
             val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
@@ -297,4 +416,44 @@
             runCurrent()
             assertThat(isAnimatingSurface).isFalse()
         }
+
+    @Test
+    @EnableSceneContainer
+    fun notificationLaunchFromLockscreen_isAnimatingSurfaceTrue_scene_container() =
+        testScope.runTest {
+            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+
+            kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+            runCurrent()
+
+            assertThat(isAnimatingSurface).isTrue()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun notificationLaunchFromGone_isAnimatingSurfaceFalse_scene_container() =
+        testScope.runTest {
+            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+
+            kosmos.setSceneTransition(Idle(Scenes.Gone))
+            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(true)
+            runCurrent()
+            assertThat(isAnimatingSurface).isFalse()
+
+            kosmos.setSceneTransition(Transition(from = Scenes.Gone, to = Scenes.Lockscreen))
+            assertThat(isAnimatingSurface).isFalse()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun notificationLaunchFalse_isAnimatingSurfaceFalse_scene_container() =
+        testScope.runTest {
+            val isAnimatingSurface by collectLastValue(underTest.isAnimatingSurface)
+
+            kosmos.setSceneTransition(Idle(Scenes.Lockscreen))
+            kosmos.notificationLaunchAnimationInteractor.setIsLaunchAnimationRunning(false)
+            runCurrent()
+            assertThat(isAnimatingSurface).isFalse()
+        }
 }
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 246cfbf..824132a 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
@@ -30,7 +30,6 @@
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.dock.fakeDockManager
 import com.android.systemui.flags.BrokenWithSceneContainer
 import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.flags.FakeFeatureFlags
@@ -124,7 +123,6 @@
 
     private val powerInteractor by lazy { kosmos.powerInteractor }
     private val communalInteractor by lazy { kosmos.communalInteractor }
-    private val dockManager by lazy { kosmos.fakeDockManager }
 
     companion object {
         @JvmStatic
@@ -583,6 +581,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun dozingToPrimaryBouncer() =
         testScope.runTest {
             // GIVEN a prior transition has run to DOZING
@@ -597,8 +596,8 @@
 
             assertThat(transitionRepository)
                 .startedTransition(
-                    to = KeyguardState.PRIMARY_BOUNCER,
                     from = KeyguardState.DOZING,
+                    to = KeyguardState.PRIMARY_BOUNCER,
                     animatorAssertion = { it.isNotNull() }
                 )
 
@@ -633,6 +632,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun dozingToGlanceableHub() =
         testScope.runTest {
             // GIVEN a prior transition has run to DOZING
@@ -654,8 +654,8 @@
 
             assertThat(transitionRepository)
                 .startedTransition(
-                    to = KeyguardState.GLANCEABLE_HUB,
                     from = KeyguardState.DOZING,
+                    to = KeyguardState.GLANCEABLE_HUB,
                     animatorAssertion = { it.isNotNull() }
                 )
 
@@ -1452,6 +1452,7 @@
         }
 
     @Test
+    @DisableSceneContainer
     fun dreamingToPrimaryBouncer() =
         testScope.runTest {
             // GIVEN a prior transition has run to DREAMING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index f624f20..b7fb759 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -57,7 +57,9 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.anyString
+import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoSession
 import org.mockito.quality.Strictness
 
@@ -75,6 +77,9 @@
 
     private lateinit var mockitoSession: MockitoSession
 
+    private val spiedContext = spy(context)
+    private val spiedResources = spy(spiedContext.resources)
+
     @Before
     fun setUp() {
         mockitoSession =
@@ -100,6 +105,8 @@
                 )
             )
             .thenReturn(listOf("com.google.test.notes"))
+
+        `when`(spiedContext.resources).thenReturn(spiedResources)
     }
 
     @After
@@ -109,7 +116,7 @@
 
     private fun createUnderTest(isEnabled: Boolean = true): KeyguardQuickAffordanceConfig =
         NoteTaskQuickAffordanceConfig(
-            context = context,
+            context = spiedContext,
             controller = controller,
             stylusManager = stylusManager,
             userManager = userManager,
@@ -132,126 +139,262 @@
         )
 
     // region lockScreenState
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUsed_userUnlocked_isSelected_shouldEmitVisible() = runTest {
-        val underTest = createUnderTest()
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(underTest)
-
-        val actual by collectLastValue(underTest.lockScreenState)
-
-        assertThat(actual).isEqualTo(createLockScreenStateVisible())
-    }
-
-    @Test
-    fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
+    fun lockScreenState_stylusUnused_userLocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
         runTest {
             val underTest = createUnderTest()
             TestConfig()
-                .setStylusEverUsed(true)
-                .setUserUnlocked(true)
-                .setConfigSelections(underTest)
-            whenever(
-                    roleManager.getRoleHoldersAsUser(
-                        eq(RoleManager.ROLE_NOTES),
-                        any(UserHandle::class.java)
-                    )
-                )
-                .thenReturn(emptyList())
+                .setStylusEverUsed(false)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections()
 
             val actual by collectLastValue(underTest.lockScreenState)
 
             assertThat(actual).isEqualTo(LockScreenState.Hidden)
         }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
-        val underTest = createUnderTest()
-        TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(underTest)
+    fun lockScreenState_stylusUnused_userLocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections(underTest)
 
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUsed_userLocked_isSelected_shouldEmitHidden() = runTest {
-        val underTest = createUnderTest()
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(underTest)
+    fun lockScreenState_stylusUnused_userLocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections()
 
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
+    fun lockScreenState_stylusUnused_userLocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections(underTest)
 
-        val underTest = createUnderTest()
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUnused_userUnlocked_noSelected_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections()
+    fun lockScreenState_stylusUnused_userUnlocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections()
 
-        val underTest = createUnderTest()
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUsed_userLocked_noSelected_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections()
+    fun lockScreenState_stylusUnused_userUnlocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections(underTest)
 
-        val underTest = createUnderTest()
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(mock())
+    fun lockScreenState_stylusUnused_userUnlocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections()
 
-        val underTest = createUnderTest()
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUnused_userUnlocked_customSelections_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(mock())
+    fun lockScreenState_stylusUnused_userUnlocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitVisible() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(false)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections(underTest)
 
-        val underTest = createUnderTest()
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(createLockScreenStateVisible())
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_stylusUsed_userLocked_customSelections_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(mock())
+    fun lockScreenState_stylusUsed_userLocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections()
 
-        val underTest = createUnderTest()
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
 
+    @Suppress("ktlint:standard:max-line-length")
     @Test
-    fun lockScreenState_isNotEnabled_shouldEmitHidden() = runTest {
-        TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
+    fun lockScreenState_stylusUsed_userLocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections(underTest)
 
-        val underTest = createUnderTest(isEnabled = false)
-        val actual by collectLastValue(underTest.lockScreenState)
+            val actual by collectLastValue(underTest.lockScreenState)
 
-        assertThat(actual).isEqualTo(LockScreenState.Hidden)
-    }
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
+
+    @Suppress("ktlint:standard:max-line-length")
+    @Test
+    fun lockScreenState_stylusUsed_userLocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections()
+
+            val actual by collectLastValue(underTest.lockScreenState)
+
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
+
+    @Suppress("ktlint:standard:max-line-length")
+    @Test
+    fun lockScreenState_stylusUsed_userLocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(false)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections(underTest)
+
+            val actual by collectLastValue(underTest.lockScreenState)
+
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
+
+    @Suppress("ktlint:standard:max-line-length")
+    @Test
+    fun lockScreenState_stylusUsed_userUnlocked_customizationDisabled_notesLockScreenShortcutNotSelected_shouldEmitVisible() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections()
+
+            val actual by collectLastValue(underTest.lockScreenState)
+
+            assertThat(actual).isEqualTo(createLockScreenStateVisible())
+        }
+
+    @Suppress("ktlint:standard:max-line-length")
+    @Test
+    fun lockScreenState_stylusUsed_userUnlocked_customizationDisabled_notesLockScreenShortcutSelected_shouldEmitVisible() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(false)
+                .setConfigSelections(underTest)
+
+            val actual by collectLastValue(underTest.lockScreenState)
+
+            assertThat(actual).isEqualTo(createLockScreenStateVisible())
+        }
+
+    @Suppress("ktlint:standard:max-line-length")
+    @Test
+    fun lockScreenState_stylusUsed_userUnlocked_customizationEnabled_notesLockScreenShortcutNotSelected_shouldEmitHidden() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections()
+
+            val actual by collectLastValue(underTest.lockScreenState)
+
+            assertThat(actual).isEqualTo(LockScreenState.Hidden)
+        }
+
+    @Suppress("ktlint:standard:max-line-length")
+    @Test
+    fun lockScreenState_stylusUsed_userUnlocked_customizationEnabled_notesLockScreenShortcutSelected_shouldEmitVisible() =
+        runTest {
+            val underTest = createUnderTest()
+            TestConfig()
+                .setStylusEverUsed(true)
+                .setUserUnlocked(true)
+                .setLockScreenCustomizationEnabled(true)
+                .setConfigSelections(underTest)
+
+            val actual by collectLastValue(underTest.lockScreenState)
+
+            assertThat(actual).isEqualTo(createLockScreenStateVisible())
+        }
+
     // endregion
 
     @Test
@@ -294,18 +437,24 @@
             .isEqualTo(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE)
         assertThat(disabled.actionIntent?.`package`).isEqualTo(context.packageName)
     }
+
     // endregion
 
     private inner class TestConfig {
 
         fun setStylusEverUsed(value: Boolean) = also {
-            whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(value)
+            whenever(InputSettings.isStylusEverUsed(spiedContext)).thenReturn(value)
         }
 
         fun setUserUnlocked(value: Boolean) = also {
             whenever(userManager.isUserUnlocked).thenReturn(value)
         }
 
+        fun setLockScreenCustomizationEnabled(value: Boolean) = also {
+            `when`(spiedResources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled))
+                .thenReturn(value)
+        }
+
         fun setConfigSelections(vararg values: KeyguardQuickAffordanceConfig) = also {
             val slotKey = "bottom-right"
             val configSnapshots = values.toList()
diff --git a/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt b/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
index 36ac4a4..c4f93d1 100644
--- a/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
+++ b/packages/SystemUI/tests/utils/src/android/hardware/input/FakeInputManager.kt
@@ -18,6 +18,7 @@
 
 import android.view.InputDevice
 import android.view.KeyCharacterMap
+import android.view.KeyCharacterMap.VIRTUAL_KEYBOARD
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import org.mockito.ArgumentMatchers.anyInt
@@ -25,7 +26,18 @@
 
 class FakeInputManager {
 
-    private val devices = mutableMapOf<Int, InputDevice>()
+    private val keyCharacterMap = KeyCharacterMap.load(VIRTUAL_KEYBOARD)
+
+    private val virtualKeyboard =
+        InputDevice.Builder()
+            .setId(VIRTUAL_KEYBOARD)
+            .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
+            .setSources(InputDevice.SOURCE_KEYBOARD)
+            .setEnabled(true)
+            .setKeyCharacterMap(keyCharacterMap)
+            .build()
+
+    private val devices = mutableMapOf<Int, InputDevice>(VIRTUAL_KEYBOARD to virtualKeyboard)
 
     val inputManager =
         mock<InputManager> {
@@ -56,10 +68,6 @@
         addKeyboard(id, enabled)
     }
 
-    fun addVirtualKeyboard(enabled: Boolean = true) {
-        addKeyboard(id = KeyCharacterMap.VIRTUAL_KEYBOARD, enabled)
-    }
-
     private fun addKeyboard(id: Int, enabled: Boolean = true) {
         devices[id] =
             InputDevice.Builder()
@@ -67,6 +75,7 @@
                 .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
                 .setSources(InputDevice.SOURCE_KEYBOARD)
                 .setEnabled(enabled)
+                .setKeyCharacterMap(keyCharacterMap)
                 .build()
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index 385a6dc..dab70f8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -59,10 +59,13 @@
 val Kosmos.shortcutHelperCategoriesRepository by
     Kosmos.Fixture {
         ShortcutHelperCategoriesRepository(
+            applicationContext,
+            testDispatcher,
             shortcutHelperSystemShortcutsSource,
             shortcutHelperMultiTaskingShortcutsSource,
             windowManager,
-            shortcutHelperStateRepository
+            fakeInputManager.inputManager,
+            shortcutHelperStateRepository,
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
index fcea9e7b..135cb14 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
@@ -22,7 +22,6 @@
 import com.android.settingslib.volume.shared.model.AudioStream
 import com.android.settingslib.volume.shared.model.AudioStreamModel
 import com.android.settingslib.volume.shared.model.RingerMode
-import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
@@ -61,7 +60,7 @@
             )
         }
 
-    override fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> =
+    override fun getAudioStream(audioStream: AudioStream): StateFlow<AudioStreamModel> =
         getAudioStreamModelState(audioStream).asStateFlow()
 
     override suspend fun setVolume(audioStream: AudioStream, volume: Int) {
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index a4026eb..c2cb5e9 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -803,22 +803,28 @@
         @Override
         public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
                 @FailureReasons int failureReason, int mitigationCount) {
+            int impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
             if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
                     || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
                 if (Flags.recoverabilityDetection()) {
                     if (!Flags.deprecateFlagsAndSettingsResets()) {
-                        return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                        impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
                                 mayPerformReboot(failedPackage), failedPackage));
                     } else {
-                        return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+                        impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
                     }
                 } else {
-                    return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+                    impact =  mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
                             mayPerformReboot(failedPackage)));
                 }
-            } else {
-                return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
             }
+
+            Slog.i(TAG, "Checking available remediations for health check failure."
+                    + " failedPackage: "
+                    + (failedPackage == null ? null : failedPackage.getPackageName())
+                    + " failureReason: " + failureReason
+                    + " available impact: " + impact);
+            return impact;
         }
 
         @Override
@@ -827,6 +833,11 @@
             if (isDisabled()) {
                 return false;
             }
+            Slog.i(TAG, "Executing remediation."
+                    + " failedPackage: "
+                    + (failedPackage == null ? null : failedPackage.getPackageName())
+                    + " failureReason: " + failureReason
+                    + " mitigationCount: " + mitigationCount);
             if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
                     || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
                 final int level;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 7cd9144..6694ebb 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1485,6 +1485,7 @@
                     || !mAutomaticBrightnessStrategy.shouldUseAutoBrightness())) {
                 rawBrightnessState = getDozeBrightnessForOffload();
                 brightnessState = clampScreenBrightness(rawBrightnessState);
+                updateScreenBrightnessSetting = false;
                 mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_MANUAL);
                 mTempBrightnessEvent.setFlags(
                         mTempBrightnessEvent.getFlags() | BrightnessEvent.FLAG_DOZE_SCALE);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
index 7c1a5e1..93ef6f0 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java
@@ -56,6 +56,7 @@
     private final PackageManager mPackageManager;
 
     private final ArrayList<MediaRoute2ProviderServiceProxy> mProxies = new ArrayList<>();
+    private final Runnable mScanPackagesRunnable = this::scanPackages;
     private boolean mRunning;
 
     MediaRoute2ProviderWatcher(Context context,
@@ -106,7 +107,7 @@
             mRunning = false;
 
             mContext.unregisterReceiver(mScanPackagesReceiver);
-            mHandler.removeCallbacks(this::scanPackages);
+            mHandler.removeCallbacks(mScanPackagesRunnable);
 
             // Stop all providers.
             for (int i = mProxies.size() - 1; i >= 0; i--) {
@@ -189,8 +190,8 @@
     }
 
     private void postScanPackagesIfNeeded() {
-        if (!mHandler.hasCallbacks(this::scanPackages)) {
-            mHandler.post(this::scanPackages);
+        if (!mHandler.hasCallbacks(mScanPackagesRunnable)) {
+            mHandler.post(mScanPackagesRunnable);
         }
     }
 
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index c85ceac..4f28e02 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -154,12 +154,22 @@
             }
         }
 
+        Slog.i(TAG, "Checking available remediations for health check failure."
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " failureReason: " + failureReason
+                + " available impact: " + impact);
         return impact;
     }
 
     @Override
     public boolean execute(@Nullable VersionedPackage failedPackage,
             @FailureReasons int rollbackReason, int mitigationCount) {
+        Slog.i(TAG, "Executing remediation."
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " rollbackReason: " + rollbackReason
+                + " mitigationCount: " + mitigationCount);
         if (Flags.recoverabilityDetection()) {
             List<RollbackInfo> availableRollbacks = getAvailableRollbacks();
             if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
@@ -503,6 +513,10 @@
             @FailureReasons int rollbackReason) {
         assertInWorkerThread();
 
+        Slog.i(TAG, "Rolling back package. RollbackId: " + rollback.getRollbackId()
+                + " failedPackage: "
+                + (failedPackage == null ? null : failedPackage.getPackageName())
+                + " rollbackReason: " + rollbackReason);
         final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
         int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
         final String failedPackageToLog;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 484481b..8be3380 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -734,6 +734,9 @@
      */
     private boolean mOccludesParent;
 
+    /** Whether the activity have style floating */
+    private boolean mStyleFloating;
+
     /**
      * Unlike {@link #mOccludesParent} which can be changed at runtime. This is a static attribute
      * from the style of activity. Because we don't want {@link WindowContainer#getOrientation()}
@@ -2188,7 +2191,11 @@
                 realTheme, com.android.internal.R.styleable.Window, mUserId);
 
         if (ent != null) {
-            mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array)
+            final boolean styleTranslucent = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+            mStyleFloating = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsFloating, false);
+            mOccludesParent = !(styleTranslucent || mStyleFloating)
                     // This style is propagated to the main window attributes with
                     // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout.
                     || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
@@ -2197,6 +2204,7 @@
             mOptOutEdgeToEdge = ent.array.getBoolean(
                     R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false);
         } else {
+            mStyleFloating = false;
             mStyleFillsParent = mOccludesParent = true;
             noDisplay = false;
             mOptOutEdgeToEdge = false;
@@ -3237,6 +3245,10 @@
         return occludesParent(true /* includingFinishing */);
     }
 
+    boolean isStyleFloating() {
+        return mStyleFloating;
+    }
+
     /** Returns true if this activity is not finishing, is opaque and fills the entire space of
      * this task. */
     boolean occludesParent() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7206b36..33a649b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3411,6 +3411,7 @@
         info.isVisibleRequested = isVisibleRequested();
         info.isSleeping = shouldSleepActivities();
         info.isTopActivityTransparent = top != null && !top.fillsParent();
+        info.isTopActivityStyleFloating = top != null && top.isStyleFloating();
         appCompatTaskInfo.topActivityLetterboxVerticalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
         appCompatTaskInfo.topActivityLetterboxHorizontalPosition = TaskInfo.PROPERTY_VALUE_UNSET;
         appCompatTaskInfo.topActivityLetterboxWidth = TaskInfo.PROPERTY_VALUE_UNSET;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fec1175..de73e6c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -28,6 +28,7 @@
 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
 import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.util.SequenceUtils.getNextSeq;
 import static android.view.SurfaceControl.Transaction;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -96,7 +97,6 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
-import static android.util.SequenceUtils.getNextSeq;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
@@ -249,8 +249,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.KeyInterceptionInfo;
-import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.policy.WindowManagerPolicy;
@@ -1976,8 +1976,8 @@
      */
     boolean isReadyForDisplay() {
         final boolean parentAndClientVisible = !isParentWindowHidden()
-                && mViewVisibility == View.VISIBLE && mToken.isVisible();
-        return mHasSurface && isVisibleByPolicy() && !mDestroying
+                && mViewVisibility == View.VISIBLE;
+        return mHasSurface && isVisibleByPolicy() && !mDestroying && mToken.isVisible()
                 && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS));
     }
 
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 7a710dc..7649a4e 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -193,7 +193,7 @@
         "android.hardware.thermal-V2-ndk",
         "android.hardware.tv.input@1.0",
         "android.hardware.tv.input-V2-ndk",
-        "android.hardware.vibrator-V2-cpp",
+        "android.hardware.vibrator-V2-ndk",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 4be21d8..2804a10 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -16,24 +16,21 @@
 
 #define LOG_TAG "VibratorController"
 
+#include <aidl/android/hardware/vibrator/IVibrator.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-
 #include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <vibratorservice/VibratorHalController.h>
+
 #include "android_runtime/AndroidRuntime.h"
+#include "com_android_server_vibrator_VibratorManagerService.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
 
-#include <utils/Log.h>
-#include <utils/misc.h>
-
-#include <vibratorservice/VibratorHalController.h>
-
-#include "com_android_server_vibrator_VibratorManagerService.h"
-
 namespace V1_0 = android::hardware::vibrator::V1_0;
 namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace aidl = android::hardware::vibrator;
+namespace Aidl = aidl::android::hardware::vibrator;
 
 namespace android {
 
@@ -67,29 +64,29 @@
 } sRampClassInfo;
 
 static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
-              static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
+              static_cast<uint8_t>(Aidl::EffectStrength::LIGHT));
 static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
-              static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
+              static_cast<uint8_t>(Aidl::EffectStrength::MEDIUM));
 static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
-              static_cast<uint8_t>(aidl::EffectStrength::STRONG));
+              static_cast<uint8_t>(Aidl::EffectStrength::STRONG));
 
 static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
-              static_cast<uint8_t>(aidl::Effect::CLICK));
+              static_cast<uint8_t>(Aidl::Effect::CLICK));
 static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
-              static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD));
-static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP));
+              static_cast<uint8_t>(Aidl::Effect::DOUBLE_CLICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(Aidl::Effect::TICK));
+static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(Aidl::Effect::THUD));
+static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(Aidl::Effect::POP));
 static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
-              static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
+              static_cast<uint8_t>(Aidl::Effect::HEAVY_CLICK));
 static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
-              static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
+              static_cast<uint8_t>(Aidl::Effect::RINGTONE_1));
 static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
-              static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
+              static_cast<uint8_t>(Aidl::Effect::RINGTONE_2));
 static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
-              static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
+              static_cast<uint8_t>(Aidl::Effect::RINGTONE_15));
 static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
-              static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
+              static_cast<uint8_t>(Aidl::Effect::TEXTURE_TICK));
 
 static std::shared_ptr<vibrator::HalController> findVibrator(int32_t vibratorId) {
     vibrator::ManagerHalController* manager =
@@ -155,15 +152,15 @@
     std::atomic<int64_t> mCallbackId;
 };
 
-static aidl::BrakingPwle brakingPwle(aidl::Braking braking, int32_t duration) {
-    aidl::BrakingPwle pwle;
+static Aidl::BrakingPwle brakingPwle(Aidl::Braking braking, int32_t duration) {
+    Aidl::BrakingPwle pwle;
     pwle.braking = braking;
     pwle.duration = duration;
     return pwle;
 }
 
-static aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
-    aidl::ActivePwle pwle;
+static Aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
+    Aidl::ActivePwle pwle;
     pwle.startAmplitude =
             static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.startAmplitude));
     pwle.endAmplitude = static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.endAmplitude));
@@ -175,20 +172,20 @@
 }
 
 /* Return true if braking is not NONE and the active PWLE starts and ends with zero amplitude. */
-static bool shouldBeReplacedWithBraking(aidl::ActivePwle activePwle, aidl::Braking braking) {
-    return (braking != aidl::Braking::NONE) && (activePwle.startAmplitude == 0) &&
+static bool shouldBeReplacedWithBraking(Aidl::ActivePwle activePwle, Aidl::Braking braking) {
+    return (braking != Aidl::Braking::NONE) && (activePwle.startAmplitude == 0) &&
             (activePwle.endAmplitude == 0);
 }
 
 /* Return true if braking is not NONE and the active PWLE only ends with zero amplitude. */
-static bool shouldAddLastBraking(aidl::ActivePwle lastActivePwle, aidl::Braking braking) {
-    return (braking != aidl::Braking::NONE) && (lastActivePwle.startAmplitude > 0) &&
+static bool shouldAddLastBraking(Aidl::ActivePwle lastActivePwle, Aidl::Braking braking) {
+    return (braking != Aidl::Braking::NONE) && (lastActivePwle.startAmplitude > 0) &&
             (lastActivePwle.endAmplitude == 0);
 }
 
-static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
-    aidl::CompositeEffect effect;
-    effect.primitive = static_cast<aidl::CompositePrimitive>(
+static Aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
+    Aidl::CompositeEffect effect;
+    effect.primitive = static_cast<Aidl::CompositePrimitive>(
             env->GetIntField(primitive, sPrimitiveClassInfo.id));
     effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
     effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
@@ -282,8 +279,8 @@
         ALOGE("vibratorPerformEffect failed because native wrapper was not initialized");
         return -1;
     }
-    aidl::Effect effectType = static_cast<aidl::Effect>(effect);
-    aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
+    Aidl::Effect effectType = static_cast<Aidl::Effect>(effect);
+    Aidl::EffectStrength effectStrength = static_cast<Aidl::EffectStrength>(strength);
     auto callback = wrapper->createCallback(vibrationId);
     auto performEffectFn = [effectType, effectStrength, &callback](vibrator::HalWrapper* hal) {
         return hal->performEffect(effectType, effectStrength, callback);
@@ -300,7 +297,7 @@
         return -1;
     }
     size_t size = env->GetArrayLength(composition);
-    std::vector<aidl::CompositeEffect> effects;
+    std::vector<Aidl::CompositeEffect> effects;
     for (size_t i = 0; i < size; i++) {
         jobject element = env->GetObjectArrayElement(composition, i);
         effects.push_back(effectFromJavaPrimitive(env, element));
@@ -321,13 +318,13 @@
         ALOGE("vibratorPerformPwleEffect failed because native wrapper was not initialized");
         return -1;
     }
-    aidl::Braking braking = static_cast<aidl::Braking>(brakingId);
+    Aidl::Braking braking = static_cast<Aidl::Braking>(brakingId);
     size_t size = env->GetArrayLength(waveform);
-    std::vector<aidl::PrimitivePwle> primitives;
+    std::vector<Aidl::PrimitivePwle> primitives;
     std::chrono::milliseconds totalDuration(0);
     for (size_t i = 0; i < size; i++) {
         jobject element = env->GetObjectArrayElement(waveform, i);
-        aidl::ActivePwle activePwle = activePwleFromJavaPrimitive(env, element);
+        Aidl::ActivePwle activePwle = activePwleFromJavaPrimitive(env, element);
         if ((i > 0) && shouldBeReplacedWithBraking(activePwle, braking)) {
             primitives.push_back(brakingPwle(braking, activePwle.duration));
         } else {
@@ -356,8 +353,8 @@
         return;
     }
     auto alwaysOnEnableFn = [id, effect, strength](vibrator::HalWrapper* hal) {
-        return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
-                                   static_cast<aidl::EffectStrength>(strength));
+        return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<Aidl::Effect>(effect),
+                                   static_cast<Aidl::EffectStrength>(strength));
     };
     wrapper->halCall<void>(alwaysOnEnableFn, "alwaysOnEnable");
 }
@@ -389,7 +386,7 @@
                               static_cast<jlong>(info.capabilities.value()));
     }
     if (info.supportedEffects.isOk()) {
-        std::vector<aidl::Effect> effects = info.supportedEffects.value();
+        std::vector<Aidl::Effect> effects = info.supportedEffects.value();
         jintArray supportedEffects = env->NewIntArray(effects.size());
         env->SetIntArrayRegion(supportedEffects, 0, effects.size(),
                                reinterpret_cast<jint*>(effects.data()));
@@ -397,7 +394,7 @@
                               sVibratorInfoBuilderClassInfo.setSupportedEffects, supportedEffects);
     }
     if (info.supportedBraking.isOk()) {
-        std::vector<aidl::Braking> braking = info.supportedBraking.value();
+        std::vector<Aidl::Braking> braking = info.supportedBraking.value();
         jintArray supportedBraking = env->NewIntArray(braking.size());
         env->SetIntArrayRegion(supportedBraking, 0, braking.size(),
                                reinterpret_cast<jint*>(braking.data()));
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 977a8a0..64dbc50 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -398,14 +398,17 @@
                 if (randomNum >= traceFrequency) {
                     return;
                 }
-                // Wait for 1s before starting tracing.
+                // For a small percentage a traces, we collect the initialization behavior.
+                boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1;
+                int traceDelay = traceInitialization ? 0 : 1000;
+                String traceTag = traceInitialization ? "camera_init" : "camera";
                 BackgroundThread.get().getThreadHandler().postDelayed(() -> {
                     try {
-                        mIProfcollect.trace_once("camera");
+                        mIProfcollect.trace_once(traceTag);
                     } catch (RemoteException e) {
                         Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
                     }
-                }, 1000);
+                }, traceDelay);
             }
         }, null);
     }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index d070aaa..2018e1a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1942,7 +1942,7 @@
     }
 
     @Test
-    public void testDozeManualBrightness() {
+    public void testDozeManualBrightness_DpcRefactorDisabled() {
         when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
         mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
         Settings.System.putInt(mContext.getContentResolver(),
@@ -1972,6 +1972,45 @@
                 /* ignoreAnimationLimits= */ anyBoolean());
         assertEquals(brightness * DOZE_SCALE_FACTOR, mHolder.dpc.getDozeBrightnessForOffload(),
                 /* delta= */ 0);
+        // This brightness shouldn't be stored in the setting
+        verify(mHolder.brightnessSetting, never()).setBrightness(brightness * DOZE_SCALE_FACTOR);
+    }
+
+    @Test
+    public void testDozeManualBrightness_DpcRefactorEnabled() {
+        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+        when(mDisplayManagerFlagsMock.isRefactorDisplayPowerControllerEnabled()).thenReturn(true);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+        float brightness = 0.277f;
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
+        when(mHolder.hbmController.getCurrentBrightnessMax())
+                .thenReturn(PowerManager.BRIGHTNESS_MAX);
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState, initialize
+
+        ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor =
+                ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class);
+        verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture());
+        BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue();
+        listener.onBrightnessChanged(brightness);
+        advanceTime(1); // Send messages, run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness * DOZE_SCALE_FACTOR),
+                /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
+                /* ignoreAnimationLimits= */ anyBoolean());
+        assertEquals(brightness * DOZE_SCALE_FACTOR, mHolder.dpc.getDozeBrightnessForOffload(),
+                /* delta= */ 0);
+        // This brightness shouldn't be stored in the setting
+        verify(mHolder.brightnessSetting, never()).setBrightness(brightness * DOZE_SCALE_FACTOR);
     }
 
     @Test
diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
index 489ef44..3722fef 100644
--- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java
@@ -47,6 +47,8 @@
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.os.test.TestLooper;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.DeviceConfig;
 import android.util.AtomicFile;
@@ -288,7 +290,8 @@
     }
 
     @Test
-    public void testBootLoopWithRescuePartyAndRollbackPackageHealthObserver() throws Exception {
+    @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopWithRescuePartyAndRollbackObserver() throws Exception {
         PackageWatchdog watchdog = createWatchdog();
         RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
         RollbackPackageHealthObserver rollbackObserver =
@@ -360,6 +363,56 @@
         verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS)
+    public void testBootLoopWithRescuePartyAndRollbackObserverNoFlags() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog);
+        RollbackPackageHealthObserver rollbackObserver =
+                setUpRollbackPackageHealthObserver(watchdog);
+
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(1);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+        for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+            watchdog.noteBoot();
+        }
+        verify(rescuePartyObserver).executeBootLoopMitigation(1);
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(1);
+
+        watchdog.noteBoot();
+
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+        verify(rollbackObserver).executeBootLoopMitigation(1);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(2);
+        // Update the list of available rollbacks after executing bootloop mitigation once
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH,
+                ROLLBACK_INFO_MANUAL));
+
+        watchdog.noteBoot();
+
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+        verify(rollbackObserver).executeBootLoopMitigation(2);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+        // Update the list of available rollbacks after executing bootloop mitigation
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL));
+
+        watchdog.noteBoot();
+
+        verify(rescuePartyObserver).executeBootLoopMitigation(2);
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(3);
+        verify(rollbackObserver, never()).executeBootLoopMitigation(3);
+
+        moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1);
+        Mockito.reset(rescuePartyObserver);
+
+        for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) {
+            watchdog.noteBoot();
+        }
+        verify(rescuePartyObserver).executeBootLoopMitigation(1);
+        verify(rescuePartyObserver, never()).executeBootLoopMitigation(2);
+    }
+
     RollbackPackageHealthObserver setUpRollbackPackageHealthObserver(PackageWatchdog watchdog) {
         RollbackPackageHealthObserver rollbackObserver =
                 spy(new RollbackPackageHealthObserver(mSpyContext, mApexManager));